Files
avatar/plugins/note.py
T
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

81 lines
3.8 KiB
Python

"""Note di macOS: crea, cerca e legge note (AppleScript)."""
from __future__ import annotations
import html
import re
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from avatar.macos import osa # noqa: E402
SEP = "␟"
def _testo(body_html: str) -> str:
t = re.sub(r"<br\s*/?>|</div>|</p>|</li>", "\n", body_html, flags=re.I)
t = html.unescape(re.sub(r"<[^>]+>", "", t))
return "\n".join(line.strip() for line in t.splitlines() if line.strip())
def crea(params: dict, ctx: dict) -> str:
titolo = str(params.get("titolo", "")).strip() or "Nota"
testo = str(params.get("testo", "")).strip()
body = f"<h1>{html.escape(titolo)}</h1>" + "".join(f"<div>{html.escape(l) or '<br>'}</div>" for l in testo.splitlines())
osa('on run argv\ntell application "Notes" to make new note at folder "Notes" with properties {name:item 1 of argv, body:item 2 of argv}\nend run', titolo, body)
return f"Nota creata: «{titolo}»."
def cerca(params: dict, ctx: dict) -> str:
q = str(params.get("query", "")).strip()
if not q:
return "Errore: serve il campo 'query'."
out = osa(f'''on run argv
set sep to "{SEP}"
set out to ""
set n to 0
tell application "Notes"
repeat with nt in (notes whose name contains (item 1 of argv) or plaintext contains (item 1 of argv))
set n to n + 1
if n > 8 then exit repeat
set out to out & (name of nt) & sep & ((modification date of nt) as string) & linefeed
end repeat
end tell
return out
end run''', q, timeout=90)
rows = [l.split(SEP) for l in out.splitlines() if l]
if not rows:
return f"Nessuna nota trovata per '{q}'."
return f"Note trovate per '{q}':\n" + "\n".join(f"- {r[0]} ({r[1]})" for r in rows) + "\nPer leggerne una usa note_leggi con il titolo."
def leggi(params: dict, ctx: dict) -> str:
titolo = str(params.get("titolo", "")).strip()
if not titolo:
return "Errore: serve il titolo."
out = osa('on run argv\ntell application "Notes" to return body of (first note whose name contains (item 1 of argv))\nend run', titolo, timeout=60)
testo = _testo(out)
return testo[:2500] + (" […]" if len(testo) > 2500 else "") if testo else "Nota vuota."
def aggiungi(params: dict, ctx: dict) -> str:
titolo = str(params.get("titolo", "")).strip()
testo = str(params.get("testo", "")).strip()
if not titolo or not testo:
return "Errore: servono titolo (della nota esistente) e testo da aggiungere."
extra = "".join(f"<div>{html.escape(l) or '<br>'}</div>" for l in testo.splitlines())
osa('on run argv\ntell application "Notes"\nset nt to first note whose name contains (item 1 of argv)\nset body of nt to (body of nt) & (item 2 of argv)\nend tell\nend run', titolo, extra)
return f"Aggiunto alla nota «{titolo}»."
TOOLS = [
{"name": "note_crea", "description": "Crea una nuova nota nell'app Note con titolo e testo. Usalo per 'prendi nota', 'appunta che…'.",
"parameters": {"type": "object", "properties": {"titolo": {"type": "string"}, "testo": {"type": "string"}}, "required": ["testo"]}, "run": crea},
{"name": "note_aggiungi", "description": "Aggiunge testo in fondo a una nota esistente, cercata per titolo.",
"parameters": {"type": "object", "properties": {"titolo": {"type": "string"}, "testo": {"type": "string"}}, "required": ["titolo", "testo"]}, "run": aggiungi},
{"name": "note_cerca", "description": "Cerca note per parola nel titolo o nel testo.",
"parameters": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}, "run": cerca},
{"name": "note_leggi", "description": "Legge il contenuto di una nota cercata per titolo.",
"parameters": {"type": "object", "properties": {"titolo": {"type": "string"}}, "required": ["titolo"]}, "run": leggi},
]