70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
"""Worker d'enrôlement vocal — process persistant sous ov_venv.
|
|
|
|
Lancé par `voice/bridge.py` (côté API py3.14) via :
|
|
ov_venv/bin/python -m kazeia_central.features.technical.voices.worker
|
|
Garde le modèle OmniVoice (enrôlement + ASR de réf) **chaud**, et sert une file de
|
|
jobs via un protocole JSON-lines sur stdin/stdout.
|
|
|
|
Canal protocole propre : la stack torch/librosa/transformers écrit du bruit sur stdout.
|
|
On capture le **vrai** stdout (fd 1) pour le protocole AVANT de rediriger fd 1 vers
|
|
stderr — ainsi tout `print()`/sortie C de lib part sur stderr (console), et seul le
|
|
JSON du protocole circule sur le pipe lu par le bridge. Sans ça, l'IPC serait corrompu.
|
|
|
|
Protocole :
|
|
requête (1 ligne) : {"id": <n>, "method": "ping|transcribe|enroll|shutdown", "params": {...}}
|
|
réponse (1 ligne) : {"id": <n>, "ok": true, "result": {...}} | {"id": <n>, "ok": false, "error": "..."}
|
|
au démarrage : {"event": "ready"}
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
# --- canal protocole propre (avant tout import lourd) ---------------------
|
|
_proto = os.fdopen(os.dup(1), "w", buffering=1) # vrai stdout (pipe vers le bridge)
|
|
os.dup2(2, 1) # fd 1 → stderr : bruit des libs hors protocole
|
|
|
|
|
|
def _send(obj: dict) -> None:
|
|
_proto.write(json.dumps(obj, ensure_ascii=False) + "\n")
|
|
_proto.flush()
|
|
|
|
|
|
def _handle(method: str, params: dict):
|
|
if method == "ping":
|
|
return {"pong": True, "pid": os.getpid()}
|
|
if method == "transcribe":
|
|
from .transcribe import transcribe
|
|
return transcribe(params["wav"], params.get("model"))
|
|
if method == "enroll":
|
|
from .enroll import enroll
|
|
return enroll(params["wav"], params["text"], params["out"])
|
|
raise ValueError(f"méthode inconnue: {method}")
|
|
|
|
|
|
def main() -> None:
|
|
_send({"event": "ready"})
|
|
for line in sys.stdin:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
try:
|
|
req = json.loads(line)
|
|
except Exception:
|
|
continue
|
|
rid = req.get("id")
|
|
method = req.get("method")
|
|
if method == "shutdown":
|
|
_send({"id": rid, "ok": True, "result": {"bye": True}})
|
|
break
|
|
try:
|
|
_send({"id": rid, "ok": True, "result": _handle(method, req.get("params") or {})})
|
|
except Exception as e: # un job qui échoue ne tue pas le worker
|
|
_send({"id": rid, "ok": False, "error": f"{type(e).__name__}: {e}"})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|