from typing import Any, Dict from fastapi import APIRouter, HTTPException from sqlmodel import Session, select from core.database import engine, get_session from core.settings import DATABASE_ENGINE, PANEL_ACCESS_PASSWORD, REDIS_ENABLED, REDIS_PREFIX, REDIS_URL from core.utils import _get_default_system_timezone from models.bot import BotInstance from schemas.system import PanelLoginRequest, SystemTemplatesUpdateRequest from core.cache import cache from services.platform_service import get_platform_settings_snapshot, get_speech_runtime_settings from services.template_service import ( get_agent_md_templates, get_topic_presets, update_agent_md_templates, update_topic_presets, ) router = APIRouter() @router.get("/api/panel/auth/status") def get_panel_auth_status(): configured = str(PANEL_ACCESS_PASSWORD or "").strip() return {"enabled": bool(configured)} @router.post("/api/panel/auth/login") def panel_login(payload: PanelLoginRequest): configured = str(PANEL_ACCESS_PASSWORD or "").strip() if not configured: return {"success": True, "enabled": False} supplied = str(payload.password or "").strip() if supplied != configured: raise HTTPException(status_code=401, detail="Invalid panel access password") return {"success": True, "enabled": True} @router.get("/api/system/defaults") def get_system_defaults(): md_templates = get_agent_md_templates() platform_settings = get_platform_settings_snapshot() speech_settings = get_speech_runtime_settings() return { "templates": md_templates, "limits": { "upload_max_mb": platform_settings.upload_max_mb, }, "workspace": { "download_extensions": list(platform_settings.workspace_download_extensions), "allowed_attachment_extensions": list(platform_settings.allowed_attachment_extensions), }, "bot": { "system_timezone": _get_default_system_timezone(), }, "chat": { "pull_page_size": platform_settings.chat_pull_page_size, "page_size": platform_settings.page_size, "command_auto_unlock_seconds": platform_settings.command_auto_unlock_seconds, }, "topic_presets": get_topic_presets().get("presets", []), "speech": { "enabled": speech_settings["enabled"], "model": speech_settings["model"], "device": speech_settings["device"], "max_audio_seconds": speech_settings["max_audio_seconds"], "default_language": speech_settings["default_language"], }, } @router.get("/api/system/templates") def get_system_templates(): return { "agent_md_templates": get_agent_md_templates(), "topic_presets": get_topic_presets(), } @router.put("/api/system/templates") def update_system_templates(payload: SystemTemplatesUpdateRequest): if payload.agent_md_templates is not None: update_agent_md_templates(payload.agent_md_templates.model_dump()) if payload.topic_presets is not None: try: update_topic_presets(payload.topic_presets) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc return { "status": "ok", "agent_md_templates": get_agent_md_templates(), "topic_presets": get_topic_presets(), } @router.get("/api/health") def get_health(): try: with Session(engine) as session: session.exec(select(BotInstance).limit(1)).first() return {"status": "ok", "database": DATABASE_ENGINE} except Exception as e: raise HTTPException(status_code=503, detail=f"database check failed: {e}") @router.get("/api/health/cache") def get_cache_health(): redis_url = str(REDIS_URL or "").strip() configured = bool(REDIS_ENABLED and redis_url) client_enabled = bool(getattr(cache, "enabled", False)) reachable = bool(cache.ping()) if client_enabled else False status = "ok" if configured and not reachable: status = "degraded" return { "status": status, "cache": { "configured": configured, "enabled": client_enabled, "reachable": reachable, "prefix": REDIS_PREFIX, }, }