refac: message edit
Some checks are pending
Deploy to HuggingFace Spaces / check-secret (push) Waiting to run
Deploy to HuggingFace Spaces / deploy (push) Blocked by required conditions
Create and publish Docker images with specific build args / build-main-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-main-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / merge-main-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-cuda-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-ollama-images (push) Blocked by required conditions
Python CI / Format Backend (3.11) (push) Waiting to run
Frontend Build / Format & Build Frontend (push) Waiting to run
Frontend Build / Frontend Unit Tests (push) Waiting to run

This commit is contained in:
Timothy Jaeryang Baek 2025-04-03 13:43:45 -06:00
parent a1f3300767
commit be20e6dec0
2 changed files with 46 additions and 8 deletions

View File

@ -332,9 +332,37 @@
} }
}; };
let preprocessedDetailsCache = [];
function preprocessForEditing(content: string): string {
// Replace <details>...</details> with unique ID placeholder
const detailsBlocks = [];
let i = 0;
content = content.replace(/<details[\s\S]*?<\/details>/gi, (match) => {
detailsBlocks.push(match);
return `<details id="__DETAIL_${i++}__"/>`;
});
// Store original blocks in the editedContent or globally (see merging later)
preprocessedDetailsCache = detailsBlocks;
return content;
}
function postprocessAfterEditing(content: string): string {
const restoredContent = content.replace(
/<details id="__DETAIL_(\d+)__"\/>/g,
(_, index) => preprocessedDetailsCache[parseInt(index)] || ''
);
return restoredContent;
}
const editMessageHandler = async () => { const editMessageHandler = async () => {
edit = true; edit = true;
editedContent = message.content;
editedContent = preprocessForEditing(message.content);
await tick(); await tick();
@ -343,7 +371,8 @@
}; };
const editMessageConfirmHandler = async () => { const editMessageConfirmHandler = async () => {
editMessage(message.id, editedContent ? editedContent : '', false); const messageContent = postprocessAfterEditing(editedContent ? editedContent : '');
editMessage(message.id, messageContent, false);
edit = false; edit = false;
editedContent = ''; editedContent = '';
@ -352,7 +381,9 @@
}; };
const saveAsCopyHandler = async () => { const saveAsCopyHandler = async () => {
editMessage(message.id, editedContent ? editedContent : ''); const messageContent = postprocessAfterEditing(editedContent ? editedContent : '');
editMessage(message.id, messageContent);
edit = false; edit = false;
editedContent = ''; editedContent = '';

View File

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { decode } from 'html-entities'; import { decode } from 'html-entities';
import { v4 as uuidv4 } from 'uuid';
import { getContext, createEventDispatcher } from 'svelte'; import { getContext, createEventDispatcher } from 'svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -54,6 +55,8 @@
export let disabled = false; export let disabled = false;
export let hide = false; export let hide = false;
const collapsibleId = uuidv4();
function parseJSONString(str) { function parseJSONString(str) {
try { try {
return parseJSONString(JSON.parse(str)); return parseJSONString(JSON.parse(str));
@ -128,14 +131,14 @@
{:else if attributes?.type === 'tool_calls'} {:else if attributes?.type === 'tool_calls'}
{#if attributes?.done === 'true'} {#if attributes?.done === 'true'}
<Markdown <Markdown
id={`tool-calls-${attributes?.id}`} id={`${collapsibleId}-tool-calls-${attributes?.id}`}
content={$i18n.t('View Result from **{{NAME}}**', { content={$i18n.t('View Result from **{{NAME}}**', {
NAME: attributes.name NAME: attributes.name
})} })}
/> />
{:else} {:else}
<Markdown <Markdown
id={`tool-calls-${attributes?.id}-executing`} id={`${collapsibleId}-tool-calls-${attributes?.id}-executing`}
content={$i18n.t('Executing **{{NAME}}**...', { content={$i18n.t('Executing **{{NAME}}**...', {
NAME: attributes.name NAME: attributes.name
})} })}
@ -208,7 +211,7 @@
{#if attributes?.type === 'tool_calls'} {#if attributes?.type === 'tool_calls'}
{#if attributes?.done === 'true'} {#if attributes?.done === 'true'}
<Markdown <Markdown
id={`tool-calls-${attributes?.id}-result`} id={`${collapsibleId}-tool-calls-${attributes?.id}-result`}
content={`> \`\`\`json content={`> \`\`\`json
> ${formatJSONString(args)} > ${formatJSONString(args)}
> ${formatJSONString(result)} > ${formatJSONString(result)}
@ -216,7 +219,7 @@
/> />
{:else} {:else}
<Markdown <Markdown
id={`tool-calls-${attributes?.id}-result`} id={`${collapsibleId}-tool-calls-${attributes?.id}-result`}
content={`> \`\`\`json content={`> \`\`\`json
> ${formatJSONString(args)} > ${formatJSONString(args)}
> \`\`\``} > \`\`\``}
@ -232,7 +235,11 @@
{#if typeof files === 'object'} {#if typeof files === 'object'}
{#each files ?? [] as file, idx} {#each files ?? [] as file, idx}
{#if file.startsWith('data:image/')} {#if file.startsWith('data:image/')}
<Image id={`tool-calls-${attributes?.id}-result-${idx}`} src={file} alt="Image" /> <Image
id={`${collapsibleId}-tool-calls-${attributes?.id}-result-${idx}`}
src={file}
alt="Image"
/>
{/if} {/if}
{/each} {/each}
{/if} {/if}