File size: 4,338 Bytes
f234692 7825141 f234692 7825141 eb93c12 7825141 864a4d0 7825141 6f92dc6 7825141 864a4d0 7825141 864a4d0 7825141 f234692 7825141 f234692 7825141 f234692 7825141 f234692 7825141 f234692 7825141 864a4d0 7825141 f234692 7825141 864a4d0 7825141 7da7aca 7825141 f234692 7825141 f234692 7825141 864a4d0 7825141 864a4d0 7825141 eb93c12 7825141 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | import logging
import re
import os
import tempfile
import time
log = logging.getLogger(__name__)
from prompts import SYSTEM_PROMPT, PHASE_SWITCH_REMINDER
from parse_feedback import parse_feedback, render_feedback_table, strip_markdown
from stt_engine import transcribe, warmup as stt_warmup
from llm_engine import chat as llm_chat, warmup as llm_warmup
from tts_engine import synthesize
TERMINATE_RE = re.compile(
r"(fin\s+de\s+(la\s+)?séance|session\s+terminée|on\s+a\s+terminé|c'est\s+fini)",
re.IGNORECASE,
)
def make_initial_state():
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
return {"messages": messages, "phase": 1, "turn_count": 0}
def _chat_val(state):
return [m for m in state["messages"] if m.get("content") != PHASE_SWITCH_REMINDER]
def _make_audio(audio_bytes):
if not audio_bytes:
return None
f = tempfile.NamedTemporaryFile(suffix=".wav", delete=False, dir=tempfile.gettempdir())
f.write(audio_bytes)
f.close()
return os.path.basename(f.name)
def _default_feedback():
"""Return a blank feedback result block."""
return {
"feedback_intro": "",
"feedback_points_forts": [],
"feedback_table": [],
"feedback_vocabulaire": [],
"feedback_priorite": [],
"feedback_bilan": {},
"feedback_open": False,
}
def process_turn(audio_path, state):
state = dict(state)
result = {
"chat": _chat_val(state),
"audio_file": None,
"state": state,
**_default_feedback(),
"status": "",
}
if not audio_path:
return result
result["status"] = "🎙 Transcription…"
_t0 = time.monotonic()
user_text = transcribe(audio_path)
_t1 = time.monotonic()
if not user_text or len(user_text.strip()) < 2:
result["status"] = "⛔ Parlez plus fort ou plus longtemps."
return result
state["messages"].append({"role": "user", "content": user_text.strip()})
if TERMINATE_RE.search(user_text):
return _end_session(state)
result["status"] = "🧠 Réflexion…"
response = llm_chat(state["messages"])
_t2 = time.monotonic()
if not response:
result["status"] = "⛔ Erreur du modèle. Réessayez."
return result
clean = strip_markdown(response)
state["messages"].append({"role": "assistant", "content": clean})
result["status"] = "🔊 Synthèse vocale…"
audio_bytes = synthesize(clean)
_t3 = time.monotonic()
result["audio_file"] = _make_audio(audio_bytes)
log.info("LATENCY stt=%.1fs llm=%.1fs tts=%.1fs total=%.1fs",
_t1 - _t0, _t2 - _t1, _t3 - _t2, _t3 - _t0)
result["chat"] = _chat_val(state)
result["status"] = ""
return result
def _end_session(state):
state["messages"].append({"role": "user", "content": PHASE_SWITCH_REMINDER})
result = {
"chat": _chat_val(state),
"audio_file": None,
"state": state,
**_default_feedback(),
"status": "📝 Génération du récapitulatif…",
}
response = llm_chat(state["messages"])
_t0_base = time.monotonic()
_t0 = _t0_base
if not response:
result["status"] = "⛔ Erreur lors de la génération du bilan."
return result
clean = strip_markdown(response)
state["phase"] = 2
fb = parse_feedback(clean)
table = render_feedback_table(fb["erreurs"]) if fb["erreurs"] else []
intro = fb.get("intro") or clean
state["messages"].append({"role": "assistant", "content": intro})
audio_bytes = synthesize(intro)
_t1 = time.monotonic()
result["chat"] = _chat_val(state)
result["audio_file"] = _make_audio(audio_bytes)
log.info("LATENCY llm=%.1fs tts=%.1fs total=%.1fs",
_t0 - _t0_base, _t1 - _t0, _t1 - _t0_base)
result["feedback_intro"] = intro
result["feedback_points_forts"] = fb["points_forts"]
result["feedback_table"] = table
result["feedback_vocabulaire"] = fb["vocabulaire"]
result["feedback_priorite"] = fb["priorite"]
result["feedback_bilan"] = fb["bilan"]
result["feedback_open"] = True
result["status"] = ""
return result
def end_session_click(state):
return _end_session(dict(state))
def reset_session():
stt_warmup()
llm_warmup()
return make_initial_state()
|