This commit is contained in:
pporcheret
2026-11-01 15:01:22 +01:00
parent 2c5537aff1
commit e2340807aa
36 changed files with 4952 additions and 8 deletions
+55 -8
View File
@@ -26,6 +26,7 @@ from services.alfred_duplex import DuplexMonitor # ALFRED_DUPLEX_BARGE_IN_V1
from services.piper_tts import stop_playback as duplex_stop_piper
from services import admin_console # ALFRED_ADMIN_PAGES_V1
from services.hermes_client import ask_hermes
from services import dona_clock_local as _dona_clock_local # DONA_CLOCK_SCULPTURE_V11
from services import alfred_timers, alfred_context_images # ALFRED_TIMERS_CONTEXT_V1
from services import alfred_features # ALFRED_FEATURES_V45
from services import audio_settings # ALFRED_AUDIO_SETTINGS_V1
@@ -44,6 +45,11 @@ get_vosk_model(os.environ["VOSK_MODEL_PATH"])
print("[ALFRED] Modèles vocaux prêts.", flush=True)
##
app=Flask(__name__); socketio=SocketIO(app,cors_allowed_origins="*")
# DONA_WAVES_V1 : événement léger, pas de flux audio transmis au navigateur.
from services import piper_tts as _dona_waves_piper
_dona_waves_piper.dona_set_level_callback(
lambda level: socketio.emit('dona_piper_level', {'level': round(level, 4)})
)
STATE={"mode":"idle","title":"Alfred","content":{"type":"text","text":"À votre écoute."},"partial":""}
STATE_LOCK = threading.RLock()
IMAGE_REVISION = 0 # Incrémenté à chaque image envoyée par ComfyUI.
@@ -128,6 +134,24 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
content={"type": "text", "text": r.text}
)
# DONA_CLOCK_SCULPTURE_V11 : heure/date locales AVANT Hermes.
_dona_local_clock_reply = _dona_clock_local.answer(r.text)
if _dona_local_clock_reply is not None:
with STATE_LOCK:
STATE['content']={'type':'text','text':_dona_local_clock_reply}
socketio.emit('alfred_render',STATE['content'])
socketio.emit('dona_learning_turn',
_dona_learning_v93.track('voice',_dona_v93_original_vosk,_dona_local_clock_reply))
if not audio_settings.speaker_muted():
emit_state('speaking')
_dona_clock_done=threading.Event()
_dona_clock_started=speak_async(_dona_local_clock_reply,
on_end=lambda: (_dona_clock_done.set(),
socketio.emit('alfred_tts_finished', {'source':'voice'})))
if _dona_clock_started:_dona_clock_done.wait(timeout=120)
emit_state('idle',partial='')
return
# DONA_VISION_V95 : photo locale et compréhension par Hermes sur demande.
if _dona_vision_v95.is_camera_question(r.text):
try:
@@ -200,7 +224,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
return
# DONA_V8_DYNAMIC — creation visuelle explicite, source Hermes/MCP ou API directe.
if _dona_dynamic.is_dynamic_request(r.text):
if _dona_dynamic.is_dynamic_request(r.text) or _dona_json_autorender.is_monitor_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}
@@ -288,6 +312,7 @@ def conversation(score=1.0, injected_text=None): # ALFRED_DUPLEX_CONVERSATION_V
else:
speech = str(answer or "")
display = {"type": "text", "text": speech}
display, speech = _dona_json_autorender.convert(answer, r.text, display, speech)
# DONA_LEARNING_V93 : évaluation du tour Hermes, RAM seulement avant 👍 / 👎.
socketio.emit('dona_learning_turn',
@@ -642,13 +667,21 @@ def _alfred_dashboard_quick_command(prompt):
_image_revision_before = IMAGE_REVISION
emit_state('thinking', transcript=prompt, partial='',
content={'type':'text', 'text':prompt})
_answer = ask_hermes(prompt)
if isinstance(_answer, dict):
_speech = str(_answer.get('speech') or _answer.get('text') or '')
_display = _answer.get('display') or {'type':'text','text':_speech}
# DONA_JSON_AUTORENDER_V1: operational shortcuts use the isolated
# dashboard session; ordinary shortcuts remain regular Hermes calls.
if _dona_dynamic.is_dynamic_request(prompt) or _dona_json_autorender.is_monitor_request(prompt):
_board = _dona_dynamic.build_dashboard(prompt, _dona_dashboard_agent.ask_dashboard)
_display = {'type':'dona_dynamic','dashboard':_board}
_speech = 'Voici le tableau de bord : ' + _board['title']
else:
_speech = str(_answer or '')
_display = {'type':'text','text':_speech}
_answer = ask_hermes(prompt)
if isinstance(_answer, dict):
_speech = str(_answer.get('speech') or _answer.get('text') or '')
_display = _answer.get('display') or {'type':'text','text':_speech}
else:
_speech = str(_answer or '')
_display = {'type':'text','text':_speech}
_display, _speech = _dona_json_autorender.convert(_answer, prompt, _display, _speech)
# Une image ComfyUI publiee pendant Hermes ne doit pas etre effacee.
with STATE_LOCK:
if IMAGE_REVISION == _image_revision_before:
@@ -722,6 +755,17 @@ def _dona_submit_typed(prompt):
_before_image = IMAGE_REVISION
emit_state('thinking', partial='', transcript=prompt,
content={'type': 'text', 'text': prompt})
# DONA_CLOCK_SCULPTURE_V11 : même traitement depuis Écrire à Dona / raccourcis.
_dona_local_clock_reply = _dona_clock_local.answer(prompt)
if _dona_local_clock_reply is not None:
with STATE_LOCK:
STATE['content']={'type':'text','text':_dona_local_clock_reply}
socketio.emit('alfred_render',STATE['content'])
socketio.emit('dona_learning_turn',
_dona_learning_v93.track('typed',prompt,_dona_local_clock_reply))
emit_state('idle',partial='')
return
# DONA_VISION_V95 : demande écrite de vision depuis la caméra réelle.
if _dona_vision_v95.is_camera_question(prompt):
try:
@@ -767,7 +811,7 @@ def _dona_submit_typed(prompt):
return
# DONA_V8_DYNAMIC — commandes visuelles saisies via le formulaire habituel.
if _dona_dynamic.is_dynamic_request(prompt):
if _dona_dynamic.is_dynamic_request(prompt) or _dona_json_autorender.is_monitor_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}
@@ -783,6 +827,7 @@ def _dona_submit_typed(prompt):
else:
_speech = str(_answer or '')
_display = {'type':'text','text':_speech}
_display, _speech = _dona_json_autorender.convert(_answer, prompt, _display, _speech)
with STATE_LOCK:
if IMAGE_REVISION == _before_image:
STATE['content'] = _display
@@ -810,6 +855,8 @@ _dona_register_family(app, adult_command=_dona_submit_typed)
# DONA_V8_DYNAMIC — tableau de bord choisi, généré et rendu en composants contrôlés.
from services import dona_dynamic as _dona_dynamic
# DONA_JSON_AUTORENDER_V1 : rendu automatique JSON Hermes, demandes et raccourcis
from services import dona_json_autorender_v1 as _dona_json_autorender
# DONA_V8_1_ISOLATION : tableaux isolés des conversations normales
from services import dona_dashboard_agent as _dona_dashboard_agent