BryanBradfo commited on
Commit
b3f4332
·
verified ·
1 Parent(s): 0165fec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +32 -53
app.py CHANGED
@@ -32,7 +32,7 @@ OPENINGS_DB = _load_lichess_openings()
32
  # --- ANALYSE ---
33
 
34
  def get_engine_analysis(board, time_limit=0.5):
35
- """Analyse sécurisée qui ne plante pas en fin de jeu."""
36
  if board.is_game_over(): return "N/A", "PARTIE TERMINÉE", ""
37
  if not os.path.exists(STOCKFISH_PATH): return "0", "Engine missing", ""
38
 
@@ -48,7 +48,6 @@ def get_engine_analysis(board, time_limit=0.5):
48
 
49
  best_move = info.get("pv", [None])[0]
50
  if best_move:
51
- # Traduction simple pour le log
52
  dest = chess.square_name(best_move.to_square)
53
  origin = chess.square_name(best_move.from_square)
54
  desc = f"{origin} ➔ {dest}"
@@ -76,9 +75,10 @@ def get_ai_move(board, level):
76
  except:
77
  return None
78
 
79
- # --- AUDIO & CHAT ---
80
 
81
  def generate_voice(text):
 
82
  if not openai_client or not text: return None
83
  try:
84
  response = openai_client.audio.speech.create(
@@ -89,9 +89,15 @@ def generate_voice(text):
89
  )
90
  unique = f"deepblue_{uuid.uuid4()}.mp3"
91
  path = os.path.join("/tmp", unique)
92
- response.stream_to_file(path)
 
 
 
 
 
93
  return path
94
- except:
 
95
  return None
96
 
97
  def transcribe(audio_path):
@@ -103,7 +109,7 @@ def transcribe(audio_path):
103
  except:
104
  return None
105
 
106
- # --- PERSONA DEEP BLUE (DIRECTIF) ---
107
 
108
  SYSTEM_PROMPT = """
109
  Tu es DEEP BLUE, supercalculateur d'échecs.
@@ -113,23 +119,21 @@ RÈGLE ABSOLUE DE FORMAT :
113
  1. Dis le COUP à jouer. (ex: "Joue Cavalier f3.", "Prends le pion e5.").
114
  2. Dis la RAISON stratégique. (ex: "Ceci contrôle le centre.", "Cela ouvre la ligne pour la Tour.").
115
 
116
- Ton : Froid, direct, efficace. Pas de "Bonjour", pas de "Je pense".
117
  Si le joueur gagne : "MAT CONFIRMÉ. FIN DE SESSION."
118
  """
119
 
120
  def consult_deepblue(fen, mode="auto", user_audio=None):
121
  board = chess.Board(fen)
122
 
123
- # GESTION FIN DE PARTIE (Anti-Erreur)
124
  if board.is_game_over():
125
  if board.is_checkmate():
126
  msg = "ÉCHEC ET MAT. PARTIE TERMINÉE."
127
  if board.turn == chess.BLACK: msg += " VICTOIRE HUMAINE."
128
- else: msg += " VICTOIRE SYSTEME."
129
  return msg, generate_voice(msg), "FIN"
130
- return "PARTIE NULLE/PAT.", None, "FIN"
131
 
132
- # Données
133
  score, best_move_text, arrow_simple = get_engine_analysis(board)
134
 
135
  opening = "N/A"
@@ -158,32 +162,26 @@ def consult_deepblue(fen, mode="auto", user_audio=None):
158
  messages=[{"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": context}]
159
  )
160
  reply = response.choices[0].message.content
161
- except Exception as e:
162
- reply = f"Erreur: {e}"
163
 
164
  audio = generate_voice(reply)
165
-
166
- # On retourne aussi arrow_simple pour l'historique
167
  return reply, audio, arrow_simple
168
 
169
  # --- BOUCLE DE JEU ---
170
 
171
  def update_history(new_advice, history_list):
172
- """Gère l'historique des conseils (Max 3 + scroll)."""
173
  if not new_advice or new_advice == "FIN": return history_list
174
-
175
- # On ajoute le conseil en haut de la liste
176
  history_list.insert(0, f"➤ {new_advice}")
177
  return history_list
178
 
179
  def format_history_display(history_list):
180
- """Affiche l'historique sous forme de texte propre."""
181
  return "\n\n".join(history_list)
182
 
183
  def game_cycle(fen, level, history_list):
184
  board = chess.Board(fen)
185
 
186
- # 1. Vérif Fin de jeu immédiate
187
  if board.is_game_over():
188
  text, audio, _ = consult_deepblue(fen)
189
  return fen, text, audio, format_history_display(history_list), history_list
@@ -193,15 +191,11 @@ def game_cycle(fen, level, history_list):
193
  ai_move = get_ai_move(board, level)
194
  if ai_move: board.push(ai_move)
195
 
196
- # Conseil Deep Blue après le coup noir
197
  text, audio, arrow = consult_deepblue(board.fen(), mode="auto")
198
-
199
- # Mise à jour historique avec le coup conseillé
200
  new_hist = update_history(f"Conseil: {arrow}", history_list)
201
-
202
  return board.fen(), text, audio, format_history_display(new_hist), new_hist
203
 
204
- return fen, "En attente...", None, format_history_display(history_list), history_list
205
 
206
  def reset_game():
207
  return chess.STARTING_FEN, "SYSTÈME RÉINITIALISÉ.", None, "", []
@@ -223,65 +217,50 @@ button.secondary { background-color: #1e293b !important; color: #94a3b8 !importa
223
 
224
  # --- INTERFACE ---
225
 
226
- with gr.Blocks(title="Deep Blue", css=css, theme=gr.themes.Base()) as demo:
227
 
228
  # HEADER
229
  with gr.Row():
230
- gr.Markdown("# 🟦 DEEP BLUE AI", elem_id="title")
231
 
232
  with gr.Row():
233
- level = gr.Dropdown(["Débutant", "Intermédiaire", "Avancé", "Grand Maître"], value="Débutant", label="Difficulté CPU", interactive=True)
 
234
 
235
  # MAIN
236
  with gr.Row():
237
- # COLONNE GAUCHE (PLATEAU)
238
  with gr.Column(scale=2):
239
  board = Chessboard(elem_id="board", label="Zone de Combat", value=chess.STARTING_FEN, game_mode=True, interactive=True)
240
 
241
- # COLONNE DROITE (CONTROLES)
242
  with gr.Column(scale=1):
243
  btn_reset = gr.Button("🔄 RESTART SYSTEM", variant="secondary")
244
 
245
  gr.Markdown("### 📟 Terminal Sortie")
246
  coach_txt = gr.Textbox(label="Message", interactive=False, lines=3, elem_classes="feedback")
247
- coach_audio = gr.Audio(label="Synthèse", autoplay=True, interactive=False, type="filepath", visible=False) # Audio caché mais actif
 
 
248
 
249
  gr.Markdown("### 📜 Log Tactique")
250
- # State pour garder la liste en mémoire
251
  history_state = gr.State([])
252
- # Affichage texte
253
- history_display = gr.Textbox(label="Historique Conseils (Derniers coups)", interactive=False, lines=5, max_lines=10, elem_classes="feedback")
254
 
255
  gr.Markdown("### 🎤 Input Vocal")
256
  mic = gr.Audio(sources=["microphone"], type="filepath", show_label=False)
257
  btn_ask = gr.Button("TRANSMETTRE QUESTION", variant="primary")
258
 
259
  # LOGIQUE
260
-
261
- # 1. Jeu
262
  board.move(
263
  fn=game_cycle,
264
  inputs=[board, level, history_state],
265
  outputs=[board, coach_txt, coach_audio, history_display, history_state]
266
  )
267
 
268
- # 2. Reset
269
- btn_reset.click(
270
- fn=reset_game,
271
- outputs=[board, coach_txt, coach_audio, history_display, history_state]
272
- )
273
-
274
- # 3. Question
275
- btn_ask.click(
276
- fn=ask_deepblue,
277
- inputs=[board, mic, history_state],
278
- outputs=[coach_txt, coach_audio, history_display, history_state]
279
- )
280
- mic.stop_recording(
281
- fn=ask_deepblue,
282
- inputs=[board, mic, history_state],
283
- outputs=[coach_txt, coach_audio, history_display, history_state]
284
- )
285
 
286
  if __name__ == "__main__":
287
  demo.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False, allowed_paths=["/tmp"])
 
32
  # --- ANALYSE ---
33
 
34
  def get_engine_analysis(board, time_limit=0.5):
35
+ """Analyse sécurisée."""
36
  if board.is_game_over(): return "N/A", "PARTIE TERMINÉE", ""
37
  if not os.path.exists(STOCKFISH_PATH): return "0", "Engine missing", ""
38
 
 
48
 
49
  best_move = info.get("pv", [None])[0]
50
  if best_move:
 
51
  dest = chess.square_name(best_move.to_square)
52
  origin = chess.square_name(best_move.from_square)
53
  desc = f"{origin} ➔ {dest}"
 
75
  except:
76
  return None
77
 
78
+ # --- AUDIO & CHAT (CORRECTIF IMPORTANT) ---
79
 
80
  def generate_voice(text):
81
+ """Génération audio robuste avec écriture binaire directe."""
82
  if not openai_client or not text: return None
83
  try:
84
  response = openai_client.audio.speech.create(
 
89
  )
90
  unique = f"deepblue_{uuid.uuid4()}.mp3"
91
  path = os.path.join("/tmp", unique)
92
+
93
+ # CORRECTIF: Utilisation de iter_bytes() au lieu de stream_to_file (déprécié)
94
+ with open(path, "wb") as f:
95
+ for chunk in response.iter_bytes():
96
+ f.write(chunk)
97
+
98
  return path
99
+ except Exception as e:
100
+ print(f"Audio Error: {e}")
101
  return None
102
 
103
  def transcribe(audio_path):
 
109
  except:
110
  return None
111
 
112
+ # --- PERSONA DEEP BLUE ---
113
 
114
  SYSTEM_PROMPT = """
115
  Tu es DEEP BLUE, supercalculateur d'échecs.
 
119
  1. Dis le COUP à jouer. (ex: "Joue Cavalier f3.", "Prends le pion e5.").
120
  2. Dis la RAISON stratégique. (ex: "Ceci contrôle le centre.", "Cela ouvre la ligne pour la Tour.").
121
 
122
+ Ton : Froid, direct, efficace. Pas de "Bonjour".
123
  Si le joueur gagne : "MAT CONFIRMÉ. FIN DE SESSION."
124
  """
125
 
126
  def consult_deepblue(fen, mode="auto", user_audio=None):
127
  board = chess.Board(fen)
128
 
 
129
  if board.is_game_over():
130
  if board.is_checkmate():
131
  msg = "ÉCHEC ET MAT. PARTIE TERMINÉE."
132
  if board.turn == chess.BLACK: msg += " VICTOIRE HUMAINE."
133
+ else: msg += " VICTOIRE SYSTÈME."
134
  return msg, generate_voice(msg), "FIN"
135
+ return "PARTIE NULLE.", None, "FIN"
136
 
 
137
  score, best_move_text, arrow_simple = get_engine_analysis(board)
138
 
139
  opening = "N/A"
 
162
  messages=[{"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": context}]
163
  )
164
  reply = response.choices[0].message.content
165
+ except:
166
+ reply = "Erreur IA."
167
 
168
  audio = generate_voice(reply)
 
 
169
  return reply, audio, arrow_simple
170
 
171
  # --- BOUCLE DE JEU ---
172
 
173
  def update_history(new_advice, history_list):
 
174
  if not new_advice or new_advice == "FIN": return history_list
 
 
175
  history_list.insert(0, f"➤ {new_advice}")
176
  return history_list
177
 
178
  def format_history_display(history_list):
 
179
  return "\n\n".join(history_list)
180
 
181
  def game_cycle(fen, level, history_list):
182
  board = chess.Board(fen)
183
 
184
+ # 1. Fin de jeu ?
185
  if board.is_game_over():
186
  text, audio, _ = consult_deepblue(fen)
187
  return fen, text, audio, format_history_display(history_list), history_list
 
191
  ai_move = get_ai_move(board, level)
192
  if ai_move: board.push(ai_move)
193
 
 
194
  text, audio, arrow = consult_deepblue(board.fen(), mode="auto")
 
 
195
  new_hist = update_history(f"Conseil: {arrow}", history_list)
 
196
  return board.fen(), text, audio, format_history_display(new_hist), new_hist
197
 
198
+ return fen, "Attente...", None, format_history_display(history_list), history_list
199
 
200
  def reset_game():
201
  return chess.STARTING_FEN, "SYSTÈME RÉINITIALISÉ.", None, "", []
 
217
 
218
  # --- INTERFACE ---
219
 
220
+ with gr.Blocks(title="Coach Deep Blue", css=css, theme=gr.themes.Base()) as demo:
221
 
222
  # HEADER
223
  with gr.Row():
224
+ gr.Markdown("# 🟦 COACH DEEP BLUE", elem_id="title")
225
 
226
  with gr.Row():
227
+ # Label modifié comme demandé
228
+ level = gr.Dropdown(["Débutant", "Intermédiaire", "Avancé", "Grand Maître"], value="Débutant", label="Difficulté Adversaire", interactive=True)
229
 
230
  # MAIN
231
  with gr.Row():
232
+ # GAUCHE (PLATEAU)
233
  with gr.Column(scale=2):
234
  board = Chessboard(elem_id="board", label="Zone de Combat", value=chess.STARTING_FEN, game_mode=True, interactive=True)
235
 
236
+ # DROITE (CONTROLES)
237
  with gr.Column(scale=1):
238
  btn_reset = gr.Button("🔄 RESTART SYSTEM", variant="secondary")
239
 
240
  gr.Markdown("### 📟 Terminal Sortie")
241
  coach_txt = gr.Textbox(label="Message", interactive=False, lines=3, elem_classes="feedback")
242
+
243
+ # AUDIO VISIBLE (Pour que l'autoplay fonctionne)
244
+ coach_audio = gr.Audio(label="Synthèse", autoplay=True, interactive=False, type="filepath", visible=True)
245
 
246
  gr.Markdown("### 📜 Log Tactique")
 
247
  history_state = gr.State([])
248
+ history_display = gr.Textbox(label="Historique Conseils", interactive=False, lines=5, max_lines=10, elem_classes="feedback")
 
249
 
250
  gr.Markdown("### 🎤 Input Vocal")
251
  mic = gr.Audio(sources=["microphone"], type="filepath", show_label=False)
252
  btn_ask = gr.Button("TRANSMETTRE QUESTION", variant="primary")
253
 
254
  # LOGIQUE
 
 
255
  board.move(
256
  fn=game_cycle,
257
  inputs=[board, level, history_state],
258
  outputs=[board, coach_txt, coach_audio, history_display, history_state]
259
  )
260
 
261
+ btn_reset.click(fn=reset_game, outputs=[board, coach_txt, coach_audio, history_display, history_state])
262
+ btn_ask.click(fn=ask_deepblue, inputs=[board, mic, history_state], outputs=[coach_txt, coach_audio, history_display, history_state])
263
+ mic.stop_recording(fn=ask_deepblue, inputs=[board, mic, history_state], outputs=[coach_txt, coach_audio, history_display, history_state])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
  if __name__ == "__main__":
266
  demo.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False, allowed_paths=["/tmp"])