rtc-voice-chat/backend/services/scene_service.py

97 lines
2.9 KiB
Python

"""
场景配置加载与运行时准备
"""
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