Files
avatar/plugins/contatti.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

66 lines
2.4 KiB
Python

"""Contatti di macOS: cerca numero, email e dati di una persona (framework Contacts)."""
from __future__ import annotations
import threading
_store = None
_lock = threading.Lock()
def _get_store():
global _store
with _lock:
if _store is not None:
return _store
import Contacts
store = Contacts.CNContactStore.alloc().init()
done, res = threading.Event(), {}
def cb(granted, err):
res["granted"] = bool(granted)
done.set()
store.requestAccessForEntityType_completionHandler_(Contacts.CNEntityTypeContacts, cb)
done.wait(60)
if not res.get("granted"):
raise RuntimeError("Accesso ai Contatti negato: concedilo in Impostazioni di Sistema > Privacy e sicurezza > Contatti.")
_store = store
return store
def cerca(params: dict, ctx: dict) -> str:
import Contacts
q = str(params.get("nome", "")).strip()
if not q:
return "Errore: serve il nome."
store = _get_store()
keys = [Contacts.CNContactGivenNameKey, Contacts.CNContactFamilyNameKey, Contacts.CNContactOrganizationNameKey,
Contacts.CNContactPhoneNumbersKey, Contacts.CNContactEmailAddressesKey]
pred = Contacts.CNContact.predicateForContactsMatchingName_(q)
people, err = store.unifiedContactsMatchingPredicate_keysToFetch_error_(pred, keys, None)
if err:
return f"Errore: {err}"
people = list(people or [])[:6]
if not people:
return f"Nessun contatto trovato per '{q}'."
lines = []
for p in people:
name = f"{p.givenName()} {p.familyName()}".strip() or p.organizationName()
bits = [name]
tels = [ph.value().stringValue() for ph in p.phoneNumbers()]
mails = [str(e.value()) for e in p.emailAddresses()]
if tels:
bits.append("tel " + ", ".join(tels))
if mails:
bits.append("email " + ", ".join(mails))
if p.organizationName() and p.organizationName() != name:
bits.append(p.organizationName())
lines.append("- " + " · ".join(bits))
return "\n".join(lines)
TOOLS = [
{"name": "contatti_cerca", "description": "Cerca una persona in Contatti e restituisce telefono, email e azienda. Usalo per trovare l'indirizzo email o il numero prima di scrivere a qualcuno per nome.",
"parameters": {"type": "object", "properties": {"nome": {"type": "string"}}, "required": ["nome"]}, "run": cerca},
]