98 lines
3.4 KiB
Python
98 lines
3.4 KiB
Python
"""AvatarPy: assistente personale con volto animato (interfaccia da Mark-LIV, motori propri)."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import platform
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent
|
|
sys.path.insert(0, str(BASE_DIR))
|
|
|
|
from avatar.settings import CONFIG_DIR, Settings # noqa: E402
|
|
|
|
|
|
def ensure_identity_file() -> None:
|
|
"""L'interfaccia legge config/api_keys.json per nome, colore e stato di configurazione."""
|
|
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
f = CONFIG_DIR / "api_keys.json"
|
|
data: dict = {}
|
|
if f.exists():
|
|
try:
|
|
data = json.loads(f.read_text(encoding="utf-8"))
|
|
except Exception:
|
|
data = {}
|
|
changed = False
|
|
if not data.get("os_system"):
|
|
data["os_system"] = {"Darwin": "mac", "Windows": "windows"}.get(platform.system(), "linux")
|
|
changed = True
|
|
if not data.get("assistant_name"):
|
|
data["assistant_name"] = "Ava"
|
|
changed = True
|
|
if changed:
|
|
f.write_text(json.dumps(data, indent=4, ensure_ascii=False), encoding="utf-8")
|
|
|
|
|
|
def main() -> None:
|
|
ensure_identity_file()
|
|
settings = Settings()
|
|
try:
|
|
from PyQt6 import QtWebEngineWidgets # noqa: F401 (va importato prima della QApplication)
|
|
except Exception as err:
|
|
print(f"[avatar3d] WebEngine non disponibile: {err}")
|
|
from ui import JarvisUI # crea la QApplication
|
|
from avatar.assistant import Assistant
|
|
from avatar.settings_dialog import SettingsDialog
|
|
|
|
ui = JarvisUI(str(BASE_DIR / "core" / "face_model.obj"))
|
|
ui._win._log._ai_name_lc = ui.assistant_name.lower()
|
|
assistant = Assistant(ui, settings)
|
|
|
|
ui.on_text_command = assistant.handle_text
|
|
ui.on_interrupt = assistant.interrupt
|
|
ui.on_voice_change = lambda: assistant.reload_voice(from_customise=True)
|
|
ui.on_audio_device_change = assistant.reopen_audio
|
|
ui.on_push_to_talk = assistant.set_push_to_talk
|
|
ui.ptt_hold = assistant.ptt_hold
|
|
ui.on_wake_toggle = assistant.on_wake_toggle
|
|
ui.on_wake_manual = assistant.on_wake_manual
|
|
ui.wake_get_state = assistant.wake_get_state
|
|
from avatar.plugins import registry
|
|
from core import confirm
|
|
confirm.bind(ui.show_confirm, ui.hide_confirm, ui.write_log)
|
|
registry.ctx = {"say": assistant.say, "log": ui.write_log, "confirm": confirm.request, "player": ui}
|
|
ui.get_plugins = registry.list_for_ui
|
|
from avatar.mcp_client import manager as mcp_manager
|
|
mcp_manager.start(registry, ui.write_log)
|
|
ui._app.aboutToQuit.connect(mcp_manager.stop)
|
|
ui.get_plugin_settings = lambda: []
|
|
ui.request_say = assistant.say
|
|
# Questi due sono attributi della finestra, non della facciata JarvisUI.
|
|
ui._win.on_new_conversation = assistant.reset_conversation
|
|
|
|
def open_settings() -> None:
|
|
SettingsDialog(settings, assistant.reconfigure, parent=ui._win).exec()
|
|
|
|
ui._win.on_engine_settings = open_settings
|
|
|
|
if "--smoke" in sys.argv:
|
|
from PyQt6.QtCore import QTimer
|
|
QTimer.singleShot(3000, lambda: (print("SMOKE OK"), ui._app.quit()))
|
|
else:
|
|
if not settings.ready:
|
|
from PyQt6.QtCore import QTimer
|
|
QTimer.singleShot(800, open_settings)
|
|
assistant.start()
|
|
try:
|
|
ui.root.mainloop()
|
|
finally:
|
|
try:
|
|
from avatar import whatsapp_bridge as wb
|
|
wb.stop()
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|