15
15
<!-- sidebar -->
16
16
< div class ="drawer-side h-screen lg:h-screen z-50 lg:max-w-64 ">
17
17
< 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 ">
19
19
< div class ="flex flex-row items-center justify-between mb-4 mt-4 ">
20
20
< h2 class ="font-bold ml-4 "> Conversations</ h2 >
21
21
@@ -120,51 +120,25 @@ <h2 class="font-bold ml-4">Conversations</h2>
120
120
{{ messages.length === 0 ? 'Send a message to start' : '' }}
121
121
</ div >
122
122
< 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 >
160
130
</ div >
161
131
162
132
<!-- 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 >
168
142
</ div >
169
143
</ div >
170
144
@@ -227,6 +201,10 @@ <h3 class="text-lg font-bold mb-6">Settings</h3>
227
201
< details class ="collapse collapse-arrow bg-base-200 mb-2 overflow-visible ">
228
202
< summary class ="collapse-title font-bold "> Advanced config</ summary >
229
203
< 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 >
230
208
< label class ="form-control mb-2 ">
231
209
<!-- Custom parameters input -->
232
210
< 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>
247
225
248
226
</ div >
249
227
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
+
250
288
<!-- Template to be used by settings modal -->
251
289
< template id ="settings-modal-short-input ">
252
290
< label class ="input input-bordered join-item grow flex items-center gap-2 mb-2 ">
0 commit comments