feat: 添加 s2s 实时语音 WebSocket 地址支持,并更新相关配置
This commit is contained in:
@@ -82,6 +82,11 @@ 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()
|
||||
# 对外可访问的 s2s 实时语音 WS 地址(供 /api/config 下发;DPM_VOICE_WS 可显式覆盖)
|
||||
S2S_WS_URL = _env(
|
||||
"DPM_VOICE_WS",
|
||||
f"ws://{_env('MQTT_PUBLIC_HOST', _env('MQTT_BROKER_HOST', 'localhost'))}:8765/v1/realtime",
|
||||
)
|
||||
# 语音助手基础提示词(.env 设 DPM_S2S_INSTRUCTIONS 可覆盖;知识库内容由 rag 自动拼接)
|
||||
S2S_INSTRUCTIONS = _env(
|
||||
"DPM_S2S_INSTRUCTIONS",
|
||||
|
||||
@@ -127,6 +127,7 @@ async def runtime_config():
|
||||
"mqtt_url": ws,
|
||||
"mqtt_username": settings.MQTT_USERNAME or "",
|
||||
"mqtt_password": settings.MQTT_PASSWORD or "",
|
||||
"voice_url": settings.S2S_WS_URL,
|
||||
"api_base": f"http://{host}:{settings.PORT}",
|
||||
"broker_host": host,
|
||||
}
|
||||
|
||||
+3
-1
@@ -10,7 +10,8 @@
|
||||
"api_base": "http://192.168.1.9:10085",
|
||||
"mqtt_url": "ws://192.168.1.3:8083/mqtt",
|
||||
"mqtt_username": "dpm",
|
||||
"mqtt_password": "123456"
|
||||
"mqtt_password": "123456",
|
||||
"voice_url": "ws://192.168.1.3:8765/v1/realtime"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,6 +30,7 @@
|
||||
DPM_MQTT_HOST=192.168.1.3
|
||||
DPM_MQTT_PORT=1883
|
||||
DPM_MQTT_WS=ws://192.168.1.3:8083/mqtt # 展播端可访问的 WebSocket 地址
|
||||
DPM_VOICE_WS=ws://192.168.1.3:8765/v1/realtime # s2s 语音 WS(可选,默认按主机推导)
|
||||
MQTT_USERNAME=dpmserver
|
||||
MQTT_PASSWORD=你的密码
|
||||
```
|
||||
|
||||
@@ -41,6 +41,12 @@ export function getMqttCredentials() {
|
||||
};
|
||||
}
|
||||
|
||||
/** 惰性读取 s2s 实时语音 WebSocket 地址(打包部署:tauri.localhost → 127.0.0.1) */
|
||||
export function getVoiceWsUrl() {
|
||||
const baked = env.VITE_VOICE_WS || `ws://${resolveHost()}:8765/v1/realtime`;
|
||||
return window.__DPM_VOICE_WS__ || baked;
|
||||
}
|
||||
|
||||
export const MQTT_TOPIC_COMMAND = 'opc/display/command';
|
||||
export const MQTT_TOPIC_TICK = 'opc/dashboard/tick';
|
||||
export const MQTT_TOPIC_HEARTBEAT = 'opc/display/heartbeat';
|
||||
|
||||
+9
-4
@@ -23,6 +23,7 @@ async function bootstrapRuntimeConfig() {
|
||||
if (cfg.mqtt_url) window.__DPM_MQTT__ = cfg.mqtt_url;
|
||||
if (cfg.mqtt_username) window.__DPM_MQTT_USER__ = cfg.mqtt_username;
|
||||
if (cfg.mqtt_password) window.__DPM_MQTT_PASS__ = cfg.mqtt_password;
|
||||
if (cfg.voice_url) window.__DPM_VOICE_WS__ = cfg.voice_url;
|
||||
// eslint-disable-next-line no-console
|
||||
if (cfg.mqtt_url) console.info(`[bootstrap] config.json MQTT -> ${cfg.mqtt_url}`);
|
||||
}
|
||||
@@ -31,15 +32,19 @@ async function bootstrapRuntimeConfig() {
|
||||
}
|
||||
|
||||
// 2) 后端 /api/config(MQTT 地址/账号;API 基址以前端实际可达地址为准)
|
||||
// 优先级保护:若构建期已用 .env.local 烘焙了 VITE_MQTT_URL,
|
||||
// 则后端 /api/config 不再覆盖(避免后端默认 localhost 冲掉正确地址)。
|
||||
const bakedMqtt = import.meta.env.VITE_MQTT_URL;
|
||||
try {
|
||||
const res = await fetch(`${getApiBase()}/api/config`, { cache: 'no-store' });
|
||||
if (res.ok) {
|
||||
const cfg = await res.json();
|
||||
if (cfg.mqtt_url) window.__DPM_MQTT__ = cfg.mqtt_url;
|
||||
if (cfg.mqtt_username) window.__DPM_MQTT_USER__ = cfg.mqtt_username;
|
||||
if (cfg.mqtt_password) window.__DPM_MQTT_PASS__ = cfg.mqtt_password;
|
||||
if (!bakedMqtt && cfg.mqtt_url) window.__DPM_MQTT__ = cfg.mqtt_url;
|
||||
if (!bakedMqtt && cfg.mqtt_username) window.__DPM_MQTT_USER__ = cfg.mqtt_username;
|
||||
if (!bakedMqtt && cfg.mqtt_password) window.__DPM_MQTT_PASS__ = cfg.mqtt_password;
|
||||
if (!import.meta.env.VITE_VOICE_WS && cfg.voice_url) window.__DPM_VOICE_WS__ = cfg.voice_url;
|
||||
// eslint-disable-next-line no-console
|
||||
if (cfg.mqtt_url) console.info(`[bootstrap] /api/config MQTT -> ${cfg.mqtt_url}`);
|
||||
if (cfg.mqtt_url) console.info(`[bootstrap] /api/config MQTT -> ${cfg.mqtt_url}${bakedMqtt ? '(已烘焙,忽略)' : ''}`);
|
||||
}
|
||||
} catch {
|
||||
/* 后端不可达:使用内置默认地址 */
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { S2sWsRealtimeClient } from '../voice/s2s-ws-client.js';
|
||||
import useVisionDetection, { VISION_DWELL_MS } from '../voice/useVisionDetection.js';
|
||||
import { getApiBase as API_BASE } from '../config';
|
||||
import { getApiBase as API_BASE, getVoiceWsUrl } from '../config';
|
||||
import '../styles/datascreen.css';
|
||||
import './voice-original.css';
|
||||
import './voice-overrides.css';
|
||||
|
||||
const VOICE_URL = window.__DPM_VOICE_WS__ || `ws://${window.location.hostname}:8765/v1/realtime`;
|
||||
// 惰性读取 s2s 地址:打包部署 tauri.localhost → 127.0.0.1,且可在 config.json 覆盖
|
||||
const VOICE_URL = getVoiceWsUrl();
|
||||
// 基础提示词由后端统一管理(GET /api/s2s/instructions:配置提示词 + 园区知识库),
|
||||
// 前端不硬编码;此处仅为后端不可用时的兜底
|
||||
const FALLBACK_INSTRUCTIONS = '你是 PineSound 园区智能语音助手,请用简洁专业的中文回答,不超过三句话。';
|
||||
|
||||
Reference in New Issue
Block a user