forked from open-webui/open-webui
		
	refac: response message
This commit is contained in:
		
							parent
							
								
									1abe5a5487
								
							
						
					
					
						commit
						e758855590
					
				
					 2 changed files with 67 additions and 72 deletions
				
			
		
							
								
								
									
										36
									
								
								src/lib/components/chat/Messages/CodeBlock.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/lib/components/chat/Messages/CodeBlock.svelte
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| <script lang="ts"> | ||||
| 	import { copyToClipboard } from '$lib/utils'; | ||||
| 	import hljs from 'highlight.js'; | ||||
| 	import 'highlight.js/styles/github-dark.min.css'; | ||||
| 
 | ||||
| 	export let lang = ''; | ||||
| 	export let code = ''; | ||||
| 
 | ||||
| 	let copied = false; | ||||
| 
 | ||||
| 	const copyCode = async () => { | ||||
| 		copied = true; | ||||
| 		await copyToClipboard(code); | ||||
| 
 | ||||
| 		setTimeout(() => { | ||||
| 			copied = false; | ||||
| 		}, 1000); | ||||
| 	}; | ||||
| 
 | ||||
| 	$: highlightedCode = code ? hljs.highlightAuto(code, hljs.getLanguage(lang)?.aliases).value : ''; | ||||
| </script> | ||||
| 
 | ||||
| <div class="mb-3"> | ||||
| 	<div | ||||
| 		class="flex justify-between bg-[#202123] text-white text-xs px-4 pt-1 rounded-t-lg overflow-x-auto" | ||||
| 	> | ||||
| 		<div class="p-1">{lang}</div> | ||||
| 		<button class="copy-code-button bg-none border-none p-1" on:click={copyCode} | ||||
| 			>{copied ? 'Copied' : 'Copy Code'}</button | ||||
| 		> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<pre class=" rounded-b-lg hljs p-4 overflow-x-auto rounded-t-none"><code | ||||
| 			class="language-{lang} rounded-t-none whitespace-pre">{@html highlightedCode || code}</code | ||||
| 		></pre> | ||||
| </div> | ||||
|  | @ -1,17 +1,16 @@ | |||
| <script lang="ts"> | ||||
| 	import dayjs from 'dayjs'; | ||||
| 	import { marked } from 'marked'; | ||||
| 
 | ||||
| 	import tippy from 'tippy.js'; | ||||
| 	import hljs from 'highlight.js'; | ||||
| 	import 'highlight.js/styles/github-dark.min.css'; | ||||
| 	import auto_render from 'katex/dist/contrib/auto-render.mjs'; | ||||
| 	import 'katex/dist/katex.min.css'; | ||||
| 
 | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 
 | ||||
| 	import Name from './Name.svelte'; | ||||
| 	import ProfileImage from './ProfileImage.svelte'; | ||||
| 	import Skeleton from './Skeleton.svelte'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import CodeBlock from './CodeBlock.svelte'; | ||||
| 
 | ||||
| 	export let modelfiles = []; | ||||
| 	export let message; | ||||
|  | @ -33,6 +32,20 @@ | |||
| 	let tooltipInstance = null; | ||||
| 	let speaking = null; | ||||
| 
 | ||||
| 	$: tokens = marked.lexer(message.content); | ||||
| 
 | ||||
| 	const renderer = new marked.Renderer(); | ||||
| 
 | ||||
| 	// For code blocks with simple backticks | ||||
| 	renderer.codespan = (code) => { | ||||
| 		return `<code>${code.replaceAll('&', '&')}</code>`; | ||||
| 	}; | ||||
| 
 | ||||
| 	const { extensions, ...defaults } = marked.getDefaults() as marked.MarkedOptions & { | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||
| 		extensions: any; | ||||
| 	}; | ||||
| 
 | ||||
| 	$: if (message) { | ||||
| 		renderStyling(); | ||||
| 	} | ||||
|  | @ -45,8 +58,6 @@ | |||
| 		} | ||||
| 
 | ||||
| 		renderLatex(); | ||||
| 		hljs.highlightAll(); | ||||
| 		createCopyCodeBlockButton(); | ||||
| 
 | ||||
| 		if (message.info) { | ||||
| 			tooltipInstance = tippy(`#info-${message.id}`, { | ||||
|  | @ -78,71 +89,6 @@ | |||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	const createCopyCodeBlockButton = () => { | ||||
| 		// use a class selector if available | ||||
| 		let blocks = document.querySelectorAll('pre'); | ||||
| 
 | ||||
| 		blocks.forEach((block) => { | ||||
| 			// only add button if browser supports Clipboard API | ||||
| 
 | ||||
| 			if (block.childNodes.length < 2 && block.id !== 'user-message') { | ||||
| 				let code = block.querySelector('code'); | ||||
| 				code.style.borderTopRightRadius = 0; | ||||
| 				code.style.borderTopLeftRadius = 0; | ||||
| 				code.style.whiteSpace = 'pre'; | ||||
| 
 | ||||
| 				let topBarDiv = document.createElement('div'); | ||||
| 				topBarDiv.style.backgroundColor = '#202123'; | ||||
| 				topBarDiv.style.overflowX = 'auto'; | ||||
| 				topBarDiv.style.display = 'flex'; | ||||
| 				topBarDiv.style.justifyContent = 'space-between'; | ||||
| 				topBarDiv.style.padding = '0 1rem'; | ||||
| 				topBarDiv.style.paddingTop = '4px'; | ||||
| 				topBarDiv.style.borderTopRightRadius = '8px'; | ||||
| 				topBarDiv.style.borderTopLeftRadius = '8px'; | ||||
| 
 | ||||
| 				let langDiv = document.createElement('div'); | ||||
| 
 | ||||
| 				let codeClassNames = code?.className.split(' '); | ||||
| 				langDiv.textContent = | ||||
| 					codeClassNames[0] === 'hljs' ? codeClassNames[1].slice(9) : codeClassNames[0].slice(9); | ||||
| 				langDiv.style.color = 'white'; | ||||
| 				langDiv.style.margin = '4px'; | ||||
| 				langDiv.style.fontSize = '0.75rem'; | ||||
| 
 | ||||
| 				let button = document.createElement('button'); | ||||
| 				button.className = 'copy-code-button'; | ||||
| 				button.textContent = 'Copy Code'; | ||||
| 				button.style.background = 'none'; | ||||
| 				button.style.fontSize = '0.75rem'; | ||||
| 				button.style.border = 'none'; | ||||
| 				button.style.margin = '4px'; | ||||
| 				button.style.cursor = 'pointer'; | ||||
| 				button.style.color = '#ddd'; | ||||
| 				button.addEventListener('click', () => copyCode(block, button)); | ||||
| 
 | ||||
| 				topBarDiv.appendChild(langDiv); | ||||
| 				topBarDiv.appendChild(button); | ||||
| 
 | ||||
| 				block.prepend(topBarDiv); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		async function copyCode(block, button) { | ||||
| 			let code = block.querySelector('code'); | ||||
| 			let text = code.innerText; | ||||
| 
 | ||||
| 			await copyToClipboard(text); | ||||
| 
 | ||||
| 			// visual feedback that task is completed | ||||
| 			button.innerText = 'Copied!'; | ||||
| 
 | ||||
| 			setTimeout(() => { | ||||
| 				button.innerText = 'Copy Code'; | ||||
| 			}, 1000); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	const renderLatex = () => { | ||||
| 		let chatMessageElements = document.getElementsByClassName('chat-assistant'); | ||||
| 		// let lastChatMessageElement = chatMessageElements[chatMessageElements.length - 1]; | ||||
|  | @ -292,7 +238,20 @@ | |||
| 									</div> | ||||
| 								</div> | ||||
| 							{:else} | ||||
| 								{@html marked(message.content.replaceAll('\\', '\\\\'))} | ||||
| 								{#each tokens as token} | ||||
| 									{#if token.type === 'code'} | ||||
| 										<CodeBlock lang={token.lang} code={token.text} /> | ||||
| 									{:else} | ||||
| 										<!-- eslint-disable-next-line svelte/no-at-html-tags --> | ||||
| 										{@html marked.parse(token.raw, { | ||||
| 											...defaults, | ||||
| 											gfm: true, | ||||
| 											breaks: true, | ||||
| 											renderer | ||||
| 										})} | ||||
| 									{/if} | ||||
| 								{/each} | ||||
| 								<!-- {@html marked(message.content.replaceAll('\\', '\\\\'))} --> | ||||
| 							{/if} | ||||
| 
 | ||||
| 							{#if message.done} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek