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