]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/blob
7e79ab2309b0c1f618575666500b011685f7e902
[pkg/ggml/sources/llama.cpp] /
1 <script lang="ts">
2 import {
3 ChatMessageActionIcons,
4 ChatMessageEditForm,
5 ChatMessageStatistics,
6 ChatMessageUserBubble
7 } from '$lib/components/app/chat';
8 import { getMessageEditContext } from '$lib/contexts';
9 import { ChatMessageStatisticsMode, MessageRole } from '$lib/enums';
10 import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';
11 import { isLoading } from '$lib/stores/chat.svelte';
12 import { config } from '$lib/stores/settings.svelte';
13
14 interface Props {
15 class?: string;
16 message: DatabaseMessage;
17 siblingInfo?: ChatMessageSiblingInfo | null;
18 deletionInfo: {
19 totalCount: number;
20 userMessages: number;
21 assistantMessages: number;
22 messageTypes: string[];
23 } | null;
24 isLastUserMessage?: boolean;
25 nextAssistantMessage?: DatabaseMessage | null;
26 showDeleteDialog: boolean;
27 onEdit: () => void;
28 onDelete: () => void;
29 onConfirmDelete: () => void;
30 onForkConversation?: (options: { name: string; includeAttachments: boolean }) => void;
31 onShowDeleteDialogChange: (show: boolean) => void;
32 onNavigateToSibling?: (siblingId: string) => void;
33 onCopy: () => void;
34 }
35
36 let {
37 class: className = '',
38 deletionInfo,
39 isLastUserMessage = false,
40 message,
41 nextAssistantMessage = null,
42 onConfirmDelete,
43 onCopy,
44 onDelete,
45 onEdit,
46 onForkConversation,
47 onNavigateToSibling,
48 onShowDeleteDialogChange,
49 showDeleteDialog,
50 siblingInfo = null
51 }: Props = $props();
52
53 // Get contexts
54 const editCtx = getMessageEditContext();
55 const processingState = useProcessingState();
56
57 const currentConfig = $derived(config());
58 const isActivelyProcessing = $derived(isLastUserMessage && isLoading());
59
60 // For agentic turns, prefer the cumulative agentic.llm totals over per-call timings.
61 let storedReadingStats = $derived.by(() => {
62 const timings = nextAssistantMessage?.timings;
63
64 if (!timings?.prompt_n || !timings?.prompt_ms) return null;
65
66 const agentic = timings.agentic;
67
68 return {
69 promptMs: agentic ? agentic.llm.prompt_ms : timings.prompt_ms,
70 promptTokens: agentic ? agentic.llm.prompt_n : timings.prompt_n
71 };
72 });
73
74 let showStoredReadingStats = $derived(
75 Boolean(currentConfig.showMessageStats) && storedReadingStats !== null
76 );
77
78 let showLiveReadingStats = $derived(
79 Boolean(currentConfig.showMessageStats) && isActivelyProcessing && storedReadingStats === null
80 );
81
82 $effect(() => {
83 if (showLiveReadingStats) {
84 processingState.startMonitoring();
85 }
86 });
87 </script>
88
89 <div
90 aria-label="User message with actions"
91 class="chat-message-user group flex flex-col items-end gap-3 md:gap-2 {className}"
92 role="group"
93 >
94 {#if editCtx.isEditing}
95 <ChatMessageEditForm />
96 {:else}
97 <ChatMessageUserBubble
98 content={message.content}
99 attachments={message.extra}
100 renderMarkdown={true}
101 />
102
103 {#if showStoredReadingStats}
104 <!-- Reading stats sourced from the assistant message that followed this turn -->
105 <div class="info my-2 grid w-full justify-items-end gap-4 tabular-nums">
106 <div
107 class="inline-flex flex-wrap items-start justify-end gap-2 text-xs text-muted-foreground"
108 >
109 <ChatMessageStatistics
110 mode={ChatMessageStatisticsMode.READING}
111 promptTokens={storedReadingStats!.promptTokens}
112 promptMs={storedReadingStats!.promptMs}
113 />
114 </div>
115 </div>
116 {:else if showLiveReadingStats}
117 {@const liveStats = processingState.getLiveProcessingStats()}
118 {#if liveStats}
119 <div class="info my-2 grid w-full justify-items-end gap-4 tabular-nums">
120 <div
121 class="inline-flex flex-wrap items-start justify-end gap-2 text-xs text-muted-foreground"
122 >
123 <ChatMessageStatistics
124 mode={ChatMessageStatisticsMode.READING}
125 isLive
126 promptTokens={liveStats.tokensProcessed}
127 promptMs={liveStats.timeMs}
128 />
129 </div>
130 </div>
131 {/if}
132 {/if}
133
134 {#if message.timestamp}
135 <div class="max-w-[80%]">
136 <ChatMessageActionIcons
137 actionsPosition="right"
138 {deletionInfo}
139 justify="end"
140 {onConfirmDelete}
141 {onCopy}
142 {onDelete}
143 {onEdit}
144 {onForkConversation}
145 {onNavigateToSibling}
146 {onShowDeleteDialogChange}
147 {siblingInfo}
148 {showDeleteDialog}
149 role={MessageRole.USER}
150 />
151 </div>
152 {/if}
153 {/if}
154 </div>