Add voice state tags, SuperTTS configs, and demo WS log groups.

Parse leading <state> tags from LLM replies and emit response.state over the product websocket while stripping tags from TTS/text streams. Add FastGPT+Xfyun voice configs (including state-enabled preset), SuperTTS support, and context sync for interrupted turns. Refresh the voice demo with a state indicator and collapsible audio delta websocket log groups.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xin Wang
2026-05-28 11:32:20 +08:00
parent b14ef64665
commit 9e2374f492
18 changed files with 1596 additions and 195 deletions

View File

@@ -10,11 +10,13 @@ from pipecat.services.openai._constants import OPENAI_SAMPLE_RATE
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.services.openai.stt import OpenAISTTService
from pipecat.services.openai.tts import VALID_VOICES, OpenAITTSService
from pipecat.services.tts_service import TextAggregationMode
from pipecat.transcriptions.language import Language
from .config import AudioConfig, LLMConfig, STTConfig, TTSConfig
from .fastgpt_llm import FastGPTLLMService, FastGPTLLMSettings
from .xfyun_asr import DEFAULT_XFYUN_ASR_URL, XfyunASRService
from .xfyun_super_tts import DEFAULT_XFYUN_SUPER_TTS_URL, XfyunSuperTTSService
from .xfyun_tts import DEFAULT_XFYUN_TTS_URL, XfyunTTSService
@@ -54,12 +56,13 @@ def create_llm_service(
session_variables: dict | None = None,
greeting_prompt: str | None = None,
):
if config.provider == "fastgpt":
if config.is_fastgpt:
variables = {**config.variables, **(session_variables or {})}
return FastGPTLLMService(
api_key=config.api_key,
base_url=config.base_url or "http://localhost:3000",
chat_id=chat_id or config.chat_id,
app_id=config.app_id,
send_system_prompt=config.send_system_prompt,
greeting_prompt=greeting_prompt,
timeout=config.timeout_sec,
@@ -70,7 +73,11 @@ def create_llm_service(
),
)
_require_provider(config.provider, "openai", "llm")
if not config.is_openai:
supported = ", ".join(sorted(("openai", "fastgpt", "llm")))
raise ValueError(
f"Unsupported llm provider {config.provider!r}; expected one of: {supported}"
)
return OpenAILLMService(
api_key=config.api_key or None,
base_url=config.base_url,
@@ -102,6 +109,30 @@ def create_tts_service(config: TTSConfig, audio: AudioConfig):
timeout=config.timeout_sec,
)
if config.provider in ("xfyun_super", "xfyun_super_tts"):
source_sample_rate = config.source_sample_rate_hz or 24000
if source_sample_rate not in (8000, 16000, 24000):
raise ValueError(
"Xfyun Super TTS source_sample_rate_hz must be 8000, 16000, or 24000"
)
text_aggregation_mode = config.text_aggregation_mode or TextAggregationMode.TOKEN
return XfyunSuperTTSService(
app_id=config.app_id,
api_key=config.api_key or "",
api_secret=config.api_secret,
voice=config.voice,
url=config.base_url or DEFAULT_XFYUN_SUPER_TTS_URL,
sample_rate=audio.sample_rate_hz,
source_sample_rate=source_sample_rate,
encoding=config.aue,
speed=config.speed,
volume=config.volume,
pitch=config.pitch,
oral_level=config.oral_level,
text_aggregation_mode=text_aggregation_mode,
open_timeout=config.timeout_sec,
)
_require_provider(config.provider, "openai", "tts")
service_class = OpenAITTSService if config.voice in VALID_VOICES else OpenAICompatibleTTSService
return service_class(