"""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)[^>]*>.*?", " ", page, flags=re.S | re.I) page = re.sub(r"|

||||", "\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"]*>(.*?)", 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}, ]