| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- <script lang="ts">
- import { PROCESSING_INFO_TIMEOUT } from '$lib/constants/processing-info';
- import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';
- import { slotsService } from '$lib/services/slots';
- import { isLoading, activeMessages, activeConversation } from '$lib/stores/chat.svelte';
- import { config } from '$lib/stores/settings.svelte';
- const processingState = useProcessingState();
- let isCurrentConversationLoading = $derived(isLoading());
- let processingDetails = $derived(processingState.getProcessingDetails());
- let showSlotsInfo = $derived(isCurrentConversationLoading || config().keepStatsVisible);
- // Track loading state reactively by checking if conversation ID is in loading conversations array
- $effect(() => {
- const keepStatsVisible = config().keepStatsVisible;
- if (keepStatsVisible || isCurrentConversationLoading) {
- processingState.startMonitoring();
- }
- if (!isCurrentConversationLoading && !keepStatsVisible) {
- setTimeout(() => {
- if (!config().keepStatsVisible) {
- processingState.stopMonitoring();
- }
- }, PROCESSING_INFO_TIMEOUT);
- }
- });
- // Update processing state from stored timings
- $effect(() => {
- const conversation = activeConversation();
- const messages = activeMessages() as DatabaseMessage[];
- const keepStatsVisible = config().keepStatsVisible;
- if (keepStatsVisible && conversation) {
- if (messages.length === 0) {
- slotsService.clearConversationState(conversation.id);
- return;
- }
- // Search backwards through messages to find most recent assistant message with timing data
- // Using reverse iteration for performance - avoids array copy and stops at first match
- let foundTimingData = false;
- for (let i = messages.length - 1; i >= 0; i--) {
- const message = messages[i];
- if (message.role === 'assistant' && message.timings) {
- foundTimingData = true;
- slotsService
- .updateFromTimingData(
- {
- prompt_n: message.timings.prompt_n || 0,
- predicted_n: message.timings.predicted_n || 0,
- predicted_per_second:
- message.timings.predicted_n && message.timings.predicted_ms
- ? (message.timings.predicted_n / message.timings.predicted_ms) * 1000
- : 0,
- cache_n: message.timings.cache_n || 0
- },
- conversation.id
- )
- .catch((error) => {
- console.warn('Failed to update processing state from stored timings:', error);
- });
- break;
- }
- }
- if (!foundTimingData) {
- slotsService.clearConversationState(conversation.id);
- }
- }
- });
- </script>
- <div class="chat-processing-info-container pointer-events-none" class:visible={showSlotsInfo}>
- <div class="chat-processing-info-content">
- {#each processingDetails as detail (detail)}
- <span class="chat-processing-info-detail pointer-events-auto">{detail}</span>
- {/each}
- </div>
- </div>
- <style>
- .chat-processing-info-container {
- position: sticky;
- top: 0;
- z-index: 10;
- padding: 1.5rem 1rem;
- opacity: 0;
- transform: translateY(50%);
- transition:
- opacity 300ms ease-out,
- transform 300ms ease-out;
- }
- .chat-processing-info-container.visible {
- opacity: 1;
- transform: translateY(0);
- }
- .chat-processing-info-content {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 1rem;
- justify-content: center;
- max-width: 48rem;
- margin: 0 auto;
- }
- .chat-processing-info-detail {
- color: var(--muted-foreground);
- font-size: 0.75rem;
- padding: 0.25rem 0.75rem;
- background: var(--muted);
- border-radius: 0.375rem;
- font-family:
- ui-monospace, SFMono-Regular, 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;
- white-space: nowrap;
- }
- @media (max-width: 768px) {
- .chat-processing-info-content {
- gap: 0.5rem;
- }
- .chat-processing-info-detail {
- font-size: 0.7rem;
- padding: 0.2rem 0.5rem;
- }
- }
- </style>
|