Spaces:
Runtime error
Runtime error
| <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> | |