Thomas G. Lopes
MCPs (#91)
52c6f5c unverified
raw
history blame
9.3 kB
<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>