| <!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> |