Update app.py
Browse files
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,
|
| 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 |
-
|
| 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 (
|
| 1242 |
-
test_trial_ui_updates = [stimulus_display, feedback_display, progress_indicator, timer_display] + all_response_buttons + [distraction_overlay]
|
| 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]
|
| 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'> </p>"), gr.HTML(" "), 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 |
-
|
| 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": " ", "_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 +
|
| 1508 |
-
|
|
|
|
| 1509 |
# For resetting level - state + agent_info = 2 outputs
|
| 1510 |
reset_outputs = [game_state, agent_info]
|
| 1511 |
|
| 1512 |
-
|
|
|
|
| 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'> </p>"), gr.HTML(" "), 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": " ", "_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 ---")
|