"""Home page — quick launcher + active backends + counters.""" import flet as ft from gui import services as svc def _stat_card(title: str, value: str, color: str = "#33d3a4") -> ft.Container: return ft.Container( content=ft.Column( [ ft.Text(title, size=11, color="#8aa0a8"), ft.Text(value, size=22, weight=ft.FontWeight.W_600, color=color), ], spacing=2, ), bgcolor="#15252b", border_radius=10, padding=14, expand=True, ) def build(page: ft.Page) -> ft.Control: running = svc.assistant_is_running() try: llm_b, llm_m = svc.llm_active() except (RuntimeError, OSError, ValueError) as exc: llm_b, llm_m = "—", str(exc) counters = ft.Row( controls=[ _stat_card("Команды", str(_safe_count(svc, "commands"))), _stat_card("Макросы", str(len(svc.macros_all()))), _stat_card("Расписание", str(len(svc.scheduler_all()))), _stat_card("Память (фактов)", str(len(svc.memory_all()))), _stat_card("Плагины", str(len(svc.plugins_all()))), ], spacing=10, ) status_chip = ft.Container( content=ft.Text( "АССИСТЕНТ РАБОТАЕТ" if running else "АССИСТЕНТ ОСТАНОВЛЕН", size=12, weight=ft.FontWeight.W_700, color="#13191c", ), bgcolor="#33d3a4" if running else "#d8d8d8", padding=ft.padding.symmetric(horizontal=12, vertical=6), border_radius=20, ) start_btn = ft.FilledButton( text="Запустить J.A.R.V.I.S.", icon=ft.Icons.PLAY_ARROW, on_click=lambda e: _launch(page, e), disabled=running, ) backends_card = ft.Container( content=ft.Column([ ft.Text("Активный LLM", size=11, color="#8aa0a8"), ft.Text(f"{llm_b} · {llm_m}", size=14, weight=ft.FontWeight.W_500), ], spacing=2), bgcolor="#15252b", border_radius=10, padding=14, ) return ft.Column( controls=[ ft.Row([ ft.Text("J.A.R.V.I.S.", size=28, weight=ft.FontWeight.W_700), status_chip, ], alignment=ft.MainAxisAlignment.SPACE_BETWEEN), ft.Text( "Голосовой ассистент — Python-форк. Эта панель управляет состоянием, " "запускает main.py и переключает движки.", color="#8aa0a8", size=12, ), ft.Divider(color="#1f3540"), backends_card, counters, ft.Divider(color="#1f3540"), start_btn, ], spacing=14, expand=True, scroll=ft.ScrollMode.AUTO, ) def _launch(page: ft.Page, _e) -> None: ok = svc.assistant_run() page.open( ft.SnackBar( content=ft.Text( "Запускаю main.py" if ok else "Не удалось запустить main.py", color="white", ), bgcolor="#33d3a4" if ok else "#d8584f", ) ) def _safe_count(svc_module, kind: str) -> int: """Counts come from disk; if a store fails we display 0 rather than crash.""" try: if kind == "commands": # Don't import the full VA_CMD_LIST machinery — read yaml directly. import os, yaml # pylint: disable=import-outside-toplevel here = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) with open(os.path.join(here, "commands.yaml"), "rt", encoding="utf8") as f: return len(yaml.safe_load(f) or {}) except (OSError, ValueError): return 0 return 0