Speech calls keep one connection per server, opened when listening starts

transcribe and speak share an httpx client per speech server with a 300 s
keep-alive, and run on the engine's loop. stt warms it with GET /v1/models
when an utterance opens, so a reply's first sentence finds the connection
open: a new one over a lossy link cost up to a second (openpanel V4).
This commit is contained in:
Melvin Strobl
2026-10-19 22:06:08 +02:00
parent f50d8b9570
commit 4df7bdb057
4 changed files with 67 additions and 26 deletions
+18 -4
View File
@@ -52,6 +52,12 @@ def test_an_utterance_is_one_session_committed_when_listening_ends(monkeypatch):
yield True, " Turn on the light."
monkeypatch.setattr(client, "transcribe_stream", session)
warmed: list[str] = []
async def warm(api_base):
warmed.append(api_base)
monkeypatch.setattr(client, "warm", warm)
async def scenario() -> None:
node = SttNode(
@@ -94,6 +100,8 @@ def test_an_utterance_is_one_session_committed_when_listening_ends(monkeypatch):
assert pipeline.state["voice.text"] == "Turn on the light."
assert pipeline.state["voice.partial"] == "Turn on the light."
assert node._session is None
# Opened with the session, for the reply's first sentence.
assert warmed == [f"{URL}/v1"]
# No server, no session: the node says so instead.
await hear(chunks[1], True, url="")
@@ -131,10 +139,16 @@ def test_a_sentence_is_spoken_once_and_the_rest_of_a_reply_queues(monkeypatch):
Pipeline([node])
node._artifacts = Store()
node.execute({"voice.reply": "Kitchen light on. Heating off.", "voice.url": URL})
# Long after both stopped playing.
node._until = -10.0
node.execute({"voice.reply": "Kitchen light on.", "voice.url": URL})
async def scenario() -> None:
node._loop = asyncio.get_running_loop()
reply = "Kitchen light on. Heating off."
await asyncio.to_thread(node.execute, {"voice.reply": reply, "voice.url": URL})
# Long after both stopped playing.
node._until = -10.0
reply = "Kitchen light on."
await asyncio.to_thread(node.execute, {"voice.reply": reply, "voice.url": URL})
asyncio.run(scenario())
assert spoken == ["Kitchen light on.", "Heating off."]
assert ["append" in speech for speech in published] == [False, True, False]