Lukeetah commited on
Commit
22970af
·
verified ·
1 Parent(s): 1fd27e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -49
app.py CHANGED
@@ -20,7 +20,7 @@ except ImportError:
20
  pd = None
21
  # print("WARN: Pandas not found. History table will be basic HTML. Statistics like SD might be unavailable.")
22
 
23
- # --- Constants and Configuration (V8 HARD - Modificado v8.2 - User Request) ---
24
  APP_DIR = Path(__file__).parent if "__file__" in locals() else Path.cwd()
25
  ARCHIVO_RESULTADOS = APP_DIR / 'matrix_gradio_results_v8_hard.csv'
26
  MAX_DIFFICULTY_LEVEL = 5
@@ -80,7 +80,6 @@ INHIB_CONGRUENT_PROB_REDUCTION = 0.10
80
  INHIB_MIN_CONGRUENT_PROB = 0.20
81
  INHIB_CORRECT_KEY = 'c' # Key for "Correcto" (Congruent)
82
  INHIB_INCORRECT_KEY = 'i' # Key for "Incorrecto" (Incongruent)
83
- # Removed INHIB_TARGET_WORD, INHIB_TARGET_COLOR, NOGO stuff - no longer Go/NoGo
84
  INHIB_MIN_CRITICAL_PROPORTION = 0.05 # Now applies to *both* Congruent and Incongruent trials
85
 
86
  # Memory N-Back + Suppression (Modified v8.2 - Visibility handled in UI)
@@ -425,6 +424,7 @@ def generate_attention_sequence(params):
425
  ex = {'target': target, 'cue': cue, 'similar_distractor_key': params['similar_distractor_key']}
426
  return final_sequence, ex
427
 
 
428
  # --- Modified Inhibition Sequence Generator (v8.2) ---
429
  def generate_inhibition_sequence(params):
430
  n = params['trials']
@@ -577,8 +577,8 @@ def generate_flexibility_sequence(params):
577
  return final_sequence, ex
578
 
579
  sequence_generators = {
580
- "Atencion": generate_attention_sequence,
581
- "Inhibicion": generate_inhibition_sequence, # Uses modified generator
582
  "Memoria": generate_memory_sequence,
583
  "Flexibilidad": generate_flexibility_sequence,
584
  }
@@ -612,8 +612,7 @@ def leer_historial_df():
612
  try:
613
  proc_row = {'Alias': str(row.get('Alias', f'Fila_{i+1}_NA'))[:25],'Timestamp': str(row.get('Timestamp', 'NA'))[:15],'Level': int(float(row.get('Level', 0))),'AvgPrec': float(row.get('AvgPrec', 0.0))}
614
  for test in expected_test_cols: raw_val = row.get(test); \
615
- try: proc_row[test] = float(raw_val)
616
- if raw_val is not None else 0.0; \
617
  except (ValueError, TypeError): proc_row[test] = 0.0
618
  processed_rows.append(proc_row)
619
  except (ValueError, TypeError, KeyError): continue
@@ -1143,7 +1142,7 @@ def generate_sequence_for_test(test_name, params):
1143
 
1144
 
1145
  # --- Gradio UI Definition (Modified v8.2 - New Inhib Buttons) ---
1146
- with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes.Monochrome(font=[gr.themes.GoogleFont("Courier Prime"), "monospace"]), css=css) as demo:
1147
 
1148
  # Initial state dictionary (Unchanged)
1149
  initial_state = {
@@ -1161,7 +1160,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1161
 
1162
  # --- UI Blocks (Welcome, Alias, Menu, Instructions - Unchanged) ---
1163
  with gr.Column(visible=True, elem_classes="main-content-box", elem_id="welcome-block") as welcome_block:
1164
- gr.Markdown("""## Matrix Cognitiva AR v8.2 HARD+ 🇦🇷
1165
  <div class='warning-text'><p><strong>⚠️ ADVERTENCIA ⚠️</strong></p><p>Este NO es un test médico. Es un <strong>DESAFÍO COGNITIVO EXTREMO</strong>.</p><p>Diseñado para explorar límites, no para diagnóstico. Resultados TEMÁTICOS.</p><p><strong>ALTA DIFICULTAD:</strong> Niveles avanzados pueden ser frustrantes.</p><p>Si tienes dudas sobre tu cognición, <strong>CONSULTA A UN PROFESIONAL</strong>.</p><p>Al continuar, <strong>ACEPTAS</strong> estas condiciones.</p></div>
1166
  <p class='info-text'>Rendimiento depende del dispositivo y concentración. Botones persistentes en Mem/Flex. Inhibición es Juicio C/I.</p>""", elem_classes="welcome-text") # Added note about changes
1167
  accept_button = gr.Button("Entendido, Acepto el Desafío", elem_classes="btn-matrix-accept", scale=1)
@@ -1223,7 +1222,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1223
  results_title=gr.Markdown("### Reporte de Simulación", elem_classes="matrix-title")
1224
  results_summary=gr.HTML("...", elem_id="results-summary")
1225
  results_level_msg=gr.HTML("...", elem_id="results-level")
1226
- results_analysis_title=gr.Markdown("--- Análisis Táctico Detallado (V8.2) ---", elem_classes="matrix-subtitle", visible=True) # Updated version
1227
  results_analysis=gr.HTML("<p>Calculando...</p>", elem_id="results-analysis")
1228
  results_info=gr.Markdown("<p class='info-text'>Registro guardado (si alias definido). Desafío extremo completado.</p>", elem_id="results-info")
1229
  results_back_button=gr.Button("Volver al Terminal Principal", elem_classes="btn-matrix")
@@ -1238,16 +1237,15 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1238
  all_blocks = [welcome_block, alias_block, menu_block, instructions_block, test_block, results_block, history_block]
1239
  # Now 11 response buttons
1240
  all_response_buttons = [attn_target_btn, attn_distractor_btn, inhib_correct_btn, inhib_incorrect_btn, mem_s_btn, mem_n_btn, fx_p_btn, fx_i_btn, fx_a_btn, fx_b_btn, fx_int_btn]
1241
- # UI elements updated during a trial (+2 for new inhib buttons, -1 for old inhib button = +1 -> 11 buttons. 4 other elements + overlay = 16)
1242
- test_trial_ui_updates = [stimulus_display, feedback_display, progress_indicator, timer_display] + all_response_buttons + [distraction_overlay] # Total 1 + 4 + 11 + 1 = 17
1243
  results_display_outputs = [results_title, results_summary, results_level_msg, results_analysis_title, results_analysis] # 5 elements
1244
  history_display_outputs = [hist_df, hist_html] # 2 elements
1245
- # Components within the test block area itself
1246
- test_block_ui_components = [test_title, progress_indicator, timer_display, stimulus_display, feedback_display, *all_response_buttons, distraction_overlay] # Total 1 + 4 + 11 + 1 = 17
1247
 
1248
- # --- Backend Functions (Callbacks) ---
1249
 
1250
- # Helper functions (update_menu_info, confirm_alias_wrapper, etc.) - Largely unchanged, ensure output counts match definitions
1251
  def update_menu_info(state_dict):
1252
  alias = state_dict.get('alias', '???'); level = state_dict.get('level', 1)
1253
  return gr.update(value=f"Agente: <strong>{alias}</strong> | Nivel de Acceso: <strong>{level}</strong>")
@@ -1257,17 +1255,15 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1257
  if alias and len(alias) >= 2: next_state["alias"] = alias; next_stage = "menu"; gr.Info(f"Alias '{alias}' confirmado."); feedback_msg = ""
1258
  else: feedback_msg = "<p style='color: #FF8888;'>Alias inválido. Mínimo 2 caracteres.</p>"; gr.Warning("Alias inválido."); next_stage = "set_alias"
1259
  next_state["stage"] = next_stage; visibility_updates = get_stage_visibility(next_stage); menu_info_update = update_menu_info(next_state); alias_feedback_update = gr.update(value=feedback_msg)
1260
- # Output: state + blocks(7) + menu_info + alias_feedback = 10 outputs
1261
  return [next_state] + visibility_updates + [menu_info_update, alias_feedback_update]
1262
 
1263
  def start_simulation_wrapper(state_dict):
1264
  current_state = deepcopy(state_dict)
1265
  if not current_state.get("alias"):
1266
  gr.Warning("Se requiere alias para iniciar."); current_state["stage"] = "set_alias"
1267
- # Need outputs for state + blocks(7) + menu_info + dummy instr(2) = 11 outputs
1268
  dummy_instr = [gr.update()] * 2; return [current_state] + get_stage_visibility("set_alias") + [update_menu_info(current_state)] + dummy_instr
1269
  current_level = current_state.get("level", 1); test_order = random.sample(AVAILABLE_TESTS, len(AVAILABLE_TESTS)); current_state["current_test_order"] = test_order
1270
- # print(f"\n--- Iniciando Simulación Nivel {current_level} (V8.2 HARD+) ---"); print(f"Orden de Pruebas: {', '.join(test_order)}")
1271
  first_test_index = 0; first_test_name = test_order[first_test_index]
1272
  try:
1273
  params = get_difficulty_params(first_test_name, current_level); instruction_text = get_instructions_text(first_test_name, params)
@@ -1284,20 +1280,17 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1284
  "flex_active_interference_key": flex_int_key, "_level_before_results": current_level })
1285
  visibility_updates = get_stage_visibility("instructions"); menu_info_update = update_menu_info(current_state)
1286
  instr_title_update = gr.update(value=f"#### {TEST_ICONS.get(first_test_name, '')} Briefing: {first_test_name} [Nivel {current_level}]"); instr_text_update = gr.update(value=instruction_text)
1287
- # Output: state + blocks(7) + menu_info + instr_title + instr_text = 11 outputs
1288
  return [current_state] + visibility_updates + [menu_info_update, instr_title_update, instr_text_update]
1289
 
1290
  def start_test_wrapper(state_dict):
1291
  current_state = deepcopy(state_dict); current_test = current_state.get("current_test"); params = current_state.get("test_params", {}); level = current_state.get("level", 1)
1292
  if not current_test or not params:
1293
  gr.Error("Estado inválido: Falta info de prueba."); current_state["stage"] = "menu"
1294
- # Need full output list (36 components: state + 7 blocks + 1 menu + 2 instr + 17 test_ui + 5 results + 2 history = 35? Let's recalculate)
1295
- # state + blocks(7) + menu(1) + instr(2) + test_ui(17) + results(5) + history(2) = 35 total components
1296
  visibility_updates = get_stage_visibility("menu"); menu_info_update = update_menu_info(current_state); dummy_instr = [gr.update()] * 2; dummy_test_ui = [gr.update()] * len(test_block_ui_components); dummy_results = [gr.update()] * len(results_display_outputs); dummy_history = [gr.update()] * len(history_display_outputs)
1297
  return [current_state] + visibility_updates + [menu_info_update] + dummy_instr + dummy_test_ui + dummy_results + dummy_history
1298
 
1299
  try:
1300
- # print(f"Generando secuencia V8.2 para: {current_test} Nivel {level}...")
1301
  sequence, expected_info = generate_sequence_for_test(current_test, params)
1302
  if 'trials' in params and params['trials'] != len(sequence): params['trials'] = len(sequence)
1303
  current_state['test_params'] = params
@@ -1318,8 +1311,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1318
  button_updates = [gr.update(visible=False)] * len(all_response_buttons) # 11 buttons
1319
  distraction_update = gr.update(value="<div id='distraction-overlay'></div>")
1320
  results_dummies = [gr.update()] * len(results_display_outputs); history_dummies = [gr.update()] * len(history_display_outputs)
1321
- # print(f"Iniciando prueba V8.2: {current_test}, {len(sequence)} trials.")
1322
- # Combine updates: state + blocks(7) + menu(1) + instr(2) + test_ui(17) + results(5) + history(2) = 35 total
1323
  return ([current_state] + visibility_updates + [menu_info_update] + instr_updates +
1324
  [test_title_update, progress_update, timer_update, stimulus_update, feedback_update] + button_updates + [distraction_update] +
1325
  results_dummies + history_dummies)
@@ -1334,7 +1326,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1334
  distraction_prob = params.get('distraction_prob', 0)
1335
  flex_int_info = params.get('interference', {}) if current_test == "Flexibilidad" else {}; flex_key_switch_point = state.get("test_expected_response", {}).get('interference_key_switch_point', -1) if current_test == "Flexibilidad" else -1
1336
  flex_base_key = flex_int_info.get('base_key', FLEX_INTERFERENCE_BASE_KEY); flex_alt_key = flex_int_info.get('alt_key', FLEX_INTERFERENCE_ALT_KEY); key_switched_flag = False
1337
- # print(f"--- Iniciando Flujo de Trials V8.2: {current_test} ({test_duration} trials) ---")
1338
  while state["test_trial_index"] < test_duration:
1339
  current_trial_idx = state["test_trial_index"]
1340
  # 1. ITI
@@ -1375,11 +1367,11 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1375
  # 9. Next Trial
1376
  state["test_trial_index"] += 1
1377
  # --- End Loop ---
1378
- # print(f"--- Flujo de Trials Completado V8.2: {current_test} ---")
1379
  state["awaiting_input"] = False
1380
  yield [state, gr.update(value="<p class='stimulus-display'>&nbsp;</p>"), gr.HTML("&nbsp;"), gr.update(), gr.update(value="")] + [gr.update(visible=False)]*len(all_response_buttons) + [gr.update(value="<div id='distraction-overlay'></div>")] # Final clear
1381
  except Exception as e:
1382
- print(f"ERROR FATAL durante run_trial_flow V8.2 para {state.get('current_test', '??')}: {e}"); traceback.print_exc(); gr.Error(f"Error durante la prueba {state.get('current_test', '??')}. Volviendo al menú.")
1383
  state["stage"] = "menu"; state["awaiting_input"] = False
1384
  yield [state, gr.update(value="<p class='stimulus-display' style='color:red;'>ERROR</p>"), gr.HTML("<p style='color:red;'>ERROR</p>"), gr.update(), gr.update()] + [gr.update(visible=False)]*len(all_response_buttons) + [gr.update(value="<div id='distraction-overlay'></div>")] # Yield error state
1385
 
@@ -1404,12 +1396,12 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1404
  current_test = state.get("current_test"); trial_results = state.get("current_trial_results", []); params = state.get("test_params", {}); expected_response_info = state.get("test_expected_response", {}); sequence = state.get("test_sequence", [])
1405
  current_scores = state.get("current_scores", {}); test_order = state.get("current_test_order", []); current_test_index = state.get("current_test_index", -1); current_level = state.get("level", 1); alias = state.get("alias"); level_at_start_of_round = state.get("_level_before_results", current_level)
1406
  if not current_test or current_test_index < 0 or not test_order:
1407
- print(f"WARN: Estado inválido al finalizar prueba V8.2. Test={current_test}, Index={current_test_index}. Volviendo al menú."); state["stage"] = "menu"; state.update({k: deepcopy(initial_state[k]) for k in ["current_test", "current_test_index", "test_params", "test_sequence", "awaiting_input", "round_results", "current_trial_results"]})
1408
  visibility_updates = get_stage_visibility("menu"); menu_info_update = update_menu_info(state); dummy_instr = [gr.update()] * 2; dummy_test_ui = [gr.update()] * len(test_block_ui_components); dummy_results = [gr.update()] * len(results_display_outputs); dummy_history = [gr.update()] * len(history_display_outputs)
1409
  return [state] + visibility_updates + [menu_info_update] + dummy_instr + dummy_test_ui + dummy_results + dummy_history
1410
- # print(f"Finalizando prueba V8.2: {current_test}")
1411
  try: score_details = calculate_detailed_scores(current_test, trial_results, params, expected_response_info, sequence); precision = score_details['precision']; analysis_html = score_details['analysis']
1412
- except Exception as e: print(f"ERROR calculando puntajes V8.2 para {current_test}: {e}"); traceback.print_exc(); precision = 0.0; analysis_html = "<p style='color:red;'>Error al generar análisis detallado.</p>"
1413
  current_scores[current_test] = precision
1414
  if "round_results" not in state or state["round_results"] is None: state["round_results"] = {"detailed_analysis": {}}
1415
  if "detailed_analysis" not in state["round_results"]: state["round_results"]["detailed_analysis"] = {}
@@ -1417,10 +1409,10 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1417
  next_test_index = current_test_index + 1
1418
  if next_test_index < len(test_order):
1419
  # --- Transition to Next Test ---
1420
- next_test_name = test_order[next_test_index]; # print(f"Transición a la siguiente prueba V8.2: {next_test_name}");
1421
  next_stage = "instructions"
1422
  try: next_params = get_difficulty_params(next_test_name, current_level); instruction_text = get_instructions_text(next_test_name, next_params); flex_int_key = next_params.get('interference',{}).get('base_key', FLEX_INTERFERENCE_BASE_KEY) if next_test_name == "Flexibilidad" else "?"
1423
- except Exception as e: gr.Error(f"Error Crítico preparando siguiente prueba V8.2 {next_test_name}: {e}"); traceback.print_exc(); state["stage"] = "menu"; visibility_updates = get_stage_visibility("menu"); menu_info_update = update_menu_info(state); dummy_instr = [gr.update()] * 2; dummy_test_ui = [gr.update()] * len(test_block_ui_components); dummy_results = [gr.update()] * len(results_display_outputs); dummy_history = [gr.update()] * len(history_display_outputs); return [state] + visibility_updates + [menu_info_update] + dummy_instr + dummy_test_ui + dummy_results + dummy_history
1424
  initial_flex_rule_for_next_test = random.randint(0, 1) if next_test_name == "Flexibilidad" else 0
1425
  state.update({
1426
  "stage": next_stage, "current_test": next_test_name, "current_test_index": next_test_index, "test_params": next_params, "test_sequence": [], "test_expected_response": {}, "test_trial_index": 0,
@@ -1428,11 +1420,10 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1428
  "initial_flex_rule": initial_flex_rule_for_next_test, "test_current_rule_idx": initial_flex_rule_for_next_test, "test_current_rule_idx_snapshot": initial_flex_rule_for_next_test, "flex_active_interference_key": flex_int_key, })
1429
  visibility_updates = get_stage_visibility(next_stage); menu_info_update = update_menu_info(state); instr_title_update = gr.update(value=f"#### {TEST_ICONS.get(next_test_name, '')} Briefing: {next_test_name} [Nivel {current_level}]"); instr_text_update = gr.update(value=instruction_text)
1430
  test_block_dummies = [gr.update()] * len(test_block_ui_components); results_dummies = [gr.update()] * len(results_display_outputs); history_dummies = [gr.update()] * len(history_display_outputs)
1431
- # Return updates (35 components: state + 7 blocks + 1 menu + 2 instr + 17 test_ui + 5 results + 2 history)
1432
  return ([state] + visibility_updates + [menu_info_update] + [instr_title_update, instr_text_update] + test_block_dummies + results_dummies + history_dummies)
1433
  else:
1434
  # --- All Tests Completed: Show Results ---
1435
- # print("Simulación V8.2 completada. Mostrando resultados.")
1436
  next_stage = "results"; avg_precision = sum(current_scores.values()) / len(current_scores) if current_scores else 0.0; can_advance = avg_precision >= ADVANCE_THRESHOLD_PERCENT; new_level = level_at_start_of_round; level_msg = ""
1437
  if can_advance and level_at_start_of_round < MAX_DIFFICULTY_LEVEL: new_level += 1; level_msg = f"<h5><strong>¡Rendimiento Excepcional!</strong> Acceso Nivel {new_level} Otorgado.</h5>"; gr.Info(f"¡Subiste al Nivel {new_level}!")
1438
  elif can_advance: level_msg = f"<h5><strong>¡Maestría Total!</strong> Nivel Máximo ({level_at_start_of_round}) Dominado.</h5>"; gr.Info(f"¡Nivel Máximo {level_at_start_of_round} mantenido con éxito!"); new_level = level_at_start_of_round
@@ -1444,11 +1435,10 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1444
  for test in test_order: analysis_part = state["round_results"]["detailed_analysis"].get(test, f"<p>Análisis no disponible para {test}.</p>"); all_analysis_parts.append(f"<h5 class='matrix-subtitle'>{TEST_ICONS.get(test,'')} Análisis: {test}</h5>{analysis_part}")
1445
  full_analysis_html = "<hr class='matrix-hr'>".join(all_analysis_parts) if all_analysis_parts else "<p>No hay análisis detallados.</p>"
1446
  final_results_data = {"scores": current_scores, "avg_precision": avg_precision, "analysis_text": full_analysis_html, "level_message": level_msg, "summary_html": summary_html}; state["round_results"] = final_results_data
1447
- # if alias: print(f"Guardando resultado V8.2 para {alias} (Nivel {level_at_start_of_round})..."); save_success = guardar_resultado(alias, level_at_start_of_round, current_scores, test_order); # print("Resultado guardado." if save_success else "¡Fallo al guardar resultado!")
1448
  # else: print("INFO: No se guarda resultado (sin alias).")
1449
  state.update({"stage": next_stage, "level": new_level, "current_test": None, "current_test_index": -1, "test_params": {}, "test_sequence": [], "test_expected_response": {}, "test_trial_index": 0, "current_stimulus_index": -1, "last_processed_index": -1, "test_stimulus": None, "awaiting_input": False, "current_trial_results": [], "test_last_stimulus": '', "test_feedback": "&nbsp;", "_distraction_active": False})
1450
- visibility_updates = get_stage_visibility(next_stage); menu_info_update = update_menu_info(state); instr_dummies = [gr.update()] * 2; test_ui_dummies = [gr.update()] * len(test_block_ui_components); results_title_update = gr.update(value=f"### Reporte V8.2: {alias or 'Agente'} [Nivel {level_at_start_of_round}]"); results_summary_update = gr.HTML(summary_html); results_level_update = gr.HTML(level_msg); results_analysis_title_update = gr.update(visible=True); results_analysis_update = gr.HTML(full_analysis_html); history_dummies = [gr.update()] * len(history_display_outputs)
1451
- # Return updates (35 components)
1452
  return ([state] + visibility_updates + [menu_info_update] + instr_dummies + test_ui_dummies + [results_title_update, results_summary_update, results_level_update, results_analysis_title_update, results_analysis_update] + history_dummies)
1453
 
1454
  def view_history_wrapper(state_dict):
@@ -1467,7 +1457,6 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1467
  if html_update.value == "<p>Cargando historial...</p>": html_update = gr.update(value="<p style='color:red;'>No se pudo cargar el historial.</p>", visible=True)
1468
  df_update = gr.update(visible=False)
1469
  instr_dummies = [gr.update()] * 2; test_ui_dummies = [gr.update()] * len(test_block_ui_components); results_dummies = [gr.update()] * len(results_display_outputs)
1470
- # Return updates (35 components)
1471
  return ([state] + visibility_updates + [menu_info_update] + instr_dummies + test_ui_dummies + results_dummies + [df_update, html_update])
1472
 
1473
  def reset_level_wrapper(state_dict):
@@ -1491,7 +1480,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1491
  if next_stage != "set_alias": output_updates[alias_feedback] = gr.update(value="")
1492
  return output_updates # Return dict for flexible output mapping
1493
 
1494
- # --- Define Output Lists for Clarity (v8.2 - Adjusted counts) ---
1495
  # For simple stage changes (back buttons, accept) - Need state + 7 blocks + agent_info + feedback + alias_feedback = 11 outputs
1496
  base_outputs_change_stage = [ game_state, *all_blocks, agent_info, feedback_display, alias_feedback ]
1497
  # For confirming alias - state + 7 blocks + agent_info + alias_feedback = 10 outputs
@@ -1501,15 +1490,17 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1501
  # For starting a test/finishing a test/viewing history (needs all components updated) - 35 components
1502
  # state + blocks(7) + menu(1) + instr(2) + test_ui(17) + results(5) + history(2) = 35 total
1503
  full_ui_update_outputs = [ game_state, *all_blocks, agent_info, instructions_title, instructions_text,
1504
- *test_block_ui_components, # 17 components
1505
  *results_display_outputs, # 5 components
1506
  *history_display_outputs ] # 2 components
1507
- # For yields during the trial flow (state + test trial UI elements) - 1 + 16 = 17 outputs
1508
- trial_flow_yield_outputs = [game_state] + test_trial_ui_updates
 
1509
  # For resetting level - state + agent_info = 2 outputs
1510
  reset_outputs = [game_state, agent_info]
1511
 
1512
- # --- Event Handlers (Updated v8.2 - Using correct output lists) ---
 
1513
 
1514
  # Navigation / Setup Buttons
1515
  accept_button.click(lambda s: change_stage_wrapper(s, "set_alias" if s.get("alias") is None else "menu"), [game_state], base_outputs_change_stage, show_progress="hidden")
@@ -1524,12 +1515,12 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1524
  start_test_button.click(
1525
  fn=start_test_wrapper, inputs=[game_state], outputs=full_ui_update_outputs, show_progress="minimal" # Needs full update list
1526
  ).then(
1527
- fn=run_trial_flow, inputs=[game_state], outputs=trial_flow_yield_outputs, show_progress="hidden"
1528
  ).then(
1529
  fn=finish_current_test_wrapper, inputs=[game_state], outputs=full_ui_update_outputs, show_progress="minimal" # Needs full update list
1530
  )
1531
 
1532
- # --- Response Button Click Handlers (Updated v8.2 - New Inhib buttons) ---
1533
  button_key_map = {
1534
  # Index 0, 1: Attention
1535
  attn_target_btn: ATTN_TARGET.lower(),
@@ -1551,7 +1542,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1551
  }
1552
 
1553
  for btn, key_or_placeholder in button_key_map.items():
1554
- btn.click(fn=process_click_wrapper, inputs=[game_state, gr.State(value=key_or_placeholder)], outputs=trial_flow_yield_outputs, show_progress="hidden")
1555
 
1556
  # Back buttons from Results and History
1557
  results_back_button.click(lambda s: change_stage_wrapper(s, "menu"), [game_state], base_outputs_change_stage, show_progress="hidden")
@@ -1560,7 +1551,7 @@ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+", theme=gr.themes
1560
 
1561
  # --- Launch App ---
1562
  if __name__ == "__main__":
1563
- # print("Iniciando Servidor Gradio MC AR v8.2 HARD+...")
1564
  try: # Ensure results file exists with header
1565
  with csv_lock:
1566
  fieldnames = ['Alias','Timestamp','Level','AvgPrec'] + AVAILABLE_TESTS; file_exists = os.path.isfile(ARCHIVO_RESULTADOS)
@@ -1568,14 +1559,14 @@ if __name__ == "__main__":
1568
  if needs_header:
1569
  try:
1570
  with open(ARCHIVO_RESULTADOS, 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=fieldnames); writer.writeheader()
1571
- # print(f"Archivo de resultados V8.2 HARD+ creado: {ARCHIVO_RESULTADOS}")
1572
  except IOError as e: print(f"ERROR CRÍTICO: No se pudo crear archivo resultados: {e}"); exit(1)
1573
  except Exception as e: print(f"ERROR CRÍTICO: Verificando archivo resultados: {e}"); exit(1)
1574
 
1575
  # print("Configurando Gradio Queue y Launch...")
1576
  demo.queue()
1577
  try:
1578
- # print("--- Servidor Listo para Conexiones (V8.2 HARD+) ---")
1579
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
1580
  except Exception as e: print(f"ERROR FATAL durante demo.launch(): {e}"); traceback.print_exc()
1581
  finally: print("--- Servidor Gradio Terminado o Fallo en Launch ---")
 
20
  pd = None
21
  # print("WARN: Pandas not found. History table will be basic HTML. Statistics like SD might be unavailable.")
22
 
23
+ # --- Constants and Configuration (V8 HARD - Modificado v8.2 - User Request + Syntax Fix) ---
24
  APP_DIR = Path(__file__).parent if "__file__" in locals() else Path.cwd()
25
  ARCHIVO_RESULTADOS = APP_DIR / 'matrix_gradio_results_v8_hard.csv'
26
  MAX_DIFFICULTY_LEVEL = 5
 
80
  INHIB_MIN_CONGRUENT_PROB = 0.20
81
  INHIB_CORRECT_KEY = 'c' # Key for "Correcto" (Congruent)
82
  INHIB_INCORRECT_KEY = 'i' # Key for "Incorrecto" (Incongruent)
 
83
  INHIB_MIN_CRITICAL_PROPORTION = 0.05 # Now applies to *both* Congruent and Incongruent trials
84
 
85
  # Memory N-Back + Suppression (Modified v8.2 - Visibility handled in UI)
 
424
  ex = {'target': target, 'cue': cue, 'similar_distractor_key': params['similar_distractor_key']}
425
  return final_sequence, ex
426
 
427
+
428
  # --- Modified Inhibition Sequence Generator (v8.2) ---
429
  def generate_inhibition_sequence(params):
430
  n = params['trials']
 
577
  return final_sequence, ex
578
 
579
  sequence_generators = {
580
+ "Atencion": generate_attention_sequence, # Uses modified generator with FIX
581
+ "Inhibicion": generate_inhibition_sequence,
582
  "Memoria": generate_memory_sequence,
583
  "Flexibilidad": generate_flexibility_sequence,
584
  }
 
612
  try:
613
  proc_row = {'Alias': str(row.get('Alias', f'Fila_{i+1}_NA'))[:25],'Timestamp': str(row.get('Timestamp', 'NA'))[:15],'Level': int(float(row.get('Level', 0))),'AvgPrec': float(row.get('AvgPrec', 0.0))}
614
  for test in expected_test_cols: raw_val = row.get(test); \
615
+ try: proc_row[test] = float(raw_val) if raw_val is not None else 0.0; \
 
616
  except (ValueError, TypeError): proc_row[test] = 0.0
617
  processed_rows.append(proc_row)
618
  except (ValueError, TypeError, KeyError): continue
 
1142
 
1143
 
1144
  # --- Gradio UI Definition (Modified v8.2 - New Inhib Buttons) ---
1145
+ with gr.Blocks(title="Matrix Cognitive Challenge AR v8.2 HARD+ (Fix)", theme=gr.themes.Monochrome(font=[gr.themes.GoogleFont("Courier Prime"), "monospace"]), css=css) as demo:
1146
 
1147
  # Initial state dictionary (Unchanged)
1148
  initial_state = {
 
1160
 
1161
  # --- UI Blocks (Welcome, Alias, Menu, Instructions - Unchanged) ---
1162
  with gr.Column(visible=True, elem_classes="main-content-box", elem_id="welcome-block") as welcome_block:
1163
+ gr.Markdown("""## Matrix Cognitiva AR v8.2 HARD+ (Fix) 🇦🇷
1164
  <div class='warning-text'><p><strong>⚠️ ADVERTENCIA ⚠️</strong></p><p>Este NO es un test médico. Es un <strong>DESAFÍO COGNITIVO EXTREMO</strong>.</p><p>Diseñado para explorar límites, no para diagnóstico. Resultados TEMÁTICOS.</p><p><strong>ALTA DIFICULTAD:</strong> Niveles avanzados pueden ser frustrantes.</p><p>Si tienes dudas sobre tu cognición, <strong>CONSULTA A UN PROFESIONAL</strong>.</p><p>Al continuar, <strong>ACEPTAS</strong> estas condiciones.</p></div>
1165
  <p class='info-text'>Rendimiento depende del dispositivo y concentración. Botones persistentes en Mem/Flex. Inhibición es Juicio C/I.</p>""", elem_classes="welcome-text") # Added note about changes
1166
  accept_button = gr.Button("Entendido, Acepto el Desafío", elem_classes="btn-matrix-accept", scale=1)
 
1222
  results_title=gr.Markdown("### Reporte de Simulación", elem_classes="matrix-title")
1223
  results_summary=gr.HTML("...", elem_id="results-summary")
1224
  results_level_msg=gr.HTML("...", elem_id="results-level")
1225
+ results_analysis_title=gr.Markdown("--- Análisis Táctico Detallado (V8.2 Fix) ---", elem_classes="matrix-subtitle", visible=True) # Updated version
1226
  results_analysis=gr.HTML("<p>Calculando...</p>", elem_id="results-analysis")
1227
  results_info=gr.Markdown("<p class='info-text'>Registro guardado (si alias definido). Desafío extremo completado.</p>", elem_id="results-info")
1228
  results_back_button=gr.Button("Volver al Terminal Principal", elem_classes="btn-matrix")
 
1237
  all_blocks = [welcome_block, alias_block, menu_block, instructions_block, test_block, results_block, history_block]
1238
  # Now 11 response buttons
1239
  all_response_buttons = [attn_target_btn, attn_distractor_btn, inhib_correct_btn, inhib_incorrect_btn, mem_s_btn, mem_n_btn, fx_p_btn, fx_i_btn, fx_a_btn, fx_b_btn, fx_int_btn]
1240
+ # UI elements updated during a trial (1 + 4 + 11 + 1 = 17)
1241
+ test_trial_ui_updates = [stimulus_display, feedback_display, progress_indicator, timer_display] + all_response_buttons + [distraction_overlay]
1242
  results_display_outputs = [results_title, results_summary, results_level_msg, results_analysis_title, results_analysis] # 5 elements
1243
  history_display_outputs = [hist_df, hist_html] # 2 elements
1244
+ # Components within the test block area itself (1 + 4 + 11 + 1 = 17)
1245
+ test_block_ui_components = [test_title, progress_indicator, timer_display, stimulus_display, feedback_display, *all_response_buttons, distraction_overlay]
1246
 
1247
+ # --- Backend Functions (Callbacks - Unchanged Function Definitions, only output lists adjusted) ---
1248
 
 
1249
  def update_menu_info(state_dict):
1250
  alias = state_dict.get('alias', '???'); level = state_dict.get('level', 1)
1251
  return gr.update(value=f"Agente: <strong>{alias}</strong> | Nivel de Acceso: <strong>{level}</strong>")
 
1255
  if alias and len(alias) >= 2: next_state["alias"] = alias; next_stage = "menu"; gr.Info(f"Alias '{alias}' confirmado."); feedback_msg = ""
1256
  else: feedback_msg = "<p style='color: #FF8888;'>Alias inválido. Mínimo 2 caracteres.</p>"; gr.Warning("Alias inválido."); next_stage = "set_alias"
1257
  next_state["stage"] = next_stage; visibility_updates = get_stage_visibility(next_stage); menu_info_update = update_menu_info(next_state); alias_feedback_update = gr.update(value=feedback_msg)
 
1258
  return [next_state] + visibility_updates + [menu_info_update, alias_feedback_update]
1259
 
1260
  def start_simulation_wrapper(state_dict):
1261
  current_state = deepcopy(state_dict)
1262
  if not current_state.get("alias"):
1263
  gr.Warning("Se requiere alias para iniciar."); current_state["stage"] = "set_alias"
 
1264
  dummy_instr = [gr.update()] * 2; return [current_state] + get_stage_visibility("set_alias") + [update_menu_info(current_state)] + dummy_instr
1265
  current_level = current_state.get("level", 1); test_order = random.sample(AVAILABLE_TESTS, len(AVAILABLE_TESTS)); current_state["current_test_order"] = test_order
1266
+ # print(f"\n--- Iniciando Simulación Nivel {current_level} (V8.2 HARD+ Fix) ---"); print(f"Orden de Pruebas: {', '.join(test_order)}")
1267
  first_test_index = 0; first_test_name = test_order[first_test_index]
1268
  try:
1269
  params = get_difficulty_params(first_test_name, current_level); instruction_text = get_instructions_text(first_test_name, params)
 
1280
  "flex_active_interference_key": flex_int_key, "_level_before_results": current_level })
1281
  visibility_updates = get_stage_visibility("instructions"); menu_info_update = update_menu_info(current_state)
1282
  instr_title_update = gr.update(value=f"#### {TEST_ICONS.get(first_test_name, '')} Briefing: {first_test_name} [Nivel {current_level}]"); instr_text_update = gr.update(value=instruction_text)
 
1283
  return [current_state] + visibility_updates + [menu_info_update, instr_title_update, instr_text_update]
1284
 
1285
  def start_test_wrapper(state_dict):
1286
  current_state = deepcopy(state_dict); current_test = current_state.get("current_test"); params = current_state.get("test_params", {}); level = current_state.get("level", 1)
1287
  if not current_test or not params:
1288
  gr.Error("Estado inválido: Falta info de prueba."); current_state["stage"] = "menu"
 
 
1289
  visibility_updates = get_stage_visibility("menu"); menu_info_update = update_menu_info(current_state); dummy_instr = [gr.update()] * 2; dummy_test_ui = [gr.update()] * len(test_block_ui_components); dummy_results = [gr.update()] * len(results_display_outputs); dummy_history = [gr.update()] * len(history_display_outputs)
1290
  return [current_state] + visibility_updates + [menu_info_update] + dummy_instr + dummy_test_ui + dummy_results + dummy_history
1291
 
1292
  try:
1293
+ # print(f"Generando secuencia V8.2 Fix para: {current_test} Nivel {level}...")
1294
  sequence, expected_info = generate_sequence_for_test(current_test, params)
1295
  if 'trials' in params and params['trials'] != len(sequence): params['trials'] = len(sequence)
1296
  current_state['test_params'] = params
 
1311
  button_updates = [gr.update(visible=False)] * len(all_response_buttons) # 11 buttons
1312
  distraction_update = gr.update(value="<div id='distraction-overlay'></div>")
1313
  results_dummies = [gr.update()] * len(results_display_outputs); history_dummies = [gr.update()] * len(history_display_outputs)
1314
+ # print(f"Iniciando prueba V8.2 Fix: {current_test}, {len(sequence)} trials.")
 
1315
  return ([current_state] + visibility_updates + [menu_info_update] + instr_updates +
1316
  [test_title_update, progress_update, timer_update, stimulus_update, feedback_update] + button_updates + [distraction_update] +
1317
  results_dummies + history_dummies)
 
1326
  distraction_prob = params.get('distraction_prob', 0)
1327
  flex_int_info = params.get('interference', {}) if current_test == "Flexibilidad" else {}; flex_key_switch_point = state.get("test_expected_response", {}).get('interference_key_switch_point', -1) if current_test == "Flexibilidad" else -1
1328
  flex_base_key = flex_int_info.get('base_key', FLEX_INTERFERENCE_BASE_KEY); flex_alt_key = flex_int_info.get('alt_key', FLEX_INTERFERENCE_ALT_KEY); key_switched_flag = False
1329
+ # print(f"--- Iniciando Flujo de Trials V8.2 Fix: {current_test} ({test_duration} trials) ---")
1330
  while state["test_trial_index"] < test_duration:
1331
  current_trial_idx = state["test_trial_index"]
1332
  # 1. ITI
 
1367
  # 9. Next Trial
1368
  state["test_trial_index"] += 1
1369
  # --- End Loop ---
1370
+ # print(f"--- Flujo de Trials Completado V8.2 Fix: {current_test} ---")
1371
  state["awaiting_input"] = False
1372
  yield [state, gr.update(value="<p class='stimulus-display'>&nbsp;</p>"), gr.HTML("&nbsp;"), gr.update(), gr.update(value="")] + [gr.update(visible=False)]*len(all_response_buttons) + [gr.update(value="<div id='distraction-overlay'></div>")] # Final clear
1373
  except Exception as e:
1374
+ print(f"ERROR FATAL durante run_trial_flow V8.2 Fix para {state.get('current_test', '??')}: {e}"); traceback.print_exc(); gr.Error(f"Error durante la prueba {state.get('current_test', '??')}. Volviendo al menú.")
1375
  state["stage"] = "menu"; state["awaiting_input"] = False
1376
  yield [state, gr.update(value="<p class='stimulus-display' style='color:red;'>ERROR</p>"), gr.HTML("<p style='color:red;'>ERROR</p>"), gr.update(), gr.update()] + [gr.update(visible=False)]*len(all_response_buttons) + [gr.update(value="<div id='distraction-overlay'></div>")] # Yield error state
1377
 
 
1396
  current_test = state.get("current_test"); trial_results = state.get("current_trial_results", []); params = state.get("test_params", {}); expected_response_info = state.get("test_expected_response", {}); sequence = state.get("test_sequence", [])
1397
  current_scores = state.get("current_scores", {}); test_order = state.get("current_test_order", []); current_test_index = state.get("current_test_index", -1); current_level = state.get("level", 1); alias = state.get("alias"); level_at_start_of_round = state.get("_level_before_results", current_level)
1398
  if not current_test or current_test_index < 0 or not test_order:
1399
+ print(f"WARN: Estado inválido al finalizar prueba V8.2 Fix. Test={current_test}, Index={current_test_index}. Volviendo al menú."); state["stage"] = "menu"; state.update({k: deepcopy(initial_state[k]) for k in ["current_test", "current_test_index", "test_params", "test_sequence", "awaiting_input", "round_results", "current_trial_results"]})
1400
  visibility_updates = get_stage_visibility("menu"); menu_info_update = update_menu_info(state); dummy_instr = [gr.update()] * 2; dummy_test_ui = [gr.update()] * len(test_block_ui_components); dummy_results = [gr.update()] * len(results_display_outputs); dummy_history = [gr.update()] * len(history_display_outputs)
1401
  return [state] + visibility_updates + [menu_info_update] + dummy_instr + dummy_test_ui + dummy_results + dummy_history
1402
+ # print(f"Finalizando prueba V8.2 Fix: {current_test}")
1403
  try: score_details = calculate_detailed_scores(current_test, trial_results, params, expected_response_info, sequence); precision = score_details['precision']; analysis_html = score_details['analysis']
1404
+ except Exception as e: print(f"ERROR calculando puntajes V8.2 Fix para {current_test}: {e}"); traceback.print_exc(); precision = 0.0; analysis_html = "<p style='color:red;'>Error al generar análisis detallado.</p>"
1405
  current_scores[current_test] = precision
1406
  if "round_results" not in state or state["round_results"] is None: state["round_results"] = {"detailed_analysis": {}}
1407
  if "detailed_analysis" not in state["round_results"]: state["round_results"]["detailed_analysis"] = {}
 
1409
  next_test_index = current_test_index + 1
1410
  if next_test_index < len(test_order):
1411
  # --- Transition to Next Test ---
1412
+ next_test_name = test_order[next_test_index]; # print(f"Transición a la siguiente prueba V8.2 Fix: {next_test_name}");
1413
  next_stage = "instructions"
1414
  try: next_params = get_difficulty_params(next_test_name, current_level); instruction_text = get_instructions_text(next_test_name, next_params); flex_int_key = next_params.get('interference',{}).get('base_key', FLEX_INTERFERENCE_BASE_KEY) if next_test_name == "Flexibilidad" else "?"
1415
+ except Exception as e: gr.Error(f"Error Crítico preparando siguiente prueba V8.2 Fix {next_test_name}: {e}"); traceback.print_exc(); state["stage"] = "menu"; visibility_updates = get_stage_visibility("menu"); menu_info_update = update_menu_info(state); dummy_instr = [gr.update()] * 2; dummy_test_ui = [gr.update()] * len(test_block_ui_components); dummy_results = [gr.update()] * len(results_display_outputs); dummy_history = [gr.update()] * len(history_display_outputs); return [state] + visibility_updates + [menu_info_update] + dummy_instr + dummy_test_ui + dummy_results + dummy_history
1416
  initial_flex_rule_for_next_test = random.randint(0, 1) if next_test_name == "Flexibilidad" else 0
1417
  state.update({
1418
  "stage": next_stage, "current_test": next_test_name, "current_test_index": next_test_index, "test_params": next_params, "test_sequence": [], "test_expected_response": {}, "test_trial_index": 0,
 
1420
  "initial_flex_rule": initial_flex_rule_for_next_test, "test_current_rule_idx": initial_flex_rule_for_next_test, "test_current_rule_idx_snapshot": initial_flex_rule_for_next_test, "flex_active_interference_key": flex_int_key, })
1421
  visibility_updates = get_stage_visibility(next_stage); menu_info_update = update_menu_info(state); instr_title_update = gr.update(value=f"#### {TEST_ICONS.get(next_test_name, '')} Briefing: {next_test_name} [Nivel {current_level}]"); instr_text_update = gr.update(value=instruction_text)
1422
  test_block_dummies = [gr.update()] * len(test_block_ui_components); results_dummies = [gr.update()] * len(results_display_outputs); history_dummies = [gr.update()] * len(history_display_outputs)
 
1423
  return ([state] + visibility_updates + [menu_info_update] + [instr_title_update, instr_text_update] + test_block_dummies + results_dummies + history_dummies)
1424
  else:
1425
  # --- All Tests Completed: Show Results ---
1426
+ # print("Simulación V8.2 Fix completada. Mostrando resultados.")
1427
  next_stage = "results"; avg_precision = sum(current_scores.values()) / len(current_scores) if current_scores else 0.0; can_advance = avg_precision >= ADVANCE_THRESHOLD_PERCENT; new_level = level_at_start_of_round; level_msg = ""
1428
  if can_advance and level_at_start_of_round < MAX_DIFFICULTY_LEVEL: new_level += 1; level_msg = f"<h5><strong>¡Rendimiento Excepcional!</strong> Acceso Nivel {new_level} Otorgado.</h5>"; gr.Info(f"¡Subiste al Nivel {new_level}!")
1429
  elif can_advance: level_msg = f"<h5><strong>¡Maestría Total!</strong> Nivel Máximo ({level_at_start_of_round}) Dominado.</h5>"; gr.Info(f"¡Nivel Máximo {level_at_start_of_round} mantenido con éxito!"); new_level = level_at_start_of_round
 
1435
  for test in test_order: analysis_part = state["round_results"]["detailed_analysis"].get(test, f"<p>Análisis no disponible para {test}.</p>"); all_analysis_parts.append(f"<h5 class='matrix-subtitle'>{TEST_ICONS.get(test,'')} Análisis: {test}</h5>{analysis_part}")
1436
  full_analysis_html = "<hr class='matrix-hr'>".join(all_analysis_parts) if all_analysis_parts else "<p>No hay análisis detallados.</p>"
1437
  final_results_data = {"scores": current_scores, "avg_precision": avg_precision, "analysis_text": full_analysis_html, "level_message": level_msg, "summary_html": summary_html}; state["round_results"] = final_results_data
1438
+ if alias: print(f"Guardando resultado V8.2 Fix para {alias} (Nivel {level_at_start_of_round})..."); save_success = guardar_resultado(alias, level_at_start_of_round, current_scores, test_order); # print("Resultado guardado." if save_success else "¡Fallo al guardar resultado!")
1439
  # else: print("INFO: No se guarda resultado (sin alias).")
1440
  state.update({"stage": next_stage, "level": new_level, "current_test": None, "current_test_index": -1, "test_params": {}, "test_sequence": [], "test_expected_response": {}, "test_trial_index": 0, "current_stimulus_index": -1, "last_processed_index": -1, "test_stimulus": None, "awaiting_input": False, "current_trial_results": [], "test_last_stimulus": '', "test_feedback": "&nbsp;", "_distraction_active": False})
1441
+ visibility_updates = get_stage_visibility(next_stage); menu_info_update = update_menu_info(state); instr_dummies = [gr.update()] * 2; test_ui_dummies = [gr.update()] * len(test_block_ui_components); results_title_update = gr.update(value=f"### Reporte V8.2 Fix: {alias or 'Agente'} [Nivel {level_at_start_of_round}]"); results_summary_update = gr.HTML(summary_html); results_level_update = gr.HTML(level_msg); results_analysis_title_update = gr.update(visible=True); results_analysis_update = gr.HTML(full_analysis_html); history_dummies = [gr.update()] * len(history_display_outputs)
 
1442
  return ([state] + visibility_updates + [menu_info_update] + instr_dummies + test_ui_dummies + [results_title_update, results_summary_update, results_level_update, results_analysis_title_update, results_analysis_update] + history_dummies)
1443
 
1444
  def view_history_wrapper(state_dict):
 
1457
  if html_update.value == "<p>Cargando historial...</p>": html_update = gr.update(value="<p style='color:red;'>No se pudo cargar el historial.</p>", visible=True)
1458
  df_update = gr.update(visible=False)
1459
  instr_dummies = [gr.update()] * 2; test_ui_dummies = [gr.update()] * len(test_block_ui_components); results_dummies = [gr.update()] * len(results_display_outputs)
 
1460
  return ([state] + visibility_updates + [menu_info_update] + instr_dummies + test_ui_dummies + results_dummies + [df_update, html_update])
1461
 
1462
  def reset_level_wrapper(state_dict):
 
1480
  if next_stage != "set_alias": output_updates[alias_feedback] = gr.update(value="")
1481
  return output_updates # Return dict for flexible output mapping
1482
 
1483
+ # --- Define Output Lists for Clarity (v8.2 Fix - Adjusted counts/components) ---
1484
  # For simple stage changes (back buttons, accept) - Need state + 7 blocks + agent_info + feedback + alias_feedback = 11 outputs
1485
  base_outputs_change_stage = [ game_state, *all_blocks, agent_info, feedback_display, alias_feedback ]
1486
  # For confirming alias - state + 7 blocks + agent_info + alias_feedback = 10 outputs
 
1490
  # For starting a test/finishing a test/viewing history (needs all components updated) - 35 components
1491
  # state + blocks(7) + menu(1) + instr(2) + test_ui(17) + results(5) + history(2) = 35 total
1492
  full_ui_update_outputs = [ game_state, *all_blocks, agent_info, instructions_title, instructions_text,
1493
+ *test_block_ui_components, # 17 components (incl. 11 buttons)
1494
  *results_display_outputs, # 5 components
1495
  *history_display_outputs ] # 2 components
1496
+ # For yields during the trial flow (state + test trial UI elements) - 1 + 17 = 18 outputs? No, it's state + list of 17 UI updates = 18 items.
1497
+ # Let's re-check test_trial_ui_updates: 4 display + 11 buttons + 1 overlay = 16 components. + state = 17 outputs for yield.
1498
+ trial_flow_yield_outputs = [game_state] + test_trial_ui_updates # 17 components
1499
  # For resetting level - state + agent_info = 2 outputs
1500
  reset_outputs = [game_state, agent_info]
1501
 
1502
+
1503
+ # --- Event Handlers (Updated v8.2 Fix - Using correct output lists) ---
1504
 
1505
  # Navigation / Setup Buttons
1506
  accept_button.click(lambda s: change_stage_wrapper(s, "set_alias" if s.get("alias") is None else "menu"), [game_state], base_outputs_change_stage, show_progress="hidden")
 
1515
  start_test_button.click(
1516
  fn=start_test_wrapper, inputs=[game_state], outputs=full_ui_update_outputs, show_progress="minimal" # Needs full update list
1517
  ).then(
1518
+ fn=run_trial_flow, inputs=[game_state], outputs=trial_flow_yield_outputs, show_progress="hidden" # 17 outputs
1519
  ).then(
1520
  fn=finish_current_test_wrapper, inputs=[game_state], outputs=full_ui_update_outputs, show_progress="minimal" # Needs full update list
1521
  )
1522
 
1523
+ # --- Response Button Click Handlers (Updated v8.2 Fix - New Inhib buttons) ---
1524
  button_key_map = {
1525
  # Index 0, 1: Attention
1526
  attn_target_btn: ATTN_TARGET.lower(),
 
1542
  }
1543
 
1544
  for btn, key_or_placeholder in button_key_map.items():
1545
+ btn.click(fn=process_click_wrapper, inputs=[game_state, gr.State(value=key_or_placeholder)], outputs=trial_flow_yield_outputs, show_progress="hidden") # 17 outputs
1546
 
1547
  # Back buttons from Results and History
1548
  results_back_button.click(lambda s: change_stage_wrapper(s, "menu"), [game_state], base_outputs_change_stage, show_progress="hidden")
 
1551
 
1552
  # --- Launch App ---
1553
  if __name__ == "__main__":
1554
+ # print("Iniciando Servidor Gradio MC AR v8.2 HARD+ (Fix)...")
1555
  try: # Ensure results file exists with header
1556
  with csv_lock:
1557
  fieldnames = ['Alias','Timestamp','Level','AvgPrec'] + AVAILABLE_TESTS; file_exists = os.path.isfile(ARCHIVO_RESULTADOS)
 
1559
  if needs_header:
1560
  try:
1561
  with open(ARCHIVO_RESULTADOS, 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=fieldnames); writer.writeheader()
1562
+ # print(f"Archivo de resultados V8.2 HARD+ Fix creado: {ARCHIVO_RESULTADOS}")
1563
  except IOError as e: print(f"ERROR CRÍTICO: No se pudo crear archivo resultados: {e}"); exit(1)
1564
  except Exception as e: print(f"ERROR CRÍTICO: Verificando archivo resultados: {e}"); exit(1)
1565
 
1566
  # print("Configurando Gradio Queue y Launch...")
1567
  demo.queue()
1568
  try:
1569
+ # print("--- Servidor Listo para Conexiones (V8.2 HARD+ Fix) ---")
1570
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
1571
  except Exception as e: print(f"ERROR FATAL durante demo.launch(): {e}"); traceback.print_exc()
1572
  finally: print("--- Servidor Gradio Terminado o Fallo en Launch ---")