Spaces:
Paused
Paused
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>ChatScope — Export Viewer</title> | |
| <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> | |
| <style> | |
| :root { | |
| --bg: #0a0a0b; | |
| --bg-secondary: #131316; | |
| --bg-tertiary: #1c1c21; | |
| --bg-hover: #25252b; | |
| --bg-card: #16161a; | |
| --border: #2a2a30; | |
| --border-light: #353540; | |
| --text: #e8e8ec; | |
| --text-dim: #8a8a96; | |
| --text-faint: #50505a; | |
| --accent: #6c5ce7; | |
| --accent-light: #8b7ff0; | |
| --accent-dim: #4a3fb0; | |
| --accent-glow: rgba(108, 92, 231, 0.15); | |
| --green: #00d4a0; | |
| --green-dim: #00a07a; | |
| --orange: #ff9f43; | |
| --red: #ee5253; | |
| --blue: #54a0ff; | |
| --radius: 10px; | |
| --radius-sm: 6px; | |
| --sidebar-w: 300px; | |
| --header-h: 52px; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| html, | |
| body { | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| background: var(--bg); | |
| color: var(--text); | |
| font-size: 14px; | |
| line-height: 1.6; | |
| } | |
| /* ===== Layout ===== */ | |
| .app { | |
| display: flex; | |
| height: 100vh; | |
| } | |
| .sidebar { | |
| width: var(--sidebar-w); | |
| min-width: var(--sidebar-w); | |
| background: var(--bg-secondary); | |
| border-right: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .main { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| /* ===== Logo / Brand ===== */ | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 14px 16px 10px; | |
| flex-shrink: 0; | |
| } | |
| .logo-mark { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 8px; | |
| background: linear-gradient(135deg, var(--accent), var(--green)); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 18px; | |
| font-weight: 800; | |
| color: #fff; | |
| flex-shrink: 0; | |
| box-shadow: 0 2px 12px var(--accent-glow); | |
| } | |
| .logo-text { | |
| font-size: 16px; | |
| font-weight: 700; | |
| letter-spacing: -0.3px; | |
| } | |
| .logo-text span { | |
| color: var(--accent-light); | |
| } | |
| /* ===== Top nav tabs ===== */ | |
| .nav-tabs { | |
| display: flex; | |
| gap: 2px; | |
| padding: 0 12px 10px; | |
| flex-shrink: 0; | |
| } | |
| .nav-tab { | |
| padding: 6px 14px; | |
| border-radius: var(--radius-sm); | |
| font-size: 13px; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| border: none; | |
| background: transparent; | |
| color: var(--text-dim); | |
| } | |
| .nav-tab:hover { | |
| background: var(--bg-hover); | |
| color: var(--text); | |
| } | |
| .nav-tab.active { | |
| background: var(--accent); | |
| color: #fff; | |
| } | |
| /* ===== Sidebar header ===== */ | |
| .sidebar-header { | |
| padding: 0 16px 12px; | |
| border-bottom: 1px solid var(--border); | |
| flex-shrink: 0; | |
| } | |
| .search-box { | |
| width: 100%; | |
| padding: 8px 12px 8px 34px; | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| color: var(--text); | |
| font-size: 13px; | |
| outline: none; | |
| transition: all 0.2s; | |
| } | |
| .search-box:focus { | |
| border-color: var(--accent); | |
| box-shadow: 0 0 0 3px var(--accent-glow); | |
| } | |
| .search-box::placeholder { | |
| color: var(--text-faint); | |
| } | |
| .search-wrap { | |
| position: relative; | |
| } | |
| .search-wrap .search-icon { | |
| position: absolute; | |
| left: 10px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| color: var(--text-faint); | |
| font-size: 14px; | |
| pointer-events: none; | |
| } | |
| /* ===== Conversation list ===== */ | |
| .convo-list { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 8px; | |
| } | |
| .convo-item { | |
| padding: 10px 12px; | |
| border-radius: var(--radius-sm); | |
| cursor: pointer; | |
| transition: all 0.15s; | |
| margin-bottom: 2px; | |
| border: 1px solid transparent; | |
| position: relative; | |
| } | |
| .convo-item:hover { | |
| background: var(--bg-hover); | |
| } | |
| .convo-item.active { | |
| background: var(--bg-tertiary); | |
| border-color: var(--accent-dim); | |
| } | |
| .convo-item.active::before { | |
| content: ''; | |
| position: absolute; | |
| left: 0; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| width: 3px; | |
| height: 60%; | |
| background: var(--accent); | |
| border-radius: 0 3px 3px 0; | |
| } | |
| .convo-item .title { | |
| font-size: 13px; | |
| font-weight: 500; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| margin-bottom: 3px; | |
| } | |
| .convo-item .meta { | |
| font-size: 11px; | |
| color: var(--text-dim); | |
| display: flex; | |
| gap: 6px; | |
| align-items: center; | |
| } | |
| .convo-item .meta .model { | |
| background: var(--bg); | |
| padding: 1px 6px; | |
| border-radius: 4px; | |
| font-size: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.3px; | |
| } | |
| /* ===== Main area ===== */ | |
| .chat-header { | |
| padding: 12px 20px; | |
| border-bottom: 1px solid var(--border); | |
| flex-shrink: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| background: var(--bg-secondary); | |
| min-height: var(--header-h); | |
| } | |
| .chat-header .title { | |
| font-size: 15px; | |
| font-weight: 600; | |
| } | |
| .chat-header .info { | |
| font-size: 12px; | |
| color: var(--text-dim); | |
| margin-top: 2px; | |
| } | |
| .chat-body { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 24px 0; | |
| } | |
| .chat-empty { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| color: var(--text-faint); | |
| gap: 12px; | |
| } | |
| .chat-empty .icon { | |
| font-size: 48px; | |
| opacity: 0.3; | |
| } | |
| .chat-empty .text { | |
| font-size: 15px; | |
| } | |
| /* ===== Messages ===== */ | |
| .message { | |
| max-width: 820px; | |
| margin: 0 auto; | |
| padding: 6px 24px; | |
| display: flex; | |
| gap: 14px; | |
| margin-bottom: 2px; | |
| } | |
| .message .avatar { | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 7px; | |
| flex-shrink: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 13px; | |
| font-weight: 700; | |
| margin-top: 2px; | |
| } | |
| .message.user .avatar { | |
| background: var(--accent); | |
| color: #fff; | |
| } | |
| .message.assistant .avatar { | |
| background: var(--green-dim); | |
| color: #fff; | |
| } | |
| .message.system .avatar { | |
| background: var(--orange); | |
| color: #fff; | |
| } | |
| .message.tool .avatar { | |
| background: #6b4fa0; | |
| color: #fff; | |
| } | |
| .message .content { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .message .role-label { | |
| font-size: 12px; | |
| font-weight: 600; | |
| margin-bottom: 3px; | |
| color: var(--text-dim); | |
| text-transform: capitalize; | |
| } | |
| .message .text { | |
| font-size: 14px; | |
| line-height: 1.7; | |
| word-wrap: break-word; | |
| } | |
| .message .text p { | |
| margin-bottom: 10px; | |
| } | |
| .message .text p:last-child { | |
| margin-bottom: 0; | |
| } | |
| .message .text pre { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 14px 16px; | |
| overflow-x: auto; | |
| font-size: 13px; | |
| line-height: 1.5; | |
| margin: 10px 0; | |
| } | |
| .message .text code { | |
| font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; | |
| font-size: 13px; | |
| } | |
| .message .text :not(pre)>code { | |
| background: var(--bg-tertiary); | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| } | |
| .message .text ul, | |
| .message .text ol { | |
| margin: 8px 0 10px 20px; | |
| } | |
| .message .text li { | |
| margin-bottom: 3px; | |
| } | |
| .message .text table { | |
| border-collapse: collapse; | |
| margin: 10px 0; | |
| width: 100%; | |
| } | |
| .message .text th, | |
| .message .text td { | |
| border: 1px solid var(--border); | |
| padding: 6px 10px; | |
| text-align: left; | |
| } | |
| .message .text th { | |
| background: var(--bg-tertiary); | |
| } | |
| .message .text img { | |
| max-width: 100%; | |
| border-radius: var(--radius-sm); | |
| margin: 10px 0; | |
| } | |
| .message .text a { | |
| color: var(--accent-light); | |
| text-decoration: none; | |
| } | |
| .message .text a:hover { | |
| text-decoration: underline; | |
| } | |
| .message .text blockquote { | |
| border-left: 3px solid var(--accent-dim); | |
| padding-left: 14px; | |
| margin: 10px 0; | |
| color: var(--text-dim); | |
| } | |
| .message .meta-row { | |
| font-size: 10px; | |
| color: var(--text-faint); | |
| margin-top: 4px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.3px; | |
| } | |
| /* ===== KPI Dashboard ===== */ | |
| .kpi-view { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 24px 32px; | |
| } | |
| .kpi-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); | |
| gap: 16px; | |
| max-width: 900px; | |
| margin: 0 auto 32px; | |
| } | |
| .kpi-card { | |
| background: var(--bg-card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| padding: 20px; | |
| transition: all 0.2s; | |
| } | |
| .kpi-card:hover { | |
| border-color: var(--border-light); | |
| transform: translateY(-2px); | |
| } | |
| .kpi-card .label { | |
| font-size: 11px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| color: var(--text-dim); | |
| margin-bottom: 8px; | |
| } | |
| .kpi-card .value { | |
| font-size: 28px; | |
| font-weight: 700; | |
| letter-spacing: -0.5px; | |
| } | |
| .kpi-card .sub { | |
| font-size: 11px; | |
| color: var(--text-faint); | |
| margin-top: 4px; | |
| } | |
| .kpi-card.accent .value { | |
| color: var(--accent-light); | |
| } | |
| .kpi-card.green .value { | |
| color: var(--green); | |
| } | |
| .kpi-card.orange .value { | |
| color: var(--orange); | |
| } | |
| .kpi-card.blue .value { | |
| color: var(--blue); | |
| } | |
| /* Charts */ | |
| .kpi-charts { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 16px; | |
| max-width: 900px; | |
| margin: 0 auto 32px; | |
| } | |
| .chart-card { | |
| background: var(--bg-card); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| padding: 20px; | |
| } | |
| .chart-card .chart-title { | |
| font-size: 13px; | |
| font-weight: 600; | |
| margin-bottom: 16px; | |
| color: var(--text-dim); | |
| text-transform: uppercase; | |
| letter-spacing: 0.3px; | |
| } | |
| .bar-chart { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 6px; | |
| } | |
| .bar-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| font-size: 12px; | |
| } | |
| .bar-row .bar-label { | |
| width: 80px; | |
| text-align: right; | |
| color: var(--text-dim); | |
| flex-shrink: 0; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .bar-row .bar-track { | |
| flex: 1; | |
| height: 20px; | |
| background: var(--bg-tertiary); | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .bar-row .bar-fill { | |
| height: 100%; | |
| border-radius: 4px; | |
| transition: width 0.6s ease; | |
| } | |
| .bar-row .bar-value { | |
| width: 40px; | |
| color: var(--text-dim); | |
| flex-shrink: 0; | |
| } | |
| /* Timeline */ | |
| .timeline-chart { | |
| display: flex; | |
| align-items: flex-end; | |
| gap: 3px; | |
| height: 120px; | |
| padding-top: 10px; | |
| } | |
| .timeline-bar { | |
| flex: 1; | |
| min-width: 4px; | |
| background: var(--accent-dim); | |
| border-radius: 3px 3px 0 0; | |
| transition: all 0.3s; | |
| position: relative; | |
| cursor: pointer; | |
| } | |
| .timeline-bar:hover { | |
| background: var(--accent); | |
| } | |
| .timeline-bar:hover::after { | |
| content: attr(data-label); | |
| position: absolute; | |
| bottom: 100%; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| background: var(--bg); | |
| border: 1px solid var(--border); | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 11px; | |
| white-space: nowrap; | |
| z-index: 10; | |
| } | |
| .timeline-labels { | |
| display: flex; | |
| gap: 3px; | |
| margin-top: 6px; | |
| } | |
| .timeline-label { | |
| flex: 1; | |
| text-align: center; | |
| font-size: 9px; | |
| color: var(--text-faint); | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| /* Model distribution */ | |
| .model-bars .bar-fill { | |
| background: var(--accent); | |
| } | |
| /* Hour heatmap */ | |
| .hour-chart { | |
| display: flex; | |
| gap: 2px; | |
| height: 60px; | |
| align-items: flex-end; | |
| } | |
| .hour-bar { | |
| flex: 1; | |
| background: var(--green-dim); | |
| border-radius: 2px 2px 0 0; | |
| min-height: 2px; | |
| transition: all 0.3s; | |
| } | |
| .hour-bar:hover { | |
| background: var(--green); | |
| } | |
| .hour-labels { | |
| display: flex; | |
| gap: 2px; | |
| margin-top: 4px; | |
| } | |
| .hour-label { | |
| flex: 1; | |
| text-align: center; | |
| font-size: 8px; | |
| color: var(--text-faint); | |
| } | |
| @media (max-width: 768px) { | |
| .kpi-charts { | |
| grid-template-columns: 1fr; | |
| } | |
| .sidebar { | |
| position: absolute; | |
| z-index: 10; | |
| height: 100%; | |
| transform: translateX(-100%); | |
| transition: transform 0.3s; | |
| } | |
| .sidebar.open { | |
| transform: translateX(0); | |
| } | |
| .main { | |
| width: 100%; | |
| } | |
| .message { | |
| padding: 6px 16px; | |
| } | |
| .kpi-view { | |
| padding: 16px; | |
| } | |
| } | |
| /* ===== Loading ===== */ | |
| .loading { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| } | |
| .spinner { | |
| width: 32px; | |
| height: 32px; | |
| border: 3px solid var(--bg-tertiary); | |
| border-top-color: var(--accent); | |
| border-radius: 50%; | |
| animation: spin 0.8s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| /* Scrollbars */ | |
| ::-webkit-scrollbar { | |
| width: 6px; | |
| height: 6px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--border); | |
| border-radius: 3px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: var(--border-light); | |
| } | |
| /* View toggle */ | |
| .view { | |
| display: none; | |
| flex: 1; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .view.active { | |
| display: flex; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <div class="sidebar" id="sidebar"> | |
| <div class="logo"> | |
| <div class="logo-mark">C</div> | |
| <div class="logo-text">Chat<span>Scope</span></div> | |
| </div> | |
| <div class="nav-tabs"> | |
| <button class="nav-tab active" data-view="chats" id="tabChats">Chats</button> | |
| <button class="nav-tab" data-view="kpi" id="tabKpi">Analytics</button> | |
| </div> | |
| <div class="sidebar-header"> | |
| <div class="search-wrap"> | |
| <span class="search-icon">🔍</span> | |
| <input class="search-box" id="search" placeholder="Search conversations..." type="text"> | |
| </div> | |
| </div> | |
| <div class="convo-list" id="convoList"></div> | |
| </div> | |
| <div class="main"> | |
| <!-- Chat View --> | |
| <div class="view active" id="chatView"> | |
| <div class="chat-header" id="chatHeader" style="display:none;"> | |
| <div> | |
| <div class="title" id="chatTitle"></div> | |
| <div class="info" id="chatInfo"></div> | |
| </div> | |
| </div> | |
| <div class="chat-body" id="chatBody"> | |
| <div class="chat-empty"> | |
| <div class="icon">💬</div> | |
| <div class="text">Select a conversation from the sidebar</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- KPI View --> | |
| <div class="view" id="kpiView"> | |
| <div class="kpi-view" id="kpiContent"> | |
| <div class="loading"> | |
| <div class="spinner"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| </script> | |
| </body> | |
| </html> |