| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>AI Response Validator</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> |
| <style> |
| * { margin: 0; padding: 0; box-sizing: border-box; } |
| |
| body { |
| font-family: 'Inter', sans-serif; |
| background: #eef4fc; |
| color: #1a1a1a; |
| height: 100vh; |
| display: grid; |
| grid-template-rows: auto 1fr; |
| overflow: hidden; |
| } |
| |
| |
| header { |
| background: #fff; |
| border-bottom: 2px solid #1e3a5f; |
| padding: 14px 28px; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 24px; |
| } |
| |
| .header-left h1 { |
| font-size: 22px; |
| font-weight: 900; |
| color: #1a1a1a; |
| letter-spacing: -0.5px; |
| } |
| .header-left h1 span { color: #3a6ea8; } |
| .header-left .tagline { |
| font-size: 11px; |
| color: #8aabcc; |
| margin-top: 2px; |
| } |
| |
| |
| .switcher { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| flex-wrap: wrap; |
| } |
| |
| .switcher label { |
| font-size: 10px; |
| font-weight: 700; |
| text-transform: uppercase; |
| letter-spacing: 1.5px; |
| color: #8aabcc; |
| } |
| |
| .btn-group { |
| display: flex; |
| border: 1px solid #c8dff5; |
| border-radius: 5px; |
| overflow: hidden; |
| } |
| |
| .btn-group button { |
| background: #fff; |
| border: none; |
| border-right: 1px solid #c8dff5; |
| padding: 6px 14px; |
| font-size: 12px; |
| font-weight: 600; |
| color: #4a6a8a; |
| cursor: pointer; |
| transition: background 0.15s, color 0.15s; |
| } |
| .btn-group button:last-child { border-right: none; } |
| .btn-group button.active { |
| background: #1e3a5f; |
| color: #fff; |
| } |
| .btn-group button:hover:not(.active) { background: #eef4fc; } |
| |
| .divider-v { |
| width: 1px; |
| height: 28px; |
| background: #c8dff5; |
| } |
| |
| |
| main { |
| display: grid; |
| grid-template-columns: 1fr 360px; |
| overflow: hidden; |
| } |
| |
| |
| .chat-panel { |
| display: flex; |
| flex-direction: column; |
| border-right: 1px solid #c8dff5; |
| overflow: hidden; |
| } |
| |
| .messages { |
| flex: 1; |
| overflow-y: auto; |
| padding: 24px 28px; |
| display: flex; |
| flex-direction: column; |
| gap: 16px; |
| } |
| |
| .message { |
| display: flex; |
| flex-direction: column; |
| gap: 4px; |
| max-width: 80%; |
| } |
| .message.user { align-self: flex-end; } |
| .message.bot { align-self: flex-start; } |
| |
| .message .bubble { |
| padding: 12px 16px; |
| border-radius: 8px; |
| font-size: 13.5px; |
| line-height: 1.6; |
| } |
| .message.user .bubble { |
| background: #1e3a5f; |
| color: #fff; |
| border-radius: 8px 8px 2px 8px; |
| } |
| .message.bot .bubble { |
| background: #fff; |
| color: #1a1a1a; |
| border: 1px solid #c8dff5; |
| border-radius: 8px 8px 8px 2px; |
| } |
| |
| .message .meta { |
| font-size: 10px; |
| color: #8aabcc; |
| padding: 0 4px; |
| } |
| .message.user .meta { text-align: right; } |
| |
| |
| .verdict { |
| display: inline-flex; |
| align-items: center; |
| gap: 5px; |
| font-size: 10px; |
| font-weight: 700; |
| padding: 2px 8px; |
| border-radius: 3px; |
| margin-top: 4px; |
| align-self: flex-start; |
| } |
| .verdict.pass { background: #f1f8f1; color: #2e7d32; border: 1px solid #c8e6c9; } |
| .verdict.fail { background: #fdf1f1; color: #c62828; border: 1px solid #ffcdd2; } |
| .verdict.warn { background: #fffbf0; color: #a06000; border: 1px solid #ffe082; } |
| |
| |
| .input-bar { |
| padding: 16px 28px; |
| background: #fff; |
| border-top: 1px solid #c8dff5; |
| display: flex; |
| gap: 10px; |
| } |
| |
| .input-bar input { |
| flex: 1; |
| padding: 10px 14px; |
| border: 1px solid #c8dff5; |
| border-radius: 6px; |
| font-size: 13.5px; |
| font-family: 'Inter', sans-serif; |
| outline: none; |
| transition: border-color 0.15s; |
| } |
| .input-bar input:focus { border-color: #3a6ea8; } |
| .input-bar input:disabled { background: #f5f9ff; color: #8aabcc; } |
| |
| .input-bar button { |
| padding: 10px 20px; |
| background: #1e3a5f; |
| color: #fff; |
| border: none; |
| border-radius: 6px; |
| font-size: 13px; |
| font-weight: 700; |
| cursor: pointer; |
| transition: background 0.15s; |
| white-space: nowrap; |
| } |
| .input-bar button:hover:not(:disabled) { background: #3a6ea8; } |
| .input-bar button:disabled { background: #93b8d8; cursor: not-allowed; } |
| |
| .example-chips { |
| display: flex; |
| flex-direction: column; |
| gap: 6px; |
| margin-top: 10px; |
| } |
| |
| .example-chip { |
| background: #eef4fc; |
| border: 1px solid #c5d8f0; |
| border-radius: 6px; |
| padding: 7px 12px; |
| font-size: 12px; |
| color: #1e3a5f; |
| text-align: left; |
| cursor: pointer; |
| transition: background 0.15s; |
| } |
| |
| .example-chip:hover { |
| background: #d6e8fa; |
| } |
| |
| .out-of-scope-badge { |
| display: inline-block; |
| background: #fff3e0; |
| color: #e65100; |
| border: 1px solid #ffcc80; |
| border-radius: 3px; |
| font-size: 11px; |
| font-weight: 700; |
| padding: 1px 6px; |
| margin-right: 6px; |
| vertical-align: middle; |
| letter-spacing: 0.02em; |
| } |
| |
| .flagged-banner { |
| background: #fff0f0; |
| border-left: 4px solid #e74c3c; |
| color: #c0392b; |
| font-size: 12px; |
| font-weight: 600; |
| padding: 8px 16px; |
| margin: 12px 16px 0; |
| border-radius: 4px; |
| } |
| |
| |
| .eval-panel { |
| background: #fff; |
| overflow-y: auto; |
| display: flex; |
| flex-direction: column; |
| } |
| |
| .eval-panel .panel-header { |
| padding: 16px 20px 12px; |
| border-bottom: 1px solid #e8f2ff; |
| font-size: 10px; |
| font-weight: 800; |
| text-transform: uppercase; |
| letter-spacing: 2px; |
| color: #8aabcc; |
| position: sticky; |
| top: 0; |
| background: #fff; |
| z-index: 1; |
| } |
| |
| .eval-empty { |
| flex: 1; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| gap: 10px; |
| color: #b0cce8; |
| padding: 40px 20px; |
| text-align: center; |
| } |
| .eval-empty .icon { font-size: 36px; } |
| .eval-empty p { font-size: 12px; line-height: 1.6; } |
| |
| .eval-content { padding: 16px 20px; display: flex; flex-direction: column; gap: 20px; } |
| |
| |
| .metric-card { |
| border: 1px solid #e0eef8; |
| border-left: 3px solid #1e3a5f; |
| border-radius: 0 6px 6px 0; |
| padding: 12px 14px; |
| background: #f5f9ff; |
| } |
| .metric-card.pass { border-left-color: #4caf50; background: #f0faf3; } |
| .metric-card.fail { border-left-color: #c62828; background: #fdf5f5; } |
| .metric-card.warn { border-left-color: #f9a825; background: #fffdf0; } |
| |
| .metric-card .metric-header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 6px; |
| } |
| .metric-card .metric-name { |
| font-size: 12px; |
| font-weight: 800; |
| color: #1e3a5f; |
| font-family: 'JetBrains Mono', monospace; |
| } |
| .metric-card.pass .metric-name { color: #2e7d32; } |
| .metric-card.fail .metric-name { color: #c62828; } |
| |
| .score-badge { |
| font-family: 'JetBrains Mono', monospace; |
| font-size: 11px; |
| font-weight: 700; |
| padding: 2px 8px; |
| border-radius: 3px; |
| border: 1px solid; |
| } |
| .score-badge.pass { background: #f1f8f1; color: #2e7d32; border-color: #c8e6c9; } |
| .score-badge.fail { background: #fdf1f1; color: #c62828; border-color: #ffcdd2; } |
| .score-badge.warn { background: #fffbf0; color: #a06000; border-color: #ffe082; } |
| |
| .metric-card .metric-detail { |
| font-size: 11px; |
| color: #4a6080; |
| line-height: 1.5; |
| } |
| |
| |
| .score-bar-wrap { margin-top: 8px; } |
| .score-bar-bg { |
| height: 4px; |
| background: #e0eef8; |
| border-radius: 2px; |
| overflow: hidden; |
| } |
| .score-bar-fill { |
| height: 100%; |
| border-radius: 2px; |
| transition: width 0.4s ease; |
| } |
| .score-bar-fill.pass { background: #4caf50; } |
| .score-bar-fill.fail { background: #c62828; } |
| .score-bar-fill.warn { background: #f9a825; } |
| |
| |
| .sources-section .sources-label { |
| font-size: 10px; |
| font-weight: 700; |
| text-transform: uppercase; |
| letter-spacing: 1.5px; |
| color: #8aabcc; |
| margin-bottom: 8px; |
| } |
| .source-item { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| padding: 7px 10px; |
| background: #f5f9ff; |
| border: 1px solid #e0eef8; |
| border-radius: 5px; |
| margin-bottom: 5px; |
| font-size: 11.5px; |
| } |
| .source-item .source-title { color: #2a4a6a; font-weight: 500; } |
| .source-item .source-score { |
| font-family: 'JetBrains Mono', monospace; |
| font-size: 10px; |
| color: #8aabcc; |
| } |
| |
| |
| .thinking { |
| display: flex; |
| gap: 5px; |
| align-items: center; |
| padding: 12px 16px; |
| background: #fff; |
| border: 1px solid #c8dff5; |
| border-radius: 8px 8px 8px 2px; |
| width: fit-content; |
| } |
| .thinking span { |
| width: 7px; height: 7px; |
| background: #3a6ea8; |
| border-radius: 50%; |
| animation: bounce 1.2s infinite ease-in-out; |
| } |
| .thinking span:nth-child(2) { animation-delay: 0.2s; } |
| .thinking span:nth-child(3) { animation-delay: 0.4s; } |
| |
| @keyframes bounce { |
| 0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; } |
| 40% { transform: scale(1); opacity: 1; } |
| } |
| |
| |
| ::-webkit-scrollbar { width: 5px; } |
| ::-webkit-scrollbar-track { background: transparent; } |
| ::-webkit-scrollbar-thumb { background: #c8dff5; border-radius: 3px; } |
| </style> |
| </head> |
| <body> |
|
|
| <header> |
| <div class="header-left"> |
| <h1>AI Response <span>Validator</span></h1> |
| <div class="tagline">Domain-agnostic RAG evaluation · real-time L1 metrics · RosettaStone terminology</div> |
| </div> |
|
|
| <div class="switcher"> |
| <label>Domain</label> |
| <div class="btn-group" id="domain-switcher"></div> |
|
|
| <div class="divider-v"></div> |
|
|
| <label>Client</label> |
| <div class="btn-group" id="client-switcher"></div> |
| </div> |
| </header> |
|
|
| <main> |
| <div class="chat-panel"> |
| <div class="messages" id="messages"> |
| |
| </div> |
| <div class="input-bar"> |
| <input |
| type="text" |
| id="query-input" |
| placeholder="Ask something…" |
| autocomplete="off" |
| /> |
| <button id="send-btn">Send</button> |
| </div> |
| </div> |
|
|
| <div class="eval-panel"> |
| <div class="panel-header">Evaluation</div> |
| <div id="eval-body"> |
| <div class="eval-empty"> |
| <div class="icon">◎</div> |
| <p>Send a message to see<br>real-time metric evaluation.</p> |
| </div> |
| </div> |
| </div> |
| </main> |
|
|
| <script src="/static/app.js"></script> |
| </body> |
| </html> |
|
|