from typing import Any, Dict, List from sqlmodel import Session, select from core.database import engine from core.settings import ( DEFAULT_STT_AUDIO_FILTER, DEFAULT_STT_AUDIO_PREPROCESS, DEFAULT_STT_DEFAULT_LANGUAGE, DEFAULT_STT_FORCE_SIMPLIFIED, DEFAULT_STT_INITIAL_PROMPT, DEFAULT_STT_MAX_AUDIO_SECONDS, STT_DEVICE, STT_MODEL, ) from models.platform import PlatformSetting from schemas.platform import PlatformSettingsPayload from services.platform_settings_core import ( ACTIVITY_EVENT_RETENTION_SETTING_KEY, DEFAULT_ACTIVITY_EVENT_RETENTION_DAYS, DEFAULT_ALLOWED_ATTACHMENT_EXTENSIONS, SETTING_KEYS, SYSTEM_SETTING_DEFINITIONS, _bootstrap_platform_setting_values, _normalize_extension_list, _read_setting_value, _upsert_setting_row, ) from services.platform_system_settings_service import ( create_or_update_system_setting, delete_system_setting, ensure_default_system_settings, get_activity_event_retention_days, list_system_settings, ) def default_platform_settings() -> PlatformSettingsPayload: bootstrap = _bootstrap_platform_setting_values() return PlatformSettingsPayload( page_size=int(bootstrap["page_size"]), chat_pull_page_size=int(bootstrap["chat_pull_page_size"]), command_auto_unlock_seconds=int(bootstrap["command_auto_unlock_seconds"]), auth_token_ttl_hours=int(bootstrap["auth_token_ttl_hours"]), auth_token_max_active=int(bootstrap["auth_token_max_active"]), upload_max_mb=int(bootstrap["upload_max_mb"]), allowed_attachment_extensions=list(bootstrap["allowed_attachment_extensions"]), workspace_download_extensions=list(bootstrap["workspace_download_extensions"]), speech_enabled=bool(bootstrap["speech_enabled"]), ) def get_platform_settings(session: Session) -> PlatformSettingsPayload: defaults = default_platform_settings() ensure_default_system_settings(session) rows = session.exec(select(PlatformSetting).where(PlatformSetting.key.in_(SETTING_KEYS))).all() data: Dict[str, Any] = {row.key: _read_setting_value(row) for row in rows} merged = defaults.model_dump() merged["page_size"] = max(1, min(100, int(data.get("page_size") or merged["page_size"]))) merged["chat_pull_page_size"] = max(10, min(500, int(data.get("chat_pull_page_size") or merged["chat_pull_page_size"]))) merged["command_auto_unlock_seconds"] = max( 1, min(600, int(data.get("command_auto_unlock_seconds") or merged["command_auto_unlock_seconds"])), ) merged["auth_token_ttl_hours"] = max( 1, min(720, int(data.get("auth_token_ttl_hours") or merged["auth_token_ttl_hours"])), ) merged["auth_token_max_active"] = max( 1, min(20, int(data.get("auth_token_max_active") or merged["auth_token_max_active"])), ) merged["upload_max_mb"] = int(data.get("upload_max_mb") or merged["upload_max_mb"]) merged["allowed_attachment_extensions"] = _normalize_extension_list( data.get("allowed_attachment_extensions", merged["allowed_attachment_extensions"]) ) merged["workspace_download_extensions"] = _normalize_extension_list( data.get("workspace_download_extensions", merged["workspace_download_extensions"]) ) merged["speech_enabled"] = bool(data.get("speech_enabled", merged["speech_enabled"])) return PlatformSettingsPayload.model_validate(merged) def save_platform_settings(session: Session, payload: PlatformSettingsPayload) -> PlatformSettingsPayload: normalized = PlatformSettingsPayload( page_size=max(1, min(100, int(payload.page_size))), chat_pull_page_size=max(10, min(500, int(payload.chat_pull_page_size))), command_auto_unlock_seconds=max(1, min(600, int(payload.command_auto_unlock_seconds))), auth_token_ttl_hours=max(1, min(720, int(payload.auth_token_ttl_hours))), auth_token_max_active=max(1, min(20, int(payload.auth_token_max_active))), upload_max_mb=payload.upload_max_mb, allowed_attachment_extensions=_normalize_extension_list(payload.allowed_attachment_extensions), workspace_download_extensions=_normalize_extension_list(payload.workspace_download_extensions), speech_enabled=bool(payload.speech_enabled), ) payload_by_key = normalized.model_dump() for key in SETTING_KEYS: definition = SYSTEM_SETTING_DEFINITIONS[key] _upsert_setting_row( session, key, name=str(definition["name"]), category=str(definition["category"]), description=str(definition["description"]), value_type=str(definition["value_type"]), value=payload_by_key[key], is_public=bool(definition["is_public"]), sort_order=int(definition["sort_order"]), ) session.commit() return normalized def get_platform_settings_snapshot() -> PlatformSettingsPayload: with Session(engine) as session: return get_platform_settings(session) def get_upload_max_mb() -> int: return get_platform_settings_snapshot().upload_max_mb def get_allowed_attachment_extensions() -> List[str]: return get_platform_settings_snapshot().allowed_attachment_extensions def get_workspace_download_extensions() -> List[str]: return get_platform_settings_snapshot().workspace_download_extensions def get_page_size() -> int: return get_platform_settings_snapshot().page_size def get_chat_pull_page_size() -> int: return get_platform_settings_snapshot().chat_pull_page_size def get_auth_token_ttl_hours(session: Session) -> int: return get_platform_settings(session).auth_token_ttl_hours def get_auth_token_max_active(session: Session) -> int: return get_platform_settings(session).auth_token_max_active def get_speech_runtime_settings() -> Dict[str, Any]: settings = get_platform_settings_snapshot() return { "enabled": bool(settings.speech_enabled), "max_audio_seconds": int(DEFAULT_STT_MAX_AUDIO_SECONDS), "default_language": str(DEFAULT_STT_DEFAULT_LANGUAGE or "zh").strip().lower() or "zh", "force_simplified": bool(DEFAULT_STT_FORCE_SIMPLIFIED), "audio_preprocess": bool(DEFAULT_STT_AUDIO_PREPROCESS), "audio_filter": str(DEFAULT_STT_AUDIO_FILTER or "").strip(), "initial_prompt": str(DEFAULT_STT_INITIAL_PROMPT or "").strip(), "model": STT_MODEL, "device": STT_DEVICE, }