refactor(s2s): 语音助手基础提示词迁移到后端统一管理
- 后端 config.py:新增 S2S_INSTRUCTIONS(.env DPM_S2S_INSTRUCTIONS 可覆盖) - rag.py:build_instructions() 组装 配置提示词 + 园区知识库摘要 - routers.py:GET /api/s2s/instructions 下发(前端连接时拉取) - 前端 VoiceAssistant:删除硬编码 DEFAULT_INSTRUCTIONS,改拉取后端指令; 仅保留后端不可用时的极简兜底 改提示词只需改后端(.env 或代码),前端零硬编码。
This commit is contained in:
@@ -82,6 +82,13 @@ class Settings:
|
||||
S2S_BUILD_RETRIES = int(_env("DPM_S2S_BUILD_RETRIES", "4"))
|
||||
S2S_BUILD_RETRY_DELAY = float(_env("DPM_S2S_BUILD_RETRY_DELAY", "10"))
|
||||
S2S_LOG_LEVEL = _env("DPM_S2S_LOG_LEVEL", "INFO").upper()
|
||||
# 语音助手基础提示词(.env 设 DPM_S2S_INSTRUCTIONS 可覆盖;知识库内容由 rag 自动拼接)
|
||||
S2S_INSTRUCTIONS = _env(
|
||||
"DPM_S2S_INSTRUCTIONS",
|
||||
"你是 PineSound 园区智能语音助手。可用工具:get_park_overview(园区实时数据)、"
|
||||
"query_companies(企业名录)、control_display(大屏控制)、get_time(时间)。"
|
||||
"涉及园区数据/企业/大屏控制时务必调用工具获取准确信息。请用简洁专业的中文回答,不超过三句话。",
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -100,3 +100,16 @@ def brief(max_chars: int = 1200) -> str:
|
||||
out.append(c)
|
||||
total += len(c)
|
||||
return "\n\n".join(out)
|
||||
|
||||
|
||||
def build_instructions() -> str:
|
||||
"""语音助手的完整基础提示词 = 配置提示词 + 园区知识库摘要(服务端统一组装)"""
|
||||
from .config import settings
|
||||
base = settings.S2S_INSTRUCTIONS.strip()
|
||||
try:
|
||||
kb = brief()
|
||||
if kb:
|
||||
base += f"\n\n【园区知识库】\n{kb}"
|
||||
except Exception as e: # noqa: BLE001
|
||||
log.warning("rag: 知识库拼接失败(仅用基础提示词): %s", e)
|
||||
return base
|
||||
|
||||
@@ -465,3 +465,13 @@ def kb_retrieve(q: str = "", top_k: int = 3):
|
||||
except Exception as e: # noqa: BLE001
|
||||
log.warning("kb retrieve 失败: %s", e)
|
||||
return {"ok": False, "error": str(e)}
|
||||
|
||||
@router.get("/api/s2s/instructions")
|
||||
def s2s_instructions():
|
||||
"""语音助手基础提示词(服务端统一组装:配置提示词 + 园区知识库)"""
|
||||
try:
|
||||
from .rag import build_instructions
|
||||
return {"ok": True, "instructions": build_instructions()}
|
||||
except Exception as e: # noqa: BLE001
|
||||
log.warning("s2s instructions 构建失败: %s", e)
|
||||
return {"ok": False, "error": str(e)}
|
||||
|
||||
@@ -16,7 +16,9 @@ import './voice-original.css';
|
||||
import './voice-overrides.css';
|
||||
|
||||
const VOICE_URL = window.__DPM_VOICE_WS__ || `ws://${window.location.hostname}:8765/v1/realtime`;
|
||||
const DEFAULT_INSTRUCTIONS = '你是 PineSound 园区智能语音助手。可用工具:get_park_overview(园区实时数据)、query_companies(企业名录)、control_display(大屏控制)、get_time(时间)。涉及园区数据/企业/大屏控制时务必调用工具获取准确信息。请用简洁专业的中文回答,不超过三句话。';
|
||||
// 基础提示词由后端统一管理(GET /api/s2s/instructions:配置提示词 + 园区知识库),
|
||||
// 前端不硬编码;此处仅为后端不可用时的兜底
|
||||
const FALLBACK_INSTRUCTIONS = '你是 PineSound 园区智能语音助手,请用简洁专业的中文回答,不超过三句话。';
|
||||
const DEFAULT_VOICE = 'Cherry';
|
||||
const DEFAULT_GATE_DB = -50;
|
||||
|
||||
@@ -316,15 +318,13 @@ export default function VoiceAssistant() {
|
||||
if (!audioCtxRef.current) audioCtxRef.current = new AudioContext();
|
||||
if (audioCtxRef.current.state === 'suspended') await audioCtxRef.current.resume();
|
||||
|
||||
// 知识库:拉取园区知识摘要拼进 instructions(静态知识一次注入;失败不影响对话)
|
||||
let instructions = DEFAULT_INSTRUCTIONS;
|
||||
// 基础提示词:从后端拉取(配置 + 园区知识库已由服务端组装);失败用极简兜底
|
||||
let instructions = FALLBACK_INSTRUCTIONS;
|
||||
try {
|
||||
const kbRes = await fetch(`${API_BASE}/api/kb/brief`, { cache: 'no-store' });
|
||||
const kbData = await kbRes.json();
|
||||
if (kbData?.ok && kbData.brief) {
|
||||
instructions = `${DEFAULT_INSTRUCTIONS}\n\n【园区知识库】\n${kbData.brief}`;
|
||||
}
|
||||
} catch { /* 知识库不可用不影响对话 */ }
|
||||
const insRes = await fetch(`${API_BASE}/api/s2s/instructions`, { cache: 'no-store' });
|
||||
const insData = await insRes.json();
|
||||
if (insData?.ok && insData.instructions) instructions = insData.instructions;
|
||||
} catch { /* 后端不可用不影响对话 */ }
|
||||
|
||||
const client = new S2sWsRealtimeClient({
|
||||
directUrl: VOICE_URL,
|
||||
|
||||
Reference in New Issue
Block a user