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 ">
0 commit comments