feat: Audio-Streaming (chunked TTS) über WebSocket (#4 Ausbau)
- SentenceChunker (pipeline/sentence_chunker.py): inkrementelle Satzsegmentierung
- Orchestrator.chat_stream(on_audio): satzweise TTS, Audio-Chunk pro fertigem Satz;
Gesamtaudio zusaetzlich an den Output-Endpunkt
- WS /ws/chat {"audio_stream":true}: audio-Events (json seq + binaerer Frame) live,
kein finales Vollaudio; mit stream kombinierbar
- Tests: 45 gruen (+2: Sentence-Chunker, Audio-Streaming)
- Doku aktualisiert (README, BEDIENUNGSANLEITUNG, Architektur)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
379e002460
commit
b5913b0a44
7 changed files with 157 additions and 19 deletions
|
|
@ -96,11 +96,25 @@ async def ws_chat(
|
|||
|
||||
voice = msg.get("voice") or settings.openrouter_tts_voice
|
||||
stream = bool(msg.get("stream"))
|
||||
try:
|
||||
if stream:
|
||||
async def on_token(delta):
|
||||
await websocket.send_json({"type": "token", "text": delta})
|
||||
audio_stream = bool(msg.get("audio_stream"))
|
||||
|
||||
on_token = None
|
||||
if stream:
|
||||
async def on_token(delta):
|
||||
await websocket.send_json({"type": "token", "text": delta})
|
||||
|
||||
on_audio = None
|
||||
if audio_stream:
|
||||
audio_seq = 0
|
||||
|
||||
async def on_audio(chunk):
|
||||
nonlocal audio_seq
|
||||
await websocket.send_json({"type": "audio", "seq": audio_seq})
|
||||
audio_seq += 1
|
||||
await websocket.send_bytes(chunk)
|
||||
|
||||
try:
|
||||
if stream or audio_stream:
|
||||
trace, audio = await orchestrator.chat_stream(
|
||||
text,
|
||||
language=route.language,
|
||||
|
|
@ -108,6 +122,7 @@ async def ws_chat(
|
|||
output=output,
|
||||
history=llm_context,
|
||||
on_token=on_token,
|
||||
on_audio=on_audio,
|
||||
)
|
||||
else:
|
||||
trace, audio = await orchestrator.chat_text(
|
||||
|
|
@ -132,7 +147,9 @@ async def ws_chat(
|
|||
"spoken": trace.spoken_response,
|
||||
}
|
||||
)
|
||||
await websocket.send_bytes(audio)
|
||||
# Bei audio_stream wurden die Audio-Chunks bereits live gesendet.
|
||||
if not audio_stream:
|
||||
await websocket.send_bytes(audio)
|
||||
await websocket.send_json(
|
||||
{"type": "done", "audio_format": "pcm", "sample_rate": 24000}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue