|
|
<!DOCTYPE html> |
|
|
<html lang="es"> |
|
|
<head> |
|
|
<meta charset="utf-8" /> |
|
|
<title>Explorador CSV Consumertec</title> |
|
|
<meta name="viewport" content="width=device-width,initial-scale=1" /> |
|
|
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.js"></script> |
|
|
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|
|
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script> |
|
|
|
|
|
<style> |
|
|
:root{ |
|
|
--bg:#020617; |
|
|
--card:#020617; |
|
|
--border:#1f2937; |
|
|
--accent:#22d3ee; |
|
|
--accent2:#4ade80; |
|
|
--text:#e5e7eb; |
|
|
--muted:#9ca3af; |
|
|
} |
|
|
*{box-sizing:border-box;margin:0;padding:0;} |
|
|
body{ |
|
|
min-height:100vh; |
|
|
display:flex; |
|
|
align-items:center; |
|
|
justify-content:center; |
|
|
font-family:system-ui,-apple-system,"Segoe UI",sans-serif; |
|
|
background:radial-gradient(circle at top,#0f172a,#020617); |
|
|
color:var(--text); |
|
|
padding:10px; |
|
|
} |
|
|
.card{ |
|
|
width:min(1100px,100%); |
|
|
max-height:96vh; |
|
|
background:var(--card); |
|
|
border-radius:20px; |
|
|
border:1px solid var(--border); |
|
|
padding:18px 20px; |
|
|
box-shadow:0 22px 50px rgba(0,0,0,0.6); |
|
|
display:flex; |
|
|
flex-direction:column; |
|
|
gap:12px; |
|
|
overflow-y:auto; |
|
|
} |
|
|
h1{ |
|
|
font-size:1.7rem; |
|
|
text-align:center; |
|
|
margin-bottom:4px; |
|
|
} |
|
|
p{ |
|
|
font-size:0.9rem; |
|
|
line-height:1.5; |
|
|
color:var(--muted); |
|
|
text-align:justify; |
|
|
text-justify:inter-word; |
|
|
} |
|
|
.section-title{ |
|
|
font-size:1rem; |
|
|
font-weight:600; |
|
|
margin-bottom:4px; |
|
|
margin-top:8px; |
|
|
} |
|
|
label{ |
|
|
font-size:0.85rem; |
|
|
margin-bottom:4px; |
|
|
display:block; |
|
|
color:var(--muted); |
|
|
} |
|
|
input[type="file"]{ |
|
|
width:100%; |
|
|
padding:8px; |
|
|
border-radius:10px; |
|
|
border:1px dashed var(--border); |
|
|
background:#020617; |
|
|
color:var(--muted); |
|
|
font-size:0.85rem; |
|
|
} |
|
|
input[type="text"], |
|
|
select{ |
|
|
width:100%; |
|
|
padding:8px; |
|
|
border-radius:10px; |
|
|
border:1px solid var(--border); |
|
|
background:#020617; |
|
|
color:var(--text); |
|
|
font-size:0.85rem; |
|
|
} |
|
|
textarea{ |
|
|
width:100%; |
|
|
min-height:90px; |
|
|
max-height:200px; |
|
|
resize:vertical; |
|
|
border-radius:10px; |
|
|
border:1px solid var(--border); |
|
|
background:#020617; |
|
|
color:var(--text); |
|
|
padding:8px 10px; |
|
|
font-size:0.85rem; |
|
|
line-height:1.4; |
|
|
} |
|
|
.row{ |
|
|
display:flex; |
|
|
flex-wrap:wrap; |
|
|
gap:10px; |
|
|
margin-top:6px; |
|
|
align-items:center; |
|
|
} |
|
|
.row > *{ flex:1 1 auto; } |
|
|
.btn{ |
|
|
display:inline-flex; |
|
|
align-items:center; |
|
|
justify-content:center; |
|
|
padding:8px 16px; |
|
|
border-radius:999px; |
|
|
text-decoration:none; |
|
|
border:none; |
|
|
background:linear-gradient(135deg,var(--accent),var(--accent2)); |
|
|
color:#020617; |
|
|
font-weight:600; |
|
|
font-size:0.85rem; |
|
|
letter-spacing:0.02em; |
|
|
cursor:pointer; |
|
|
transition:transform 0.1s ease, filter 0.1s ease; |
|
|
white-space:nowrap; |
|
|
} |
|
|
.btn.secondary{ |
|
|
background:#111827; |
|
|
color:var(--muted); |
|
|
border:1px solid var(--border); |
|
|
} |
|
|
.btn:hover{ |
|
|
filter:brightness(1.06); |
|
|
transform:translateY(-1px); |
|
|
} |
|
|
.status{ |
|
|
font-size:0.83rem; |
|
|
color:var(--muted); |
|
|
margin-top:4px; |
|
|
} |
|
|
.output-box{ |
|
|
margin-top:8px; |
|
|
border-radius:10px; |
|
|
border:1px solid var(--border); |
|
|
background:#020617; |
|
|
padding:8px 10px; |
|
|
font-size:0.83rem; |
|
|
line-height:1.45; |
|
|
max-height:260px; |
|
|
overflow:auto; |
|
|
white-space:pre-wrap; |
|
|
} |
|
|
.small{ font-size:0.8rem; color:var(--muted); } |
|
|
.mode-options{ |
|
|
display:flex; |
|
|
flex-direction:column; |
|
|
gap:8px; |
|
|
margin-top:4px; |
|
|
flex-wrap:wrap; |
|
|
} |
|
|
.mode-group{ |
|
|
display:flex; |
|
|
flex-wrap:wrap; |
|
|
gap:12px; |
|
|
} |
|
|
.mode-group.hidden{ display:none; } |
|
|
.mode-group.disabled{ opacity:0.3; pointer-events:none; } |
|
|
.mode-options label{ |
|
|
display:flex; |
|
|
align-items:center; |
|
|
gap:6px; |
|
|
cursor:pointer; |
|
|
font-size:0.85rem; |
|
|
} |
|
|
.mode-options input[type="radio"]{ |
|
|
accent-color:#22d3ee; |
|
|
width:16px; |
|
|
height:16px; |
|
|
} |
|
|
#textOutput{ |
|
|
max-height:60vh; |
|
|
overflow-y:auto; |
|
|
} |
|
|
.chart-wrapper{ |
|
|
margin-top:8px; |
|
|
border-radius:10px; |
|
|
border:1px solid var(--border); |
|
|
background:#020617; |
|
|
padding:8px 10px; |
|
|
height:260px; |
|
|
} |
|
|
#chartCanvas{ width:100%; height:100%; } |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="card"> |
|
|
<h1>Explorador CSV Consumertec</h1> |
|
|
<p> |
|
|
Este chatbot está diseñado para trabajar con archivos <strong>OUTPUT_MAP_COMPARISONS.csv</strong> y |
|
|
otros CSV derivados de los experimentos de Consumertec. Primero se <strong>sube en la sección 1</strong> |
|
|
el archivo CSV que se desea analizar. A partir de su estructura, en la <strong>sección 2</strong> se |
|
|
activan los <strong>prompts internos</strong> compatibles. Después se ejecuta el análisis: |
|
|
la <strong>sección 5</strong> calcula un <strong>resumen numérico determinista en el navegador</strong> |
|
|
(sin usar backend). Luego, ese resumen numérico se envía al <strong>backend LLM</strong> como evidencia |
|
|
para generar la explicación de la <strong>sección 6</strong> (sin repetir tablas). |
|
|
</p> |
|
|
|
|
|
|
|
|
<div id="llmStatus" class="status small"> |
|
|
ℹ️ La sección 5 se calcula de forma determinista en el navegador. Luego, ese resumen numérico se envía al backend LLM |
|
|
como evidencia para construir la sección 6 (sin reimprimir tablas ni listados). |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="section-title">1. Subir archivo CSV</div> |
|
|
<label for="csvInput" id="csvLabel"> |
|
|
Sube primero el CSV que quieres analizar. Según sus columnas, se activarán las opciones de análisis en la sección 2. |
|
|
</label> |
|
|
<input id="csvInput" type="file" accept=".csv" /> |
|
|
<div id="fileStatus" class="status">⚠️ Ningún archivo seleccionado.</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="section-title">2. Elegir tipo de análisis y prompt interno</div> |
|
|
<p class="small"> |
|
|
Después de subir el CSV, se mostrarán aquí los tipos de análisis compatibles. Cada tipo activa sus |
|
|
prompts internos. El prompt seleccionado se mostrará en la <strong>sección 3</strong> (puedes editarlo) |
|
|
y se usará junto con la evidencia numérica determinista de la sección 5 como entrada al backend LLM. |
|
|
</p> |
|
|
|
|
|
<div class="mode-options"> |
|
|
|
|
|
<div id="group_comparaciones" class="mode-group hidden"> |
|
|
<label> |
|
|
<input id="mode_comparaciones_basico" type="radio" name="mode" |
|
|
onclick="setMode('comparaciones','comparaciones_basico')" /> |
|
|
Prompt 1 — Comparación (PRODUCT_TEST vs RESPONSE) |
|
|
</label> |
|
|
<label> |
|
|
<input id="mode_comparaciones_escenarios" type="radio" name="mode" |
|
|
onclick="setMode('comparaciones','comparaciones_escenarios')" /> |
|
|
Prompt 5 — Comparación por escenarios y modalidades |
|
|
</label> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="group_whiteness" class="mode-group hidden"> |
|
|
<label> |
|
|
<input id="mode_whiteness_basico" type="radio" name="mode" |
|
|
onclick="setMode('whiteness','whiteness_basico')" /> |
|
|
Prompt 2 — Blancura por MONITOR (métricas WI) |
|
|
</label> |
|
|
<label> |
|
|
<input id="mode_whiteness_productos" type="radio" name="mode" |
|
|
onclick="setMode('whiteness','whiteness_productos')" /> |
|
|
Prompt 6 — Perfil de blancura por producto |
|
|
</label> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="group_resumen" class="mode-group hidden"> |
|
|
<label> |
|
|
<input id="mode_resumen_basico" type="radio" name="mode" |
|
|
onclick="setMode('resumen','resumen_basico')" /> |
|
|
Prompt 3 — Resumen general de la tabla |
|
|
</label> |
|
|
<label> |
|
|
<input id="mode_resumen_avanzado" type="radio" name="mode" |
|
|
onclick="setMode('resumen','resumen_avanzado')" /> |
|
|
Prompt 7 — Resumen avanzado y bloques de variables |
|
|
</label> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="group_response_rel" class="mode-group hidden"> |
|
|
<label> |
|
|
<input id="mode_response_basico" type="radio" name="mode" |
|
|
onclick="setMode('response_rel','response_basico')" /> |
|
|
Prompt 4 — Comparar RESPONSE con las demás columnas |
|
|
</label> |
|
|
<label> |
|
|
<input id="mode_response_extremos" type="radio" name="mode" |
|
|
onclick="setMode('response_rel','response_extremos')" /> |
|
|
Prompt 8 — RESPONSE: mejores y peores resultados |
|
|
</label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="status small" id="modeStatus"> |
|
|
Primero sube un CSV en la sección 1. Luego se activarán aquí los tipos de análisis compatibles. |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="section-title">3. Prompt de análisis</div> |
|
|
<label for="question"> |
|
|
El prompt se rellenará automáticamente según el análisis elegido, pero puedes editarlo libremente. |
|
|
Este texto se enviará al <strong>backend LLM</strong> junto con el resumen numérico determinista (sección 5), |
|
|
como evidencia para generar la explicación de la sección 6. |
|
|
</label> |
|
|
<textarea id="question" placeholder="Sube un CSV y elige un tipo de análisis; aquí aparecerá el prompt asociado, que podrás ajustar…"></textarea> |
|
|
<div class="row"> |
|
|
<button class="btn" type="button" onclick="analizarCSV()"> |
|
|
4. Analizar CSV |
|
|
</button> |
|
|
</div> |
|
|
<div id="analysisStatus" class="status"> |
|
|
⏳ Sube un CSV, elige un tipo de análisis en la sección 2 y luego usa el botón Analizar. |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="section-title">5. Resultados numéricos (resumen determinista en el navegador)</div> |
|
|
<div id="numericOutput" class="output-box small"> |
|
|
// Sección 5 — Resumen numérico determinista (generado en el navegador). |
|
|
// Ejecuta “4. Analizar CSV” para generarlo aquí. |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="section-title">6. Explicación (LLM usando el resumen numérico como evidencia)</div> |
|
|
<div id="textOutput" class="output-box"> |
|
|
// Aquí se generará la explicación producida por el LLM usando tu prompt (sección 3) + evidencia numérica (sección 5). |
|
|
</div> |
|
|
|
|
|
<div class="row"> |
|
|
<div> |
|
|
<label for="reportTitle" class="small"> |
|
|
Título del reporte (se usará como título en el PDF y en el nombre del archivo) |
|
|
</label> |
|
|
<input id="reportTitle" |
|
|
type="text" |
|
|
placeholder="Ejemplo: Informe de desempeño de productos Consumertec" /> |
|
|
</div> |
|
|
<div style="flex:0 0 auto;"> |
|
|
<button class="btn secondary" type="button" onclick="descargarPDF()"> |
|
|
Descargar secciones 6 y 7 (.pdf) |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="section-title">7. Visualización gráfica de resultados (desde la sección 5)</div> |
|
|
<p class="small"> |
|
|
Estos gráficos se generan a partir del resumen determinista de la sección 5. |
|
|
El LLM no usa los gráficos; son una ayuda visual para interpretar los resultados. |
|
|
</p> |
|
|
<div class="row"> |
|
|
<div> |
|
|
<label for="chartType">Tipo de gráfico</label> |
|
|
<select id="chartType" onchange="cambiarTipoGrafico()"> |
|
|
<option value="bar">Barras</option> |
|
|
<option value="line">Líneas</option> |
|
|
</select> |
|
|
</div> |
|
|
<div id="chartStatus" class="status"> |
|
|
⚠️ Aún no hay datos para graficar. Ejecuta un análisis primero. |
|
|
</div> |
|
|
</div> |
|
|
<div class="chart-wrapper"> |
|
|
<canvas id="chartCanvas"></canvas> |
|
|
</div> |
|
|
|
|
|
<div id="chartMultiStatus" class="status"> |
|
|
⚠️ Aún no hay datos para el gráfico multivariable. Ejecuta un análisis compatible (por ejemplo, Comparaciones). |
|
|
</div> |
|
|
<div class="chart-wrapper"> |
|
|
<canvas id="chartCanvasMulti"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<script src="static/state.js"></script> |
|
|
<script src="static/core.js"></script> |
|
|
|
|
|
<script src="static/modes/comparaciones.js"></script> |
|
|
<script src="static/modes/whiteness.js"></script> |
|
|
<script src="static/modes/resumen.js"></script> |
|
|
<script src="static/modes/response_rel.js"></script> |
|
|
|
|
|
<script src="static/pdf.js"></script> |
|
|
</body> |
|
|
</html> |