Browse Source

feat: mermaid rendering support

Timothy J. Baek 11 months ago
parent
commit
3d74c04f50

+ 2 - 0
backend/main.py

@@ -498,6 +498,8 @@ async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
     ]
     ]
     sorted_filters = sorted(filters, key=lambda x: x["pipeline"]["priority"])
     sorted_filters = sorted(filters, key=lambda x: x["pipeline"]["priority"])
 
 
+    print(model_id)
+
     if model_id in app.state.MODELS:
     if model_id in app.state.MODELS:
         model = app.state.MODELS[model_id]
         model = app.state.MODELS[model_id]
         if "pipeline" in model:
         if "pipeline" in model:

File diff suppressed because it is too large
+ 1052 - 1
package-lock.json


+ 1 - 0
package.json

@@ -63,6 +63,7 @@
 		"js-sha256": "^0.10.1",
 		"js-sha256": "^0.10.1",
 		"katex": "^0.16.9",
 		"katex": "^0.16.9",
 		"marked": "^9.1.0",
 		"marked": "^9.1.0",
+		"mermaid": "^10.9.1",
 		"pyodide": "^0.26.0-alpha.4",
 		"pyodide": "^0.26.0-alpha.4",
 		"sortablejs": "^1.15.2",
 		"sortablejs": "^1.15.2",
 		"svelte-sonner": "^0.3.19",
 		"svelte-sonner": "^0.3.19",

+ 36 - 52
src/lib/components/chat/Chat.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
 	import { v4 as uuidv4 } from 'uuid';
 	import { v4 as uuidv4 } from 'uuid';
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
+	import mermaid from 'mermaid';
 
 
 	import { getContext, onMount, tick } from 'svelte';
 	import { getContext, onMount, tick } from 'svelte';
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
@@ -246,6 +247,39 @@
 		}
 		}
 	};
 	};
 
 
+	const chatCompletedHandler = async (model, messages) => {
+		await mermaid.run({
+			querySelector: '.mermaid'
+		});
+
+		const res = await chatCompleted(localStorage.token, {
+			model: model.id,
+			messages: messages.map((m) => ({
+				id: m.id,
+				role: m.role,
+				content: m.content,
+				timestamp: m.timestamp
+			})),
+			chat_id: $chatId
+		}).catch((error) => {
+			console.error(error);
+			return null;
+		});
+
+		if (res !== null) {
+			// Update chat history with the new messages
+			for (const message of res.messages) {
+				history.messages[message.id] = {
+					...history.messages[message.id],
+					...(history.messages[message.id].content !== message.content
+						? { originalContent: history.messages[message.id].content }
+						: {}),
+					...message
+				};
+			}
+		}
+	};
+
 	//////////////////////////
 	//////////////////////////
 	// Ollama functions
 	// Ollama functions
 	//////////////////////////
 	//////////////////////////
@@ -613,32 +647,7 @@
 						controller.abort('User: Stop Response');
 						controller.abort('User: Stop Response');
 					} else {
 					} else {
 						const messages = createMessagesList(responseMessageId);
 						const messages = createMessagesList(responseMessageId);
-						const res = await chatCompleted(localStorage.token, {
-							model: model,
-							messages: messages.map((m) => ({
-								id: m.id,
-								role: m.role,
-								content: m.content,
-								timestamp: m.timestamp
-							})),
-							chat_id: $chatId
-						}).catch((error) => {
-							console.error(error);
-							return null;
-						});
-
-						if (res !== null) {
-							// Update chat history with the new messages
-							for (const message of res.messages) {
-								history.messages[message.id] = {
-									...history.messages[message.id],
-									...(history.messages[message.id].content !== message.content
-										? { originalContent: history.messages[message.id].content }
-										: {}),
-									...message
-								};
-							}
-						}
+						await chatCompletedHandler(model, messages);
 					}
 					}
 
 
 					break;
 					break;
@@ -893,32 +902,7 @@
 						} else {
 						} else {
 							const messages = createMessagesList(responseMessageId);
 							const messages = createMessagesList(responseMessageId);
 
 
-							const res = await chatCompleted(localStorage.token, {
-								model: model.id,
-								messages: messages.map((m) => ({
-									id: m.id,
-									role: m.role,
-									content: m.content,
-									timestamp: m.timestamp
-								})),
-								chat_id: $chatId
-							}).catch((error) => {
-								console.error(error);
-								return null;
-							});
-
-							if (res !== null) {
-								// Update chat history with the new messages
-								for (const message of res.messages) {
-									history.messages[message.id] = {
-										...history.messages[message.id],
-										...(history.messages[message.id].content !== message.content
-											? { originalContent: history.messages[message.id].content }
-											: {}),
-										...message
-									};
-								}
-							}
+							await chatCompletedHandler(model, messages);
 						}
 						}
 
 
 						break;
 						break;

+ 1 - 2
src/lib/components/chat/Messages.svelte

@@ -1,8 +1,7 @@
 <script lang="ts">
 <script lang="ts">
 	import { v4 as uuidv4 } from 'uuid';
 	import { v4 as uuidv4 } from 'uuid';
-
 	import { chats, config, settings, user as _user, mobile } from '$lib/stores';
 	import { chats, config, settings, user as _user, mobile } from '$lib/stores';
-	import { tick, getContext } from 'svelte';
+	import { tick, getContext, onMount } from 'svelte';
 
 
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
 	import { getChatList, updateChatById } from '$lib/apis/chats';
 	import { getChatList, updateChatById } from '$lib/apis/chats';

+ 14 - 5
src/lib/components/chat/Messages/ResponseMessage.svelte

@@ -5,6 +5,7 @@
 	import tippy from 'tippy.js';
 	import tippy from 'tippy.js';
 	import auto_render from 'katex/dist/contrib/auto-render.mjs';
 	import auto_render from 'katex/dist/contrib/auto-render.mjs';
 	import 'katex/dist/katex.min.css';
 	import 'katex/dist/katex.min.css';
+	import mermaid from 'mermaid';
 
 
 	import { fade } from 'svelte/transition';
 	import { fade } from 'svelte/transition';
 	import { createEventDispatcher } from 'svelte';
 	import { createEventDispatcher } from 'svelte';
@@ -343,6 +344,10 @@
 	onMount(async () => {
 	onMount(async () => {
 		await tick();
 		await tick();
 		renderStyling();
 		renderStyling();
+
+		await mermaid.run({
+			querySelector: '.mermaid'
+		});
 	});
 	});
 </script>
 </script>
 
 
@@ -458,11 +463,15 @@
 								<!-- unless message.error === true which is legacy error handling, where the error message is stored in message.content -->
 								<!-- unless message.error === true which is legacy error handling, where the error message is stored in message.content -->
 								{#each tokens as token, tokenIdx}
 								{#each tokens as token, tokenIdx}
 									{#if token.type === 'code'}
 									{#if token.type === 'code'}
-										<CodeBlock
-											id={`${message.id}-${tokenIdx}`}
-											lang={token?.lang ?? ''}
-											code={revertSanitizedResponseContent(token?.text ?? '')}
-										/>
+										{#if token.lang === 'mermaid'}
+											<pre class="mermaid">{revertSanitizedResponseContent(token.text)}</pre>
+										{:else}
+											<CodeBlock
+												id={`${message.id}-${tokenIdx}`}
+												lang={token?.lang ?? ''}
+												code={revertSanitizedResponseContent(token?.text ?? '')}
+											/>
+										{/if}
 									{:else}
 									{:else}
 										{@html marked.parse(token.raw, {
 										{@html marked.parse(token.raw, {
 											...defaults,
 											...defaults,

Some files were not shown because too many files changed in this diff