This commit is contained in:
pporcheret
2026-10-31 11:04:45 +01:00
parent 90ffa635a0
commit 2c5537aff1
53 changed files with 7950 additions and 22 deletions
+103 -5
View File
@@ -106,6 +106,21 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
emit_state("idle", partial="")
return
# DONA_LEARNING_V93 : évaluation vocale explicite, puis correction Vosk approuvée.
_dona_v93_original_vosk = r.text
_dona_v93_ack = _dona_learning_v93.voice_feedback(r.text)
if _dona_v93_ack is not None:
socketio.emit('alfred_render', {'type':'text','text':_dona_v93_ack})
if not audio_settings.speaker_muted():
_dona_v93_done = threading.Event()
if speak_async(_dona_v93_ack,on_end=_dona_v93_done.set):
_dona_v93_done.wait(timeout=120)
emit_state('idle',partial='')
return
r.text = _dona_learning_v93.correct_transcript(r.text)
if r.text != _dona_v93_original_vosk:
socketio.emit('dona_learning_stt', {'raw':_dona_v93_original_vosk,'used':r.text})
emit_state(
"thinking",
partial="",
@@ -113,9 +128,41 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
content={"type": "text", "text": r.text}
)
# DONA_VISION_V95 : photo locale et compréhension par Hermes sur demande.
if _dona_vision_v95.is_camera_question(r.text):
try:
_vision_answer = _dona_vision_monitor.analyze(r.text)
except RuntimeError as _vision_exc:
_vision_answer = str(_vision_exc)
except Exception as _vision_exc:
print('[DONA VISION] Analyse vocale :',type(_vision_exc).__name__,flush=True)
_vision_answer = 'Analyse visuelle indisponible. Vérifie le modèle vision Hermes.'
with STATE_LOCK:
STATE['content']={'type':'text','text':_vision_answer}
socketio.emit('alfred_render',STATE['content'])
socketio.emit('dona_learning_turn',_dona_learning_v93.track('voice',_dona_v93_original_vosk,_vision_answer))
if _vision_answer and not audio_settings.speaker_muted():
emit_state('speaking')
_vision_done=threading.Event()
if speak_async(_vision_answer[:850],on_end=_vision_done.set):_vision_done.wait(timeout=120)
emit_state('idle',partial='')
return
# DONA_FILES_V91 : questions explicites sur la pièce jointe active.
if _dona_files_v91.is_file_question(r.text):
_file_speech = _dona_files_v91.handle_voice(r.text, socketio, STATE, STATE_LOCK)
socketio.emit('dona_learning_turn', _dona_learning_v93.track('voice',_dona_v93_original_vosk,_file_speech))
if _file_speech and not audio_settings.speaker_muted():
emit_state('speaking')
_file_done = threading.Event()
if speak_async(_file_speech, on_end=_file_done.set): _file_done.wait(timeout=120)
emit_state('idle', partial='')
return
# DONA_SUITE_V9: intents locaux explicites, sinon continuer vers Hermes.
if _dona_suite_v9.is_request(r.text):
_v9_speech=_dona_suite_v9.handle_and_emit(r.text,socketio)
socketio.emit('dona_learning_turn', _dona_learning_v93.track('voice',_dona_v93_original_vosk,_v9_speech))
if _v9_speech and not audio_settings.speaker_muted():
emit_state('speaking')
_v9_done=threading.Event()
@@ -127,6 +174,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
# DONA_NAV_V83: cartes et itinéraires à la demande, sans LLM.
if _dona_nav.is_request(r.text):
_nav_reply=_dona_nav.handle_and_emit(r.text,socketio,STATE,STATE_LOCK)
socketio.emit('dona_learning_turn', _dona_learning_v93.track('voice',_dona_v93_original_vosk,_nav_reply))
if _nav_reply and not audio_settings.speaker_muted():
emit_state('speaking')
_nav_done=threading.Event()
@@ -138,6 +186,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
# DONA_YOUTUBE_V82 : recherche publique et contrôle du lecteur à la voix.
if _dona_youtube.is_search(r.text):
_speech=_dona_youtube.search_and_emit(r.text, socketio, STATE, STATE_LOCK)
socketio.emit('dona_learning_turn', _dona_learning_v93.track('voice',_dona_v93_original_vosk,_speech))
if _speech and not audio_settings.speaker_muted():
emit_state('speaking')
_evt=threading.Event()
@@ -153,6 +202,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
# DONA_V8_DYNAMIC — creation visuelle explicite, source Hermes/MCP ou API directe.
if _dona_dynamic.is_dynamic_request(r.text):
_board = _dona_dynamic.build_dashboard(r.text, _dona_dashboard_agent.ask_dashboard)
socketio.emit('dona_learning_turn',_dona_learning_v93.track('voice',_dona_v93_original_vosk,_board.get('title','Tableau de bord')))
_payload = {'type':'dona_dynamic', 'dashboard':_board}
with STATE_LOCK:
STATE['content'] = _payload
@@ -176,6 +226,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
if visual is not None:
content, speech = visual
socketio.emit('dona_learning_turn', _dona_learning_v93.track('voice',_dona_v93_original_vosk,speech))
with STATE_LOCK:
STATE["content"] = content
socketio.emit("alfred_render", content)
@@ -196,6 +247,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
print('[ALFRED LISTES] Erreur :', _lists_error, flush=True)
_lists_reply = 'Je n’ai pas pu modifier la liste. Vérifie le stockage d’Alfred.'
if _lists_reply is not None:
socketio.emit('dona_learning_turn', _dona_learning_v93.track('voice',_dona_v93_original_vosk,_lists_reply))
_lists_display = {'type':'text', 'text':_lists_reply}
with STATE_LOCK:
STATE['content'] = _lists_display
@@ -225,7 +277,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
emit_state('error', content={'type': 'text', 'text': str(exc)})
return
# DONA_V7_RELEASE: reconnaissance sur ordre vocal explicite, sinon Hermes normal.
answer = _dona_face_recognize(ask_hermes) if _dona_face_request(r.text) else ask_hermes(r.text)
answer = _dona_face_recognize(ask_hermes) if _dona_face_request(r.text) else ask_hermes(_dona_learning_v93.enhance_prompt(r.text))
print(f"[ALFRED] Réponse Hermes : {answer!r}", flush=True)
if isinstance(answer, dict):
speech = str(answer.get("speech") or answer.get("text") or "")
@@ -237,6 +289,10 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
speech = str(answer or "")
display = {"type": "text", "text": speech}
# DONA_LEARNING_V93 : évaluation du tour Hermes, RAM seulement avant 👍 / 👎.
socketio.emit('dona_learning_turn',
_dona_learning_v93.track('voice',_dona_v93_original_vosk,speech))
# Une illustration contextuelle (Wikipédia) peut compléter la réponse Hermes.
# Elle n'interrompt pas la lecture TTS et ne remplace pas la scène centrale.
alfred_context_images.schedule_context_image(
@@ -666,21 +722,43 @@ def _dona_submit_typed(prompt):
_before_image = IMAGE_REVISION
emit_state('thinking', partial='', transcript=prompt,
content={'type': 'text', 'text': prompt})
# DONA_VISION_V95 : demande écrite de vision depuis la caméra réelle.
if _dona_vision_v95.is_camera_question(prompt):
try:
_vision_answer=_dona_vision_monitor.analyze(prompt)
except Exception as _vision_exc:
_vision_answer=str(_vision_exc)[:190] if isinstance(_vision_exc,RuntimeError) else 'Analyse visuelle indisponible.'
with STATE_LOCK:
STATE['content']={'type':'text','text':_vision_answer}
socketio.emit('alfred_render',STATE['content'])
socketio.emit('dona_learning_turn',_dona_learning_v93.track('typed',prompt,_vision_answer))
emit_state('idle',partial='')
return
# DONA_FILES_V91 : question écrite à propos de la dernière pièce jointe.
if _dona_files_v91.is_file_question(prompt):
_dona_files_v91.handle_voice(prompt, socketio, STATE, STATE_LOCK)
emit_state('idle',partial='')
return
# DONA_SUITE_V9: commandes quotidiennes écrites, sans perturber Hermes.
if _dona_suite_v9.is_request(prompt):
_dona_suite_v9.handle_and_emit(prompt,socketio)
_v93_local=_dona_suite_v9.handle_and_emit(prompt,socketio)
socketio.emit('dona_learning_turn',_dona_learning_v93.track('typed',prompt,_v93_local))
emit_state('idle',partial='')
return
# DONA_NAV_V83: commande écrite navigation, sans polluer la session Hermes.
if _dona_nav.is_request(prompt):
_dona_nav.handle_and_emit(prompt,socketio,STATE,STATE_LOCK)
_v93_local=_dona_nav.handle_and_emit(prompt,socketio,STATE,STATE_LOCK)
socketio.emit('dona_learning_turn',_dona_learning_v93.track('typed',prompt,_v93_local))
emit_state('idle',partial='')
return
# DONA_YOUTUBE_V82 : vidéos et commandes écrites hors conversation Hermes.
if _dona_youtube.is_search(prompt):
_dona_youtube.search_and_emit(prompt,socketio,STATE,STATE_LOCK)
_v93_local=_dona_youtube.search_and_emit(prompt,socketio,STATE,STATE_LOCK)
socketio.emit('dona_learning_turn',_dona_learning_v93.track('typed',prompt,_v93_local))
emit_state('idle',partial='')
return
if _dona_youtube.is_control(prompt,_dona_youtube.player_active()):
@@ -691,13 +769,14 @@ def _dona_submit_typed(prompt):
# DONA_V8_DYNAMIC — commandes visuelles saisies via le formulaire habituel.
if _dona_dynamic.is_dynamic_request(prompt):
_board = _dona_dynamic.build_dashboard(prompt, _dona_dashboard_agent.ask_dashboard)
socketio.emit('dona_learning_turn',_dona_learning_v93.track('typed',prompt,_board.get('title','Tableau de bord')))
_payload = {'type':'dona_dynamic','dashboard':_board}
with STATE_LOCK:
STATE['content'] = _payload
socketio.emit('alfred_render',_payload)
emit_state('idle', partial='')
return
_answer = ask_hermes(prompt)
_answer = ask_hermes(_dona_learning_v93.enhance_prompt(prompt))
if isinstance(_answer, dict):
_speech = str(_answer.get('speech') or _answer.get('text') or '')
_display = _answer.get('display') or {'type':'text','text':_speech}
@@ -708,6 +787,9 @@ def _dona_submit_typed(prompt):
if IMAGE_REVISION == _before_image:
STATE['content'] = _display
socketio.emit('alfred_render', _display)
# DONA_LEARNING_V93 : évaluation de l’échange écrit.
socketio.emit('dona_learning_turn',
_dona_learning_v93.track('typed',prompt,_speech))
# Deliberately no speak_async(): typed interaction is silent.
emit_state('idle', partial='')
except Exception as exc:
@@ -756,6 +838,22 @@ def _dona_dynamic_submit(prompt):
_dona_dynamic.register_dynamic(app,_dona_dynamic_submit)
# DONA_VISION_V95 : API vision/YOLOv8, surveillance opt-in.
from services import dona_vision_v95 as _dona_vision_v95
_dona_vision_monitor = _dona_vision_v95.register(app, socketio)
# DONA_LEARNING_V93 : retours explicites et corrections approuvées.
from services import dona_learning_v93 as _dona_learning_v93
_dona_learning_v93.register(app)
# DONA_UI_V92 : préférences de raccourcis persistantes, menus gérés côté navigateur.
from services import dona_shortcuts_v92 as _dona_shortcuts_v92
_dona_shortcuts_v92.register(app)
# DONA_FILES_V91 : fichiers temporaires et analyse Hermes isolée.
from services import dona_files_v91 as _dona_files_v91
_dona_files_v91.register_files(app)
# DONA_SUITE_V9 : routeur local, cockpit, mémoire, cuisine, documents, routines.
from services import dona_suite_v9 as _dona_suite_v9
_dona_suite_v9.register_suite(app,socketio)