feat(tts): integrate autonomous Piper neural TTS with zero-latency pre-warming for words and context
This commit is contained in:
@@ -2230,6 +2230,56 @@ def test_wikipedia_api_endpoints_workflow(monkeypatch):
|
||||
assert del_resp.json()["deleted_id"] == book_id
|
||||
|
||||
|
||||
def test_piper_tts_endpoints_and_caching():
|
||||
login_resp = client.post("/api/login", json={"username": "testadmin", "password": "testpass12345"})
|
||||
assert login_resp.status_code == 200
|
||||
token = login_resp.cookies.get(config.SESSION_COOKIE_NAME)
|
||||
auth_headers = {"Cookie": f"{config.SESSION_COOKIE_NAME}={token}"}
|
||||
|
||||
# 1. Test TTS Status endpoint
|
||||
resp = client.get("/api/tts/status", headers=auth_headers)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "available" in data
|
||||
assert data["engine"] == "piper-vits"
|
||||
assert "en_US-lessac" in data["voices"]
|
||||
|
||||
# 2. Test TTS synthesis of English word
|
||||
tts_resp = client.get("/api/tts?text=Astronomy&lang=en&speed=1.0", headers=auth_headers)
|
||||
assert tts_resp.status_code == 200
|
||||
assert "audio/wav" in tts_resp.headers.get("content-type", "")
|
||||
assert len(tts_resp.content) > 1000
|
||||
|
||||
# 3. Test repeat request returns cached audio
|
||||
cached_resp = client.get("/api/tts?text=Astronomy&lang=en&speed=1.0", headers=auth_headers)
|
||||
assert cached_resp.status_code == 200
|
||||
assert len(cached_resp.content) == len(tts_resp.content)
|
||||
|
||||
# 4. Test cached audio streaming via /api/audio/{hash}.wav
|
||||
from app.tts import get_audio_hash
|
||||
h = get_audio_hash("Astronomy", "en", 1.0)
|
||||
audio_file_resp = client.get(f"/api/audio/{h}.wav")
|
||||
assert audio_file_resp.status_code == 200
|
||||
assert "audio/wav" in audio_file_resp.headers.get("content-type", "")
|
||||
assert "immutable" in audio_file_resp.headers.get("cache-control", "")
|
||||
|
||||
# 5. Test card creation attaches audio_url and context_audio_url
|
||||
card_resp = client.post(
|
||||
"/api/cards",
|
||||
json={
|
||||
"term": "Galileo",
|
||||
"translation": "Галилей",
|
||||
"context_sentence": "Galileo pointed his telescope at Jupiter.",
|
||||
},
|
||||
headers=auth_headers,
|
||||
)
|
||||
assert card_resp.status_code == 200
|
||||
card_data = card_resp.json()
|
||||
assert "/api/audio/" in card_data["audio_url"]
|
||||
assert "context_audio_url" in card_data
|
||||
assert "/api/audio/" in card_data["context_audio_url"]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user