Skip to content

Commit a28e3c7

Browse files
authored
webui: Stop generation from chat sidebar (ggml-org#17806)
* feat: Add stop generation button for Conversation Item * chore: update webui build output
1 parent e31b5c5 commit a28e3c7

File tree

4 files changed

+66
-7
lines changed

4 files changed

+66
-7
lines changed

tools/server/public/index.html.gz

344 Bytes
Binary file not shown.

tools/server/webui/src/lib/components/app/chat/ChatSidebar/ChatSidebar.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import * as AlertDialog from '$lib/components/ui/alert-dialog';
99
import Input from '$lib/components/ui/input/input.svelte';
1010
import { conversationsStore, conversations } from '$lib/stores/conversations.svelte';
11+
import { chatStore } from '$lib/stores/chat.svelte';
1112
import ChatSidebarActions from './ChatSidebarActions.svelte';
1213
1314
const sidebar = Sidebar.useSidebar();
@@ -98,6 +99,10 @@
9899
99100
await goto(`#/chat/${id}`);
100101
}
102+
103+
function handleStopGeneration(id: string) {
104+
chatStore.stopGenerationForChat(id);
105+
}
101106
</script>
102107

103108
<ScrollArea class="h-[100vh]">
@@ -132,6 +137,7 @@
132137
onSelect={selectConversation}
133138
onEdit={handleEditConversation}
134139
onDelete={handleDeleteConversation}
140+
onStop={handleStopGeneration}
135141
/>
136142
</Sidebar.MenuItem>
137143
{/each}

tools/server/webui/src/lib/components/app/chat/ChatSidebar/ChatSidebarConversationItem.svelte

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
2-
import { Trash2, Pencil, MoreHorizontal, Download, Loader2 } from '@lucide/svelte';
2+
import { Trash2, Pencil, MoreHorizontal, Download, Loader2, Square } from '@lucide/svelte';
33
import { ActionDropdown } from '$lib/components/app';
4+
import * as Tooltip from '$lib/components/ui/tooltip';
45
import { getAllLoadingChats } from '$lib/stores/chat.svelte';
56
import { conversationsStore } from '$lib/stores/conversations.svelte';
67
import { onMount } from 'svelte';
@@ -12,6 +13,7 @@
1213
onDelete?: (id: string) => void;
1314
onEdit?: (id: string) => void;
1415
onSelect?: (id: string) => void;
16+
onStop?: (id: string) => void;
1517
}
1618
1719
let {
@@ -20,6 +22,7 @@
2022
onDelete,
2123
onEdit,
2224
onSelect,
25+
onStop,
2326
isActive = false
2427
}: Props = $props();
2528
@@ -38,8 +41,14 @@
3841
onDelete?.(conversation.id);
3942
}
4043
44+
function handleStop(event: Event) {
45+
event.stopPropagation();
46+
onStop?.(conversation.id);
47+
}
48+
4149
function handleGlobalEditEvent(event: Event) {
4250
const customEvent = event as CustomEvent<{ conversationId: string }>;
51+
4352
if (customEvent.detail.conversationId === conversation.id && isActive) {
4453
handleEdit(event);
4554
}
@@ -88,8 +97,28 @@
8897
>
8998
<div class="flex min-w-0 flex-1 items-center gap-2">
9099
{#if isLoading}
91-
<Loader2 class="h-3.5 w-3.5 shrink-0 animate-spin text-muted-foreground" />
100+
<Tooltip.Root>
101+
<Tooltip.Trigger>
102+
<div
103+
class="stop-button flex h-4 w-4 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground"
104+
onclick={handleStop}
105+
onkeydown={(e) => e.key === 'Enter' && handleStop(e)}
106+
role="button"
107+
tabindex="0"
108+
aria-label="Stop generation"
109+
>
110+
<Loader2 class="loading-icon h-3.5 w-3.5 animate-spin" />
111+
112+
<Square class="stop-icon hidden h-3 w-3 fill-current text-destructive" />
113+
</div>
114+
</Tooltip.Trigger>
115+
116+
<Tooltip.Content>
117+
<p>Stop generation</p>
118+
</Tooltip.Content>
119+
</Tooltip.Root>
92120
{/if}
121+
93122
<!-- svelte-ignore a11y_click_events_have_key_events -->
94123
<!-- svelte-ignore a11y_no_static_element_interactions -->
95124
<span class="truncate text-sm font-medium" onclick={handleMobileSidebarItemClick}>
@@ -147,5 +176,25 @@
147176
opacity: 1 !important;
148177
}
149178
}
179+
180+
.stop-button {
181+
:global(.stop-icon) {
182+
display: none;
183+
}
184+
185+
:global(.loading-icon) {
186+
display: block;
187+
}
188+
}
189+
190+
&:is(:hover) .stop-button {
191+
:global(.stop-icon) {
192+
display: block;
193+
}
194+
195+
:global(.loading-icon) {
196+
display: none;
197+
}
198+
}
150199
}
151200
</style>

tools/server/webui/src/lib/stores/chat.svelte.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -701,13 +701,17 @@ class ChatStore {
701701

702702
if (!activeConv) return;
703703

704-
await this.savePartialResponseIfNeeded(activeConv.id);
704+
await this.stopGenerationForChat(activeConv.id);
705+
}
706+
707+
async stopGenerationForChat(convId: string): Promise<void> {
708+
await this.savePartialResponseIfNeeded(convId);
705709

706710
this.stopStreaming();
707-
this.abortRequest(activeConv.id);
708-
this.setChatLoading(activeConv.id, false);
709-
this.clearChatStreaming(activeConv.id);
710-
this.clearProcessingState(activeConv.id);
711+
this.abortRequest(convId);
712+
this.setChatLoading(convId, false);
713+
this.clearChatStreaming(convId);
714+
this.clearProcessingState(convId);
711715
}
712716

713717
/**

0 commit comments

Comments
 (0)