Spaces:
Runtime error
Runtime error
File size: 9,296 Bytes
8000347 58843c4 97c4991 6f005bf 58843c4 15094ac 97c4991 1778c9e 60216ec b924465 60216ec aac02fe 97c4991 60216ec c02e352 812d95a 1778c9e 812d95a 1778c9e 8709c70 79784ac 60216ec b924465 79784ac c02e352 812d95a ce92b65 16c3549 f9fa0a5 1778c9e 16c3549 97c4991 1778c9e f9fa0a5 6f005bf 8b09a5e 3b86586 8b09a5e 1778c9e 97c4991 f9fa0a5 97c4991 58843c4 97c4991 f9fa0a5 b924465 79784ac 812d95a 491aab8 79784ac 761e5b4 79784ac c02e352 36ed2d0 58843c4 79d3242 b37c7b7 97c4991 1778c9e 97c4991 55b300a f9fa0a5 55b300a 79784ac f9fa0a5 97c4991 812d95a 58843c4 812d95a 97c4991 58eb9d1 97c4991 e1cf22b 6fdab00 bdc9315 491aab8 c02e352 812d95a 79784ac c02e352 8709c70 1778c9e 73b6f4f 8709c70 bdc9315 e1cf22b 79784ac 7083ad1 79784ac f250f57 b924465 812d95a f250f57 7083ad1 ce92b65 7083ad1 79784ac 28faefd 761e5b4 52c6f5c 761e5b4 aac02fe 761e5b4 28faefd 97c4991 b924465 79784ac 491aab8 79784ac 1778c9e 79784ac 7083ad1 79784ac 97c4991 79784ac 36ed2d0 491aab8 79784ac e1cf22b |
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
<script lang="ts">
import { type ConversationClass } from "$lib/state/conversations.svelte";
import { token } from "$lib/state/token.svelte.js";
import { billing } from "$lib/state/billing.svelte";
import { isCustomModel } from "$lib/types.js";
import {
getInferenceSnippet,
type GetInferenceSnippetReturn,
type InferenceSnippetLanguage,
} from "$lib/utils/business.svelte.js";
import { copyToClipboard } from "$lib/utils/copy.js";
import { entries, fromEntries, keys } from "$lib/utils/object.svelte.js";
import hljs from "highlight.js/lib/core";
import http from "highlight.js/lib/languages/http";
import javascript from "highlight.js/lib/languages/javascript";
import python from "highlight.js/lib/languages/python";
import IconExternal from "~icons/carbon/arrow-up-right";
import IconCopy from "~icons/carbon/copy";
import LocalToasts from "../local-toasts.svelte";
hljs.registerLanguage("javascript", javascript);
hljs.registerLanguage("python", python);
hljs.registerLanguage("http", http);
interface Props {
conversation: ConversationClass;
onCloseCode: () => void;
}
const { conversation, onCloseCode }: Props = $props();
const labelsByLanguage = {
javascript: "JavaScript",
python: "Python",
http: "cURL",
} as const satisfies Record<string, string>;
type Language = keyof typeof labelsByLanguage;
let lang: Language = $state("javascript");
let showToken = $state(false);
type GetSnippetArgs = {
tokenStr?: string;
conversation: ConversationClass;
lang: InferenceSnippetLanguage;
};
function getSnippet({ tokenStr, conversation, lang }: GetSnippetArgs) {
const model = conversation.model;
const data = conversation.data;
const opts = {
messages: data.messages,
streaming: data.streaming,
max_tokens: data.config.max_tokens,
temperature: data.config.temperature,
top_p: data.config.top_p,
accessToken: tokenStr,
billTo: billing.organization || undefined,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
if (data.structuredOutput && conversation.isStructuredOutputAllowed) {
opts.structured_output = data.structuredOutput;
}
if (isCustomModel(model)) {
const snippets = getInferenceSnippet(conversation, lang, opts);
return snippets
.filter(s => s.client.startsWith("open") || lang === "sh")
.map(s => {
return {
...s,
content: s.content
.replaceAll("https://router.huggingface.co/hf-inference/v1", model.endpointUrl)
.replaceAll(`https://router.huggingface.co/hf-inference/models/${model.id}/v1`, model.endpointUrl),
};
});
}
return getInferenceSnippet(conversation, lang, opts);
}
// { javascript: 0, python: 0, http: 0 } at first
const selectedSnippetIdxByLang: Record<Language, number> = $state(
fromEntries(
keys(labelsByLanguage).map(lang => {
return [lang, 0];
}),
),
);
type InstallInstructions = {
title: string;
content: string;
docs: string;
};
function highlight(code?: string, language?: InferenceSnippetLanguage) {
if (!code || !language) return "";
return hljs.highlight(code, { language: language === "sh" ? "http" : language }).value;
}
const tokenStr = $derived.by(() => {
if (isCustomModel(conversation.model)) {
const t = conversation.model.accessToken;
return t && showToken ? t : undefined;
}
return token.value && showToken ? token.value : undefined;
});
const snippetsByLang = $derived({
javascript: getSnippet({ lang: "js", tokenStr, conversation }),
python: getSnippet({ lang: "python", tokenStr, conversation }),
http: getSnippet({ lang: "sh", tokenStr, conversation }),
} as Record<Language, GetInferenceSnippetReturn>);
// Auto-switch to available language if current one has no snippets
$effect(() => {
const currentSnippets = snippetsByLang[lang];
if (currentSnippets.length) return;
// Find first language with available snippets
const availableLanguage = keys(labelsByLanguage).find(l => snippetsByLang[l] && snippetsByLang[l].length > 0);
if (availableLanguage) {
lang = availableLanguage;
}
});
const selectedSnippet = $derived(snippetsByLang[lang][selectedSnippetIdxByLang[lang]]);
const installInstructions = $derived.by(function getInstallInstructions(): InstallInstructions | undefined {
if (lang === "javascript") {
const isHugging = selectedSnippet?.client.includes("hugging");
const toInstall = isHugging ? "@huggingface/inference" : "openai";
const docs = isHugging
? "https://huggingface.co/docs/huggingface.js/inference/README"
: "https://platform.openai.com/docs/libraries";
return {
title: `Install ${toInstall}`,
content: `npm install --save ${toInstall}`,
docs,
};
} else if (lang === "python") {
const isHugging = selectedSnippet?.client.includes("hugging");
const toInstall = isHugging ? "huggingface_hub" : "openai";
const docs = isHugging
? "https://huggingface.co/docs/huggingface_hub/guides/inference"
: "https://platform.openai.com/docs/libraries";
return {
title: `Install the latest`,
content: `pip install --upgrade ${toInstall}`,
docs,
};
}
});
</script>
<div class="px-2 pt-2">
<div
class="border-b border-gray-200 text-center text-sm font-medium text-gray-500 dark:border-gray-700 dark:text-gray-400"
>
<ul class="-mb-px flex flex-wrap">
{#each entries(labelsByLanguage).filter(([lang]) => {
return snippetsByLang[lang]?.length;
}) as [language, label]}
<li>
<button
onclick={() => (lang = language)}
class="inline-block rounded-t-lg border-b-2 p-4 {lang === language
? 'border-black text-black dark:border-blue-500 dark:text-blue-500'
: 'border-transparent hover:border-gray-300 hover:text-gray-600 dark:hover:text-gray-300'}"
aria-current="page">{label}</button
>
</li>
{/each}
<li class="ml-auto self-center max-sm:hidden">
<button
onclick={onCloseCode}
class="flex size-7 items-center justify-center rounded-lg px-3 py-2.5 text-xs font-medium text-gray-900 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
>
✕
</button>
</li>
</ul>
</div>
{#if (snippetsByLang[lang]?.length ?? 0) > 1}
<div class="flex gap-x-2 px-2 pt-6">
{#each snippetsByLang[lang] ?? [] as { client }, idx}
{@const isActive = idx === selectedSnippetIdxByLang[lang]}
<button
class="rounded-lg border px-1.5 py-0.5 text-sm leading-tight
{isActive
? 'bg-black text-gray-100 dark:border-gray-500 dark:bg-gray-700 dark:text-white'
: 'text-gray-500 hover:text-gray-600 dark:border-gray-600 dark:hover:text-gray-400'}"
onclick={() => (selectedSnippetIdxByLang[lang] = idx)}>{client}</button
>
{/each}
</div>
{/if}
{#if installInstructions}
<div class="flex flex-col justify-between gap-2 px-2 pt-6 pb-4 md:flex-row md:items-center">
<h2 class="flex items-center gap-2 font-semibold">
{installInstructions.title}
<a
href={installInstructions.docs}
target="_blank"
rel="external"
class="relative -bottom-[1px] flex items-center gap-1 text-sm font-normal text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300"
>
<IconExternal class="text-xs" />
Docs
</a>
</h2>
<div class="flex items-center gap-x-4 whitespace-nowrap">
<LocalToasts>
{#snippet children({ addToast, trigger })}
<button
{...trigger}
class="btn flex h-auto items-center gap-2 px-2 py-1.5 text-xs"
onclick={() => {
copyToClipboard(installInstructions.content);
addToast({ data: { content: "Copied to clipboard", variant: "info" } });
}}
>
<IconCopy />
Copy code
</button>
{/snippet}
</LocalToasts>
</div>
</div>
<pre
class="overflow-x-auto rounded-lg border border-gray-200/80 bg-white px-4 py-6 text-sm shadow-xs dark:border-gray-800 dark:bg-gray-800/50">{@html highlight(
installInstructions.content,
selectedSnippet?.language,
)}</pre>
{/if}
<div class="flex items-center justify-between px-2 pt-6 pb-4">
{#if conversation.data.streaming}
<h2 class="font-semibold">Streaming API</h2>
{:else}
<h2 class="font-semibold">Non-Streaming API</h2>
{/if}
<div class="flex items-center gap-x-4">
<label class="flex items-center gap-x-1.5 text-sm select-none">
<input type="checkbox" bind:checked={showToken} />
<p class="leading-none">With token</p>
</label>
<LocalToasts>
{#snippet children({ addToast, trigger })}
<button
{...trigger}
class="btn flex h-auto items-center gap-2 px-2 py-1.5 text-xs"
onclick={() => {
copyToClipboard(selectedSnippet?.content ?? "");
addToast({ data: { content: "Copied to clipboard", variant: "info" } });
}}
>
<IconCopy />
Copy code
</button>
{/snippet}
</LocalToasts>
</div>
</div>
<pre
class="overflow-x-auto rounded-lg border border-gray-200/80 bg-white px-4 py-6 text-sm shadow-xs dark:border-gray-800 dark:bg-gray-800/50">{@html highlight(
selectedSnippet?.content,
selectedSnippet?.language,
)}</pre>
</div>
|