Spaces:
Paused
Paused
| <html> | |
| <head> | |
| <title>Compact Chat</title> | |
| </head> | |
| <body> | |
| <div x-data x-show="$store.compactStore?.showModal" style="display: none;"> | |
| <div class="modal-overlay" @click="$store.compactStore?.closeModal()"> | |
| <div class="modal-container" @click.stop> | |
| <div class="modal-header"> | |
| <h3>Compact Chat History</h3> | |
| <button class="modal-close" @click="$store.compactStore?.closeModal()"> | |
| <span class="material-symbols-outlined">close</span> | |
| </button> | |
| </div> | |
| <div class="modal-content"> | |
| <template x-if="$store.compactStore?.stats"> | |
| <div class="stats-container"> | |
| <p class="stats-description"> | |
| This will summarize your entire conversation into a single optimized message. | |
| </p> | |
| <div class="stats-grid"> | |
| <div class="stat-item"> | |
| <span class="stat-label">Messages</span> | |
| <span class="stat-value" x-text="$store.compactStore?.stats?.message_count"></span> | |
| </div> | |
| <div class="stat-item"> | |
| <span class="stat-label">Tokens</span> | |
| <span class="stat-value" x-text="$store.compactStore?.stats?.token_count?.toLocaleString()"></span> | |
| </div> | |
| </div> | |
| <!-- Model selection --> | |
| <div class="model-section"> | |
| <div class="model-section-label">Model</div> | |
| <div class="model-controls"> | |
| <!-- Preset dropdown --> | |
| <select class="compact-select" | |
| x-model="$store.compactStore.selectedPresetName"> | |
| <option value="">Current</option> | |
| <template x-for="preset in $store.compactStore.presets" :key="preset.name"> | |
| <option :value="preset.name" x-text="preset.name"></option> | |
| </template> | |
| </select> | |
| <!-- Chat / Utility toggle --> | |
| <div class="model-type-toggle"> | |
| <button :class="{ active: $store.compactStore.useChatModel }" | |
| @click="$store.compactStore.useChatModel = true"> | |
| Chat | |
| </button> | |
| <button :class="{ active: !$store.compactStore.useChatModel }" | |
| @click="$store.compactStore.useChatModel = false"> | |
| Utility | |
| </button> | |
| </div> | |
| </div> | |
| <div class="model-name" x-text="$store.compactStore.selectedModelDisplay"></div> | |
| </div> | |
| <template x-if="!$store.compactStore?.canCompact"> | |
| <div class="stats-info"> | |
| <span class="material-symbols-outlined">info</span> | |
| <span>Conversation is too short to compact (minimum 1,000 tokens).</span> | |
| </div> | |
| </template> | |
| <div class="stats-warning"> | |
| <span class="material-symbols-outlined">warning</span> | |
| <span>This action cannot be undone. The original conversation will be replaced with a summary.</span> | |
| </div> | |
| </div> | |
| </template> | |
| <template x-if="!$store.compactStore?.stats"> | |
| <div class="stats-loading"> | |
| <span class="loading-spinner"></span> | |
| <span>Loading statistics...</span> | |
| </div> | |
| </template> | |
| </div> | |
| <div class="modal-footer"> | |
| <button class="button secondary" @click="$store.compactStore?.closeModal()"> | |
| Cancel | |
| </button> | |
| <button | |
| class="button primary danger" | |
| @click="$store.compactStore?.compact()" | |
| :disabled="$store.compactStore?.compacting || !$store.compactStore?.canCompact" | |
| > | |
| <template x-if="$store.compactStore?.compacting"> | |
| <span class="loading-spinner"></span> | |
| </template> | |
| <span>Compact</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <style> | |
| .modal-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0, 0, 0, 0.5); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 1000; | |
| } | |
| .modal-container { | |
| background: var(--color-background-elevated); | |
| border-radius: var(--border-radius-md); | |
| box-shadow: var(--shadow-lg); | |
| width: 90%; | |
| max-width: 640px; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| } | |
| .modal-header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: var(--spacing-md) var(--spacing-lg); | |
| border-bottom: 1px solid var(--color-border); | |
| } | |
| .modal-header h3 { | |
| margin: 0; | |
| font-size: 1.1rem; | |
| font-weight: 600; | |
| } | |
| .modal-close { | |
| background: transparent; | |
| border: none; | |
| cursor: pointer; | |
| padding: var(--spacing-xs); | |
| border-radius: var(--border-radius-sm); | |
| color: var(--color-text-secondary); | |
| transition: color 0.2s; | |
| } | |
| .modal-close:hover { | |
| color: var(--color-text); | |
| } | |
| .modal-content { | |
| padding: var(--spacing-lg); | |
| } | |
| .stats-description { | |
| margin: 0 0 var(--spacing-md) 0; | |
| color: var(--color-text-secondary); | |
| font-size: 0.9rem; | |
| } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: var(--spacing-md); | |
| margin-bottom: var(--spacing-lg); | |
| } | |
| .stat-item { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| padding: var(--spacing-md); | |
| background: var(--color-background-muted); | |
| border-radius: var(--border-radius-md); | |
| } | |
| .stat-label { | |
| font-size: 0.75rem; | |
| color: var(--color-text-secondary); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| margin-bottom: var(--spacing-xs); | |
| } | |
| .stat-value { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| color: var(--color-text); | |
| } | |
| /* ── Model selection ── */ | |
| .model-section { | |
| margin-bottom: var(--spacing-lg); | |
| } | |
| .model-section-label { | |
| font-size: 0.75rem; | |
| color: var(--color-text-secondary); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| margin-bottom: var(--spacing-sm); | |
| } | |
| .model-controls { | |
| display: flex; | |
| gap: var(--spacing-sm); | |
| margin-bottom: var(--spacing-sm); | |
| } | |
| .compact-select { | |
| flex: 1; | |
| min-width: 0; | |
| padding: 6px 10px; | |
| border-radius: var(--border-radius-md); | |
| border: 1px solid var(--color-border); | |
| background: var(--color-background-muted); | |
| color: var(--color-text); | |
| font-size: 0.85rem; | |
| cursor: pointer; | |
| appearance: auto; | |
| } | |
| .compact-select:focus { | |
| outline: none; | |
| border-color: var(--color-primary, #3b82f6); | |
| } | |
| .model-type-toggle { | |
| display: flex; | |
| border-radius: var(--border-radius-md); | |
| border: 1px solid var(--color-border); | |
| overflow: hidden; | |
| flex-shrink: 0; | |
| } | |
| .model-type-toggle button { | |
| padding: 6px 14px; | |
| border: none; | |
| background: var(--color-background-muted); | |
| color: var(--color-text-secondary); | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.15s; | |
| } | |
| .model-type-toggle button:not(:last-child) { | |
| border-right: 1px solid var(--color-border); | |
| } | |
| .model-type-toggle button.active { | |
| background: var(--color-primary, #3b82f6); | |
| color: white; | |
| } | |
| .model-type-toggle button:hover:not(.active) { | |
| background: var(--color-background-hover); | |
| } | |
| .model-name { | |
| font-size: 0.85rem; | |
| color: var(--color-text); | |
| opacity: 0.7; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .stats-info { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: var(--spacing-sm); | |
| padding: var(--spacing-md); | |
| margin-bottom: var(--spacing-md); | |
| background: var(--color-info-bg, rgba(59, 130, 246, 0.1)); | |
| border: 1px solid var(--color-info-border, rgba(59, 130, 246, 0.3)); | |
| border-radius: var(--border-radius-md); | |
| color: var(--color-info-text, #1e40af); | |
| font-size: 0.85rem; | |
| } | |
| .stats-info .material-symbols-outlined { | |
| font-size: 1.2rem; | |
| flex-shrink: 0; | |
| } | |
| .stats-warning { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: var(--spacing-sm); | |
| padding: var(--spacing-md); | |
| background: var(--color-warning-bg, rgba(245, 158, 11, 0.1)); | |
| border: 1px solid var(--color-warning-border, rgba(245, 158, 11, 0.3)); | |
| border-radius: var(--border-radius-md); | |
| color: var(--color-warning-text, #92400e); | |
| font-size: 0.85rem; | |
| } | |
| .stats-warning .material-symbols-outlined { | |
| font-size: 1.2rem; | |
| flex-shrink: 0; | |
| } | |
| .stats-loading { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: var(--spacing-sm); | |
| padding: var(--spacing-xl); | |
| color: var(--color-text-secondary); | |
| } | |
| .modal-footer { | |
| display: flex; | |
| justify-content: flex-end; | |
| gap: var(--spacing-sm); | |
| padding: var(--spacing-md) var(--spacing-lg); | |
| border-top: 1px solid var(--color-border); | |
| } | |
| .button { | |
| padding: var(--spacing-sm) var(--spacing-md); | |
| border-radius: var(--border-radius-md); | |
| font-size: 0.9rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: var(--spacing-xs); | |
| } | |
| .button:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| .button.secondary { | |
| background: var(--color-background-muted); | |
| border: 1px solid var(--color-border); | |
| color: var(--color-text); | |
| } | |
| .button.secondary:hover:not(:disabled) { | |
| background: var(--color-background-hover); | |
| } | |
| .button.primary { | |
| background: var(--color-primary); | |
| border: none; | |
| color: white; | |
| } | |
| .button.primary:hover:not(:disabled) { | |
| background: var(--color-primary-hover); | |
| } | |
| .button.danger { | |
| background: var(--color-danger, #dc2626); | |
| } | |
| .button.danger:hover:not(:disabled) { | |
| background: var(--color-danger-hover, #b91c1c); | |
| } | |
| .loading-spinner { | |
| width: 16px; | |
| height: 16px; | |
| border: 2px solid currentColor; | |
| border-top-color: transparent; | |
| border-radius: 50%; | |
| animation: spin 0.8s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| </style> | |
| <script type="module"> | |
| import { store } from "/plugins/_chat_compaction/webui/compact-store.js"; | |
| </script> | |
| </body> | |
| </html> | |