move vad config to json

This commit is contained in:
Xin Wang
2026-05-21 17:23:04 +08:00
parent 6a59df3dbd
commit 872b8ac64a
6 changed files with 135 additions and 1 deletions

View File

@@ -28,6 +28,39 @@ class SessionConfig:
inactivity_timeout_sec: int = 60
@dataclass(frozen=True)
class VADConfig:
"""Voice Activity Detection thresholds for the Silero analyzer.
These map directly to ``pipecat.audio.vad.vad_analyzer.VADParams``.
Defaults are tuned a touch more conservative than upstream pipecat so
short pauses in continuous speech don't end the user turn prematurely.
"""
confidence: float = 0.7
start_secs: float = 0.2
stop_secs: float = 0.6
min_volume: float = 0.6
@dataclass(frozen=True)
class TurnConfig:
"""User-turn segmentation policy.
``user_speech_timeout_sec`` is the grace window (in seconds) after VAD
has confirmed silence during which the user is allowed to resume
speaking before the aggregator finalizes the turn. Used by
``SpeechTimeoutUserTurnStopStrategy``. Higher = more tolerant of
natural mid-sentence pauses; lower = snappier turn-taking.
The combined "user pause before turn ends" budget is roughly
``vad.stop_secs + user_speech_timeout_sec``.
"""
vad: VADConfig = field(default_factory=VADConfig)
user_speech_timeout_sec: float = 1.0
@dataclass(frozen=True)
class AgentConfig:
system_prompt: str = "You are a helpful, friendly voice assistant."
@@ -90,6 +123,7 @@ class EngineConfig:
server: ServerConfig = field(default_factory=ServerConfig)
audio: AudioConfig = field(default_factory=AudioConfig)
session: SessionConfig = field(default_factory=SessionConfig)
turn: TurnConfig = field(default_factory=TurnConfig)
agent: AgentConfig = field(default_factory=AgentConfig)
services: ServicesConfig = field(default_factory=ServicesConfig)
@@ -116,10 +150,19 @@ def config_from_dict(data: dict) -> EngineConfig:
if stt.get("language") == "":
stt["language"] = None
turn = _dict(data.get("turn"))
vad = _dict(turn.get("vad"))
return EngineConfig(
server=ServerConfig(**_dict(data.get("server"))),
audio=AudioConfig(**_dict(data.get("audio"))),
session=SessionConfig(**_dict(data.get("session"))),
turn=TurnConfig(
vad=VADConfig(**vad),
user_speech_timeout_sec=float(
turn.get("user_speech_timeout_sec", TurnConfig().user_speech_timeout_sec)
),
),
agent=AgentConfig(**agent),
services=ServicesConfig(
llm=LLMConfig(**_dict(services.get("llm"))),

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
from loguru import logger
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams
from pipecat.frames.frames import (
LLMRunFrame,
OutputTransportMessageUrgentFrame,
@@ -24,6 +25,10 @@ from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from pipecat.turns.user_stop.speech_timeout_user_turn_stop_strategy import (
SpeechTimeoutUserTurnStopStrategy,
)
from pipecat.turns.user_turn_strategies import UserTurnStrategies
from .config import EngineConfig
from .product_protocol import ProductWebsocketSerializer
@@ -84,9 +89,33 @@ async def run_pipeline_with_serializer(
messages.append({"role": "system", "content": config.agent.greeting})
context = LLMContext(messages)
vad_params = VADParams(
confidence=config.turn.vad.confidence,
start_secs=config.turn.vad.start_secs,
stop_secs=config.turn.vad.stop_secs,
min_volume=config.turn.vad.min_volume,
)
# Replace pipecat's default stop strategy (Smart Turn v3) with a simple
# silence-timeout strategy. Smart Turn v3 was finalizing every short
# Chinese phrase as a complete turn, which caused one logical utterance
# to become several LLM calls and several user bubbles in the UI. The
# timeout strategy waits for `user_speech_timeout_sec` of silence
# (re-armed every time the user resumes speaking) before declaring the
# turn finished — which is what we actually want for streaming ASRs.
user_turn_strategies = UserTurnStrategies(
stop=[
SpeechTimeoutUserTurnStopStrategy(
user_speech_timeout=config.turn.user_speech_timeout_sec,
),
],
)
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
context,
user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
user_params=LLMUserAggregatorParams(
vad_analyzer=SileroVADAnalyzer(params=vad_params),
user_turn_strategies=user_turn_strategies,
),
)
pipeline = Pipeline(