Update idle prompt
This commit is contained in:
@@ -52,7 +52,10 @@
|
|||||||
"没有",
|
"没有",
|
||||||
"否"
|
"否"
|
||||||
],
|
],
|
||||||
"user_speech_timeout_sec": 0.8
|
"user_speech_timeout_sec": 0.8,
|
||||||
|
"idle_prompt_timeout_sec": 8.0,
|
||||||
|
"idle_prompt_max_count": 1,
|
||||||
|
"idle_prompt_text": "我先停在这里。你可以继续说你的想法,或者让我根据刚才的内容帮你整理下一步。"
|
||||||
},
|
},
|
||||||
"agent": {
|
"agent": {
|
||||||
"system_prompt": "You are a helpful, friendly voice assistant. Keep responses concise and natural for spoken conversation.",
|
"system_prompt": "You are a helpful, friendly voice assistant. Keep responses concise and natural for spoken conversation.",
|
||||||
|
|||||||
@@ -42,7 +42,10 @@
|
|||||||
"你好",
|
"你好",
|
||||||
"在吗"
|
"在吗"
|
||||||
],
|
],
|
||||||
"user_speech_timeout_sec": 0.2
|
"user_speech_timeout_sec": 0.8,
|
||||||
|
"idle_prompt_timeout_sec": 8.0,
|
||||||
|
"idle_prompt_max_count": 3,
|
||||||
|
"idle_prompt_text": "我先停在这里。你可以继续说你的想法,或者让我根据刚才的内容帮你整理下一步。"
|
||||||
},
|
},
|
||||||
"agent": {
|
"agent": {
|
||||||
"system_prompt": "FastGPT app owns the system prompt when send_system_prompt is false.",
|
"system_prompt": "FastGPT app owns the system prompt when send_system_prompt is false.",
|
||||||
|
|||||||
@@ -78,6 +78,12 @@ class TurnConfig:
|
|||||||
|
|
||||||
vad: VADConfig = field(default_factory=VADConfig)
|
vad: VADConfig = field(default_factory=VADConfig)
|
||||||
user_speech_timeout_sec: float = 1.0
|
user_speech_timeout_sec: float = 1.0
|
||||||
|
idle_prompt_timeout_sec: float = 0.0
|
||||||
|
idle_prompt_max_count: int = 1
|
||||||
|
idle_prompt_text: str = (
|
||||||
|
"我先停在这里。你可以继续说你的想法,"
|
||||||
|
"或者让我根据刚才的内容帮你整理下一步。"
|
||||||
|
)
|
||||||
interruption_min_chars: int = 3
|
interruption_min_chars: int = 3
|
||||||
interruption_use_interim: bool = True
|
interruption_use_interim: bool = True
|
||||||
interruption_short_replies: list[str] = field(
|
interruption_short_replies: list[str] = field(
|
||||||
@@ -263,6 +269,15 @@ def config_from_dict(data: dict) -> EngineConfig:
|
|||||||
user_speech_timeout_sec=float(
|
user_speech_timeout_sec=float(
|
||||||
turn.get("user_speech_timeout_sec", TurnConfig().user_speech_timeout_sec)
|
turn.get("user_speech_timeout_sec", TurnConfig().user_speech_timeout_sec)
|
||||||
),
|
),
|
||||||
|
idle_prompt_timeout_sec=float(
|
||||||
|
turn.get("idle_prompt_timeout_sec", TurnConfig().idle_prompt_timeout_sec)
|
||||||
|
),
|
||||||
|
idle_prompt_max_count=int(
|
||||||
|
turn.get("idle_prompt_max_count", TurnConfig().idle_prompt_max_count)
|
||||||
|
),
|
||||||
|
idle_prompt_text=str(
|
||||||
|
turn.get("idle_prompt_text", TurnConfig().idle_prompt_text)
|
||||||
|
),
|
||||||
interruption_min_chars=int(
|
interruption_min_chars=int(
|
||||||
turn.get("interruption_min_chars", TurnConfig().interruption_min_chars)
|
turn.get("interruption_min_chars", TurnConfig().interruption_min_chars)
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ async def run_pipeline_with_serializer(
|
|||||||
user_params=LLMUserAggregatorParams(
|
user_params=LLMUserAggregatorParams(
|
||||||
vad_analyzer=SileroVADAnalyzer(params=vad_params),
|
vad_analyzer=SileroVADAnalyzer(params=vad_params),
|
||||||
user_turn_strategies=user_turn_strategies,
|
user_turn_strategies=user_turn_strategies,
|
||||||
|
user_idle_timeout=config.turn.idle_prompt_timeout_sec,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -188,6 +189,7 @@ async def run_pipeline_with_serializer(
|
|||||||
),
|
),
|
||||||
idle_timeout_secs=config.session.inactivity_timeout_sec,
|
idle_timeout_secs=config.session.inactivity_timeout_sec,
|
||||||
)
|
)
|
||||||
|
idle_prompt_count = 0
|
||||||
|
|
||||||
@transport.event_handler("on_client_connected")
|
@transport.event_handler("on_client_connected")
|
||||||
async def on_client_connected(_transport, _client):
|
async def on_client_connected(_transport, _client):
|
||||||
@@ -216,6 +218,8 @@ async def run_pipeline_with_serializer(
|
|||||||
|
|
||||||
@user_aggregator.event_handler("on_user_turn_stopped")
|
@user_aggregator.event_handler("on_user_turn_stopped")
|
||||||
async def on_user_turn_stopped(_aggregator, _strategy, message: UserTurnStoppedMessage):
|
async def on_user_turn_stopped(_aggregator, _strategy, message: UserTurnStoppedMessage):
|
||||||
|
nonlocal idle_prompt_count
|
||||||
|
idle_prompt_count = 0
|
||||||
logger.info(f"User: {message.content}")
|
logger.info(f"User: {message.content}")
|
||||||
text = (message.content or "").strip()
|
text = (message.content or "").strip()
|
||||||
if not text:
|
if not text:
|
||||||
@@ -231,6 +235,17 @@ async def run_pipeline_with_serializer(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@user_aggregator.event_handler("on_user_turn_idle")
|
||||||
|
async def on_user_turn_idle(_aggregator):
|
||||||
|
nonlocal idle_prompt_count
|
||||||
|
text = config.turn.idle_prompt_text.strip()
|
||||||
|
if not text or idle_prompt_count >= config.turn.idle_prompt_max_count:
|
||||||
|
return
|
||||||
|
|
||||||
|
idle_prompt_count += 1
|
||||||
|
logger.info("User idle prompt triggered")
|
||||||
|
await task.queue_frames([TTSSpeakFrame(text)])
|
||||||
|
|
||||||
# NOTE: assistant turn started/final events are emitted by
|
# NOTE: assistant turn started/final events are emitted by
|
||||||
# ProductTextStreamProcessor, upstream of TTS, so text streams to the
|
# ProductTextStreamProcessor, upstream of TTS, so text streams to the
|
||||||
# client ahead of audio. This logger is kept for server-side visibility.
|
# client ahead of audio. This logger is kept for server-side visibility.
|
||||||
|
|||||||
Reference in New Issue
Block a user