""" 场景配置加载与运行时准备 """ import copy import json import time import uuid from pathlib import Path from typing import Any from fastapi import Request from config.custom_scene import ( CUSTOM_SCENE_ID, build_custom_scene_from_env, build_llm_settings_from_env, ) from security.rtc_token import AccessToken, privileges from utils.validation import assert_scene_value, assert_token_generation_ready BASE_DIR = Path(__file__).resolve().parent.parent SCENES_DIR = BASE_DIR / "scenes" def load_scenes() -> dict: scenes = { CUSTOM_SCENE_ID: build_custom_scene_from_env(), } for p in sorted(SCENES_DIR.glob("*.json")): if p.stem == CUSTOM_SCENE_ID: continue with open(p, encoding="utf-8") as f: scenes[p.stem] = json.load(f) return scenes def prepare_scene_runtime(scene_name: str, data: dict[str, Any]): data = copy.deepcopy(data) scene_config = data.get("SceneConfig", {}) rtc_config = data.get("RTCConfig", {}) voice_chat = data.get("VoiceChat", {}) app_id = rtc_config.get("AppId", "") assert_scene_value(scene_name, "RTCConfig.AppId", app_id) token = rtc_config.get("Token", "") user_id = rtc_config.get("UserId", "") room_id = rtc_config.get("RoomId", "") app_key = rtc_config.get("AppKey", "") if app_id and (not token or not user_id or not room_id): rtc_config["RoomId"] = voice_chat["RoomId"] = room_id or str(uuid.uuid4()) rtc_config["UserId"] = user_id = user_id or str(uuid.uuid4()) agent_config = voice_chat.get("AgentConfig", {}) target_user_ids = agent_config.get("TargetUserId") if target_user_ids: target_user_ids[0] = rtc_config["UserId"] assert_token_generation_ready(scene_name, app_key) key = AccessToken(app_id, app_key, rtc_config["RoomId"], rtc_config["UserId"]) key.add_privilege(privileges["PrivSubscribeStream"], 0) key.add_privilege(privileges["PrivPublishStream"], 0) key.expire_time(int(time.time()) + 24 * 3600) rtc_config["Token"] = key.serialize() return scene_config, rtc_config, voice_chat def get_custom_llm_callback_settings() -> dict[str, Any]: missing: list[str] = [] settings = build_llm_settings_from_env(missing) if missing: missing_str = ", ".join(dict.fromkeys(missing)) raise ValueError(f"Custom 场景缺少以下环境变量: {missing_str}") return settings def ensure_custom_llm_authorized(request: Request, api_key: str): if not api_key: return authorization = request.headers.get("authorization", "") expected_value = f"Bearer {api_key}" if authorization == expected_value: return raise PermissionError("自定义 LLM 回调鉴权失败,请检查 CUSTOM_LLM_API_KEY") try: Scenes = load_scenes() except ValueError as exc: raise RuntimeError(f"Custom 场景配置错误:{exc}") from exc