File size: 5,359 Bytes
6426ece |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
<script lang="ts">
import { StreamLanguage } from '@codemirror/language';
import CodeMirror from '$lib/CodeMirror/CodeMirror.svelte';
import { jinja2 } from '@codemirror/legacy-modes/mode/jinja2';
import { EditorView, lineNumbers } from '@codemirror/view';
import CopyButton from '$lib/CopyButton/CopyButton.svelte';
import IconCodeGeneration from '$lib/Icons/IconCodeGeneration.svelte';
import { tooltip } from '$lib/utils/tooltip';
import type { FormattedChatTemplate } from './types';
import LineWrapButton from '$lib/LineWrapButton/LineWrapButton.svelte';
import { createEventDispatcher } from 'svelte';
import IconRestart from '$lib/Icons/IconRestart.svelte';
export let modelId: string;
export let formattedTemplates: FormattedChatTemplate[] = [];
export let selectedTemplate: FormattedChatTemplate | undefined = undefined;
export let showFormattedTemplate = true;
let wrapLines = true;
const dispatch = createEventDispatcher<{ modelIdChange: string; templateChange: string }>();
async function handleUpdateEditor(e: CustomEvent{
const currentCode = e.detail;
if (selectedTemplate) {
showFormattedTemplate
? (selectedTemplate.formattedTemplate = currentCode)
: (selectedTemplate.template = currentCode);
}
}
</script>
<div class="h-full overflow-scroll bg-white dark:bg-gray-900">
<div class="sticky top-0 z-10 bg-white dark:bg-gray-900">
<div
class="text-semibold flex items-center gap-x-2 border-b border-gray-500 bg-linear-to-r from-green-200 to-white px-3 py-1.5 text-lg dark:from-green-700 dark:to-green-900 dark:text-gray-200"
>
Chat template{formattedTemplates.length > 1 ? 's' : ''} for
<a class="font-mono underline" href="https://huggingface.co/{modelId}" target="_blank"
>{modelId}</a
>
<button
class="btn ml-auto text-sm"
on:click={() => {
const newModelId = prompt('Enter model ID (ex: deepseek-ai/DeepSeek-R1)')?.trim();
if (newModelId) {
dispatch('modelIdChange', newModelId);
}
}}>change model</button
>
</div>
<div class="flex items-center border-b px-3 py-2">
{#if formattedTemplates.length > 1}
<div class="my-1.5 flex flex-wrap items-center gap-x-1 gap-y-0.5">
{#each formattedTemplates as template (template.name)}
<button
class="text-md flex items-center rounded-lg border px-1.5 py-1 leading-none select-none
{selectedTemplate?.name === template.name
? 'border-gray-800 bg-black text-white dark:bg-gray-700'
: 'cursor-pointer text-gray-500 opacity-90 hover:text-gray-700 hover:shadow-xs dark:hover:text-gray-200'}"
type="button"
on:click={() => {
selectedTemplate = template;
dispatch('templateChange', template.name);
}}
>
{template.name}
</button>
{/each}
</div>
{/if}
<div class="ml-auto flex items-center gap-x-2">
<!-- reset button -->
{#if showFormattedTemplate ? selectedTemplate?.formattedTemplate !== selectedTemplate?.formattedTemplateUnedited : selectedTemplate?.template !== selectedTemplate?.templateUnedited}
<button
class="relative inline-flex h-6! cursor-pointer items-center justify-center rounded-md border border-gray-500 bg-white p-0! px-1.5! text-sm shadow-xs focus:outline-hidden dark:bg-gray-900 dark:text-white [&_svg]:translate-x-px! [&_svg]:translate-y-px! [&_svg]:text-base!"
type="button"
on:click={() => {
if (selectedTemplate) {
showFormattedTemplate
? (selectedTemplate.formattedTemplate =
selectedTemplate.formattedTemplateUnedited)
: (selectedTemplate.template = selectedTemplate.templateUnedited);
}
}}
use:tooltip={'Reset template to original'}
><IconRestart classNames="dark:text-gray-200!" />
<span class="ml-1 text-sm select-none dark:text-gray-200!"> Reset </span>
</button>
{/if}
<CopyButton
label="Copy"
value={showFormattedTemplate
? (selectedTemplate?.formattedTemplate ?? '')
: (selectedTemplate?.template ?? '')}
style="button-clear"
classNames="h-6! [&_svg]:text-[0.7rem]! px-1.5! text-black! dark:text-gray-200!"
/>
<!-- format button -->
<button
class="relative inline-flex h-6! cursor-pointer items-center justify-center rounded-md border border-gray-500 bg-white p-0! px-1.5! text-sm shadow-xs focus:outline-hidden dark:bg-gray-900 dark:text-white [&_svg]:translate-x-px! [&_svg]:translate-y-px! [&_svg]:text-base!"
type="button"
on:click={() => {
showFormattedTemplate = !showFormattedTemplate;
}}
use:tooltip={'Format with @huggingface/jinja'}
><IconCodeGeneration classNames={showFormattedTemplate ? 'opacity-100' : 'opacity-40'} />
<span
class="ml-1 text-sm select-none {showFormattedTemplate ? 'opacity-100' : 'opacity-40'}"
>
Formatted
</span>
</button>
<LineWrapButton
style="button-clear"
bind:wrapLines
classNames="[&_svg]:text-xs! size-6! p-0!"
/>
</div>
</div>
</div>
<CodeMirror
value={showFormattedTemplate
? (selectedTemplate?.formattedTemplate ?? '')
: (selectedTemplate?.template ?? '')}
on:change={handleUpdateEditor}
extensions={[
lineNumbers(),
StreamLanguage.define(jinja2),
...[wrapLines ? [EditorView.lineWrapping] : []]
]}
/>
</div>
|