Files
lucianoandClaude Fable 5.1 ff79832c30 AvatarPy: assistente personale con volto 3D, voce, memoria e plugin
Riscrittura in Python dell'assistente Avatar con interfaccia HUD (derivata da Mark LIV, CC BY-NC 4.0, vedi NOTICE.md).
Tre motori (Claude API, server locale OpenAI-compatibile, Claude Code), voce Kokoro/macOS, Whisper MLX,
avatar 3D con sincronizzazione labiale, memoria per categorie, allegati con OCR, monitor con avvisi,
plugin per Calendario, Mail, Promemoria, Note, Musica, app, Mac, timer, meteo, contatti, Messaggi,
file, Comandi Rapidi, browser, Telegram, WhatsApp (archivio e tempo reale).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 16:21:39 +02:00

79 lines
3.8 KiB
Python

"""Browser e web: legge una pagina, la pagina aperta in Safari, cerca su YouTube o Google."""
from __future__ import annotations
import html
import re
import subprocess
import sys
from pathlib import Path
from urllib.parse import quote_plus
import requests
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from avatar.macos import osa # noqa: E402
MAX_CHARS = 6000
UA = {"User-Agent": "Mozilla/5.0 (Macintosh) AvatarPy/1.0"}
def _html_to_text(page: str) -> str:
page = re.sub(r"<(script|style|noscript|svg|header|footer|nav)[^>]*>.*?</\1>", " ", page, flags=re.S | re.I)
page = re.sub(r"<br\s*/?>|</p>|</div>|</h\d>|</li>|</tr>", "\n", page, flags=re.I)
text = html.unescape(re.sub(r"<[^>]+>", " ", page))
lines = [" ".join(l.split()) for l in text.splitlines()]
return "\n".join(l for l in lines if len(l) > 2)
def leggi_pagina(params: dict, ctx: dict) -> str:
url = str(params.get("url", "")).strip()
if not url:
try:
url = osa('tell application "Safari" to return URL of front document')
except Exception:
return "Nessun indirizzo dato e Safari non ha pagine aperte."
if not url.startswith("http"):
url = "https://" + url
r = requests.get(url, headers=UA, timeout=15)
r.raise_for_status()
title = re.search(r"<title[^>]*>(.*?)</title>", r.text, flags=re.S | re.I)
text = _html_to_text(r.text)
return f"{html.unescape(title.group(1).strip()) if title else url}\n{text[:MAX_CHARS]}{' […]' if len(text) > MAX_CHARS else ''}"
def cerca(params: dict, ctx: dict) -> str:
q = str(params.get("query", "")).strip()
dove = str(params.get("dove", "google")).lower()
if not q:
return "Errore: serve la query."
url = {"youtube": f"https://www.youtube.com/results?search_query={quote_plus(q)}",
"maps": f"https://www.google.com/maps/search/{quote_plus(q)}",
"amazon": f"https://www.amazon.it/s?k={quote_plus(q)}",
"wikipedia": f"https://it.wikipedia.org/w/index.php?search={quote_plus(q)}"}.get(dove, f"https://www.google.com/search?q={quote_plus(q)}")
subprocess.run(["open", url], check=False, timeout=10)
return f"Apro la ricerca di «{q}» su {dove}."
def youtube(params: dict, ctx: dict) -> str:
q = str(params.get("query", "")).strip()
if not q:
return "Errore: serve cosa cercare."
r = requests.get(f"https://www.youtube.com/results?search_query={quote_plus(q)}", headers=UA, timeout=15)
m = re.search(r'"videoId":"([\w-]{11})"', r.text)
if not m:
subprocess.run(["open", f"https://www.youtube.com/results?search_query={quote_plus(q)}"], check=False)
return f"Apro i risultati YouTube per «{q}»."
subprocess.run(["open", f"https://www.youtube.com/watch?v={m.group(1)}"], check=False)
t = re.search(r'"videoId":"' + m.group(1) + r'".{0,400}?"title":\{"runs":\[\{"text":"([^"]+)"', r.text)
return f"Riproduco su YouTube: {html.unescape(t.group(1)) if t else q}."
TOOLS = [
{"name": "web_leggi_pagina", "description": "Legge il testo di una pagina web (dato l'url) o della pagina aperta in Safari, per riassumerla o rispondere.",
"parameters": {"type": "object", "properties": {"url": {"type": "string"}}}, "run": leggi_pagina},
{"name": "web_cerca_apri", "description": "Apre nel browser una ricerca su Google, YouTube, Maps, Amazon o Wikipedia.",
"parameters": {"type": "object", "properties": {"query": {"type": "string"}, "dove": {"type": "string", "enum": ["google", "youtube", "maps", "amazon", "wikipedia"]}}, "required": ["query"]}, "run": cerca},
{"name": "youtube_riproduci", "description": "Cerca un video su YouTube e apre direttamente il primo risultato.",
"parameters": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}, "run": youtube},
]