File size: 4,779 Bytes
411fba2 af93b45 4b8b411 80b13a0 2488073 e8b5344 2488073 e8b5344 60216ec 2488073 60216ec e8b5344 2488073 3138e12 711cbbd 86574c0 a8ce6ad 2488073 fc99266 c7f83e1 a8ce6ad e3a37e9 80b13a0 74d5501 b52f201 74d5501 80b13a0 a8ce6ad e8b5344 2488073 25c63d0 2488073 25c63d0 2488073 e8b5344 2488073 25c63d0 2488073 411fba2 f459835 25c63d0 2488073 25c63d0 2488073 25c63d0 411fba2 2488073 f459835 2488073 73b6f4f 411fba2 2488073 f459835 8c5a2cf f459835 2488073 c077f8a |
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 |
<script lang="ts">
import type { Conversation, ModelEntryWithTokenizer } from "./types";
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import { browser } from "$app/environment";
import { fetchHuggingFaceModel, type InferenceProviderMapping } from "$lib/fetchers/providers";
import { models } from "$lib/stores/models";
import { token } from "$lib/stores/token";
import { randomPick } from "$lib/utils/array";
import Avatar from "../Avatar.svelte";
import IconCaret from "../Icons/IconCaret.svelte";
import IconProvider from "../Icons/IconProvider.svelte";
import ModelSelectorModal from "./InferencePlaygroundModelSelectorModal.svelte";
import { defaultSystemMessage } from "./inferencePlaygroundUtils";
import { createSelect, createSync } from "@melt-ui/svelte";
export let conversation: Conversation;
let showModelPickerModal = false;
// Model
function changeModel(modelId: ModelEntryWithTokenizer["id"]) {
const model = $models.find(m => m.id === modelId);
if (!model) {
return;
}
conversation.model = model;
conversation.systemMessage = { role: "system", content: defaultSystemMessage?.[modelId] ?? "" };
const url = new URL($page.url);
url.searchParams.set("modelId", model.id);
const parentOrigin = "https://huggingface.co";
window.parent.postMessage({ queryString: `modelId=${model.id}` }, parentOrigin);
goto(url.toString(), { replaceState: true });
}
$: nameSpace = conversation.model.id.split("/")[0] ?? "";
$: modelName = conversation.model.id.split("/")[1] ?? "";
const id = crypto.randomUUID();
// Provider
async function loadProviders(modelId: string) {
if (!browser) return;
providerMap = {};
const res = await fetchHuggingFaceModel(modelId, $token.value);
providerMap = res.inferenceProviderMapping;
if (conversation.provider ?? "" in providerMap) return;
conversation.provider = randomPick(Object.keys(providerMap));
}
let providerMap: InferenceProviderMapping = {};
$: modelId = conversation.model.id;
$: loadProviders(modelId);
$: provider = conversation.provider;
const {
elements: { trigger, menu, option },
states: { selected },
} = createSelect<string, false>();
const sync = createSync({ selected });
$: sync.selected(
conversation.provider ? { value: conversation.provider } : undefined,
p => (conversation.provider = p?.value)
);
</script>
<div class="flex flex-col gap-2">
<label for={id} class="flex items-baseline gap-2 text-sm font-medium text-gray-900 dark:text-white">
Models<span class="text-xs font-normal text-gray-400">{$models.length}</span>
</label>
<button
{id}
class="relative flex items-center justify-between gap-6 overflow-hidden rounded-lg border bg-gray-100/80 px-3 py-1.5 leading-tight whitespace-nowrap shadow-sm hover:brightness-95 dark:border-gray-700 dark:bg-gray-800 dark:hover:brightness-110"
on:click={() => (showModelPickerModal = true)}
>
<div class="flex flex-col items-start">
<div class="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-300">
<Avatar orgName={nameSpace} size="sm" />
{nameSpace}
</div>
<div>{modelName}</div>
</div>
<IconCaret classNames="text-xl bg-gray-100 dark:bg-gray-600 rounded-sm size-4 flex-none absolute right-2" />
</button>
</div>
{#if showModelPickerModal}
<ModelSelectorModal
{conversation}
on:modelSelected={e => changeModel(e.detail)}
on:close={() => (showModelPickerModal = false)}
/>
{/if}
<div class="flex flex-col gap-2">
<!--
<label class="flex items-baseline gap-2 text-sm font-medium text-gray-900 dark:text-white">
Providers<span class="text-xs font-normal text-gray-400"></span>
</label>
-->
<button
{...$trigger}
use:trigger
class="relative flex items-center justify-between gap-6 overflow-hidden rounded-lg border bg-gray-100/80 px-3 py-1.5 leading-tight whitespace-nowrap shadow-sm hover:brightness-95 dark:border-gray-700 dark:bg-gray-800 dark:hover:brightness-110"
>
<div class="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-300">
<IconProvider provider={conversation.provider} />
{conversation.provider ?? "loading"}
</div>
<IconCaret classNames="text-xl bg-gray-100 dark:bg-gray-600 rounded-sm size-4 flex-none absolute right-2" />
</button>
<div {...$menu} use:menu class="rounded-lg border bg-gray-100/80 dark:border-gray-700 dark:bg-gray-800">
{#each Object.keys(providerMap) as provider (provider)}
<div {...$option({ value: provider })} use:option class="group p-1 text-sm dark:text-white">
<div
class="flex items-center gap-2 rounded-md px-2 py-1 group-data-[highlighted]:bg-gray-200 dark:group-data-[highlighted]:bg-gray-700"
>
<IconProvider {provider} />
{provider}
</div>
</div>
{/each}
</div>
</div>
|