Skip to content

Commit 235f6e1

Browse files
authored
server : (UI) add tok/s, get rid of completion.js (ggml-org#10786)
* get rid of completion.js * extract chat bubble to a component * add tok/s info * sync * fix BASE_URL * only extract timings when it's enabled * fix auto scroll
1 parent 1a31d0d commit 235f6e1

File tree

6 files changed

+307
-376
lines changed

6 files changed

+307
-376
lines changed

examples/server/public/index.html

Lines changed: 118 additions & 80 deletions
Large diffs are not rendered by default.

examples/server/webui/index.html

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<!-- sidebar -->
1616
<div class="drawer-side h-screen lg:h-screen z-50 lg:max-w-64">
1717
<label for="toggle-drawer" aria-label="close sidebar" class="drawer-overlay"></label>
18-
<div class="flex flex-col bg-base-200 min-h-full max-w-[calc(100vw-2em)] py-4 px-4">
18+
<div class="flex flex-col bg-base-200 min-h-full max-w-64 py-4 px-4">
1919
<div class="flex flex-row items-center justify-between mb-4 mt-4">
2020
<h2 class="font-bold ml-4">Conversations</h2>
2121

@@ -120,51 +120,25 @@ <h2 class="font-bold ml-4">Conversations</h2>
120120
{{ messages.length === 0 ? 'Send a message to start' : '' }}
121121
</div>
122122
<div v-for="msg in messages" class="group">
123-
<div :class="{
124-
'chat': true,
125-
'chat-start': msg.role !== 'user',
126-
'chat-end': msg.role === 'user',
127-
}">
128-
<div :class="{
129-
'chat-bubble markdown': true,
130-
'chat-bubble-base-300': msg.role !== 'user',
131-
}">
132-
<!-- textarea for editing message -->
133-
<template v-if="editingMsg && editingMsg.id === msg.id">
134-
<textarea
135-
class="textarea textarea-bordered bg-base-100 text-base-content w-[calc(90vw-8em)] lg:w-96"
136-
v-model="msg.content"></textarea>
137-
<br/>
138-
<button class="btn btn-ghost mt-2 mr-2" @click="editingMsg = null">Cancel</button>
139-
<button class="btn mt-2" @click="editUserMsgAndRegenerate(msg)">Submit</button>
140-
</template>
141-
<!-- render message as markdown -->
142-
<vue-markdown v-else :source="msg.content" />
143-
</div>
144-
</div>
145-
146-
<!-- actions for each message -->
147-
<div :class="{'text-right': msg.role === 'user'}" class="mx-4 mt-2 mb-2">
148-
<!-- user message -->
149-
<button v-if="msg.role === 'user'" class="badge btn-mini show-on-hover" @click="editingMsg = msg" :disabled="isGenerating">
150-
✍️ Edit
151-
</button>
152-
<!-- assistant message -->
153-
<button v-if="msg.role === 'assistant'" class="badge btn-mini show-on-hover mr-2" @click="regenerateMsg(msg)" :disabled="isGenerating">
154-
🔄 Regenerate
155-
</button>
156-
<button v-if="msg.role === 'assistant'" class="badge btn-mini show-on-hover mr-2" @click="copyMsg(msg)" :disabled="isGenerating">
157-
📋 Copy
158-
</button>
159-
</div>
123+
<message-bubble
124+
:config="config"
125+
:msg="msg"
126+
:key="msg.id"
127+
:is-generating="isGenerating"
128+
:edit-user-msg-and-regenerate="editUserMsgAndRegenerate"
129+
:regenerate-msg="regenerateMsg"></message-bubble>
160130
</div>
161131

162132
<!-- pending (ongoing) assistant message -->
163-
<div id="pending-msg" class="chat chat-start">
164-
<div v-if="pendingMsg" class="chat-bubble markdown chat-bubble-base-300">
165-
<span v-if="!pendingMsg.content" class="loading loading-dots loading-md"></span>
166-
<vue-markdown v-else :source="pendingMsg.content" />
167-
</div>
133+
<div id="pending-msg" class="group">
134+
<message-bubble
135+
v-if="pendingMsg"
136+
:config="config"
137+
:msg="pendingMsg"
138+
:key="pendingMsg.id"
139+
:is-generating="isGenerating"
140+
:edit-user-msg-and-regenerate="() => {}"
141+
:regenerate-msg="() => {}"></message-bubble>
168142
</div>
169143
</div>
170144

@@ -227,6 +201,10 @@ <h3 class="text-lg font-bold mb-6">Settings</h3>
227201
<details class="collapse collapse-arrow bg-base-200 mb-2 overflow-visible">
228202
<summary class="collapse-title font-bold">Advanced config</summary>
229203
<div class="collapse-content">
204+
<div class="flex flex-row items-center mb-2">
205+
<input type="checkbox" class="checkbox" v-model="config.showTokensPerSecond" />
206+
<span class="ml-4">Show tokens per second</span>
207+
</div>
230208
<label class="form-control mb-2">
231209
<!-- Custom parameters input -->
232210
<div class="label inline">Custom JSON config (For more info, refer to <a class="underline" href="https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md" target="_blank" rel="noopener noreferrer">server documentation</a>)</div>
@@ -247,6 +225,66 @@ <h3 class="text-lg font-bold mb-6">Settings</h3>
247225

248226
</div>
249227

228+
229+
<!-- Template to be used as message bubble -->
230+
<template id="message-bubble">
231+
<div :class="{
232+
'chat': true,
233+
'chat-start': msg.role !== 'user',
234+
'chat-end': msg.role === 'user',
235+
}">
236+
<div :class="{
237+
'chat-bubble markdown': true,
238+
'chat-bubble-base-300': msg.role !== 'user',
239+
}">
240+
<!-- textarea for editing message -->
241+
<template v-if="editingContent !== null">
242+
<textarea
243+
class="textarea textarea-bordered bg-base-100 text-base-content w-[calc(90vw-8em)] lg:w-96"
244+
v-model="editingContent"></textarea>
245+
<br/>
246+
<button class="btn btn-ghost mt-2 mr-2" @click="editingContent = null">Cancel</button>
247+
<button class="btn mt-2" @click="editMsg()">Submit</button>
248+
</template>
249+
<template v-else>
250+
<!-- show loading dots for pending message -->
251+
<span v-if="msg.content === null" class="loading loading-dots loading-md"></span>
252+
<!-- render message as markdown -->
253+
<vue-markdown v-else :source="msg.content"></vue-markdown>
254+
<!-- render timings if enabled -->
255+
<div class="dropdown dropdown-hover dropdown-top mt-2" v-if="timings && config.showTokensPerSecond">
256+
<div tabindex="0" role="button" class="cursor-pointer font-semibold text-sm opacity-60">Speed: {{ timings.predicted_per_second.toFixed(1) }} t/s</div>
257+
<div class="dropdown-content bg-base-100 z-10 w-64 p-2 shadow mt-4">
258+
<b>Prompt</b><br/>
259+
- Tokens: {{ timings.prompt_n }}<br/>
260+
- Time: {{ timings.prompt_ms }} ms<br/>
261+
- Speed: {{ timings.prompt_per_second.toFixed(1) }} t/s<br/>
262+
<b>Generation</b><br/>
263+
- Tokens: {{ timings.predicted_n }}<br/>
264+
- Time: {{ timings.predicted_ms }} ms<br/>
265+
- Speed: {{ timings.predicted_per_second.toFixed(1) }} t/s<br/>
266+
</div>
267+
</div>
268+
</template>
269+
</div>
270+
</div>
271+
<!-- actions for each message -->
272+
<div :class="{'text-right': msg.role === 'user', 'opacity-0': isGenerating}" class="mx-4 mt-2 mb-2">
273+
<!-- user message -->
274+
<button v-if="msg.role === 'user'" class="badge btn-mini show-on-hover" @click="editingContent = msg.content" :disabled="isGenerating">
275+
✍️ Edit
276+
</button>
277+
<!-- assistant message -->
278+
<button v-if="msg.role === 'assistant'" class="badge btn-mini show-on-hover mr-2" @click="regenerateMsg(msg)" :disabled="isGenerating">
279+
🔄 Regenerate
280+
</button>
281+
<button v-if="msg.role === 'assistant'" class="badge btn-mini show-on-hover mr-2" @click="copyMsg()" :disabled="isGenerating">
282+
📋 Copy
283+
</button>
284+
</div>
285+
</template>
286+
287+
250288
<!-- Template to be used by settings modal -->
251289
<template id="settings-modal-short-input">
252290
<label class="input input-bordered join-item grow flex items-center gap-2 mb-2">

examples/server/webui/package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/server/webui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"markdown-it": "^14.1.0",
1818
"postcss": "^8.4.49",
1919
"tailwindcss": "^3.4.15",
20+
"textlinestream": "^1.1.1",
2021
"vite-plugin-singlefile": "^2.0.3",
2122
"vue": "^3.5.13"
2223
}

0 commit comments

Comments
 (0)