same prettier as hub
Browse files- .prettierrc +0 -8
- .prettierrc.mjs +11 -0
- postcss.config.js +2 -2
- src/app.css +1 -1
- src/lib/components/Icons/IconCaret.svelte +2 -5
- src/lib/components/Icons/IconCode.svelte +1 -1
- src/lib/components/Icons/IconCopyCode.svelte +1 -1
- src/lib/components/Icons/IconCross.svelte +1 -1
- src/lib/components/Icons/IconDelete.svelte +2 -5
- src/lib/components/Icons/IconPlus.svelte +2 -7
- src/lib/components/Icons/IconSearch.svelte +2 -5
- src/lib/components/Icons/IconShare.svelte +2 -9
- src/lib/components/Icons/IconStar.svelte +1 -1
- src/lib/components/InferencePlayground/InferencePlayground.svelte +34 -39
- src/lib/components/InferencePlayground/InferencePlaygroundCodeSnippets.svelte +52 -52
- src/lib/components/InferencePlayground/InferencePlaygroundConversation.svelte +7 -7
- src/lib/components/InferencePlayground/InferencePlaygroundGenerationConfig.svelte +11 -14
- src/lib/components/InferencePlayground/InferencePlaygroundHFTokenModal.svelte +11 -15
- src/lib/components/InferencePlayground/InferencePlaygroundMessage.svelte +3 -3
- src/lib/components/InferencePlayground/InferencePlaygroundModelSelector.svelte +9 -15
- src/lib/components/InferencePlayground/InferencePlaygroundModelSelectorModal.svelte +20 -20
- src/lib/components/InferencePlayground/generationConfigSettings.ts +8 -12
- src/lib/components/InferencePlayground/inferencePlaygroundUtils.ts +12 -16
- src/lib/types/index.d.ts +3 -3
- src/routes/+layout.svelte +1 -1
- src/routes/+page.server.ts +9 -12
- src/routes/+page.svelte +1 -1
- svelte.config.js +4 -4
- tailwind.config.ts +5 -5
- vite.config.ts +3 -3
.prettierrc
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"useTabs": true,
|
3 |
-
"singleQuote": true,
|
4 |
-
"trailingComma": "none",
|
5 |
-
"printWidth": 100,
|
6 |
-
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
7 |
-
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
8 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.prettierrc.mjs
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export default {
|
2 |
+
arrowParens: "avoid",
|
3 |
+
quoteProps: "consistent",
|
4 |
+
trailingComma: "es5",
|
5 |
+
useTabs: true,
|
6 |
+
tabWidth: 2,
|
7 |
+
printWidth: 120,
|
8 |
+
overrides: [{ files: "*.svelte", options: { parser: "svelte" } }],
|
9 |
+
tailwindConfig: "./tailwind.config.ts",
|
10 |
+
plugins: [import("prettier-plugin-svelte"), import("prettier-plugin-tailwindcss")],
|
11 |
+
};
|
postcss.config.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
export default {
|
2 |
plugins: {
|
3 |
tailwindcss: {},
|
4 |
-
autoprefixer: {}
|
5 |
-
}
|
6 |
};
|
|
|
1 |
export default {
|
2 |
plugins: {
|
3 |
tailwindcss: {},
|
4 |
+
autoprefixer: {},
|
5 |
+
},
|
6 |
};
|
src/app.css
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
@import
|
2 |
@tailwind base;
|
3 |
@tailwind components;
|
4 |
@tailwind utilities;
|
|
|
1 |
+
@import "highlight.js/styles/atom-one-light";
|
2 |
@tailwind base;
|
3 |
@tailwind components;
|
4 |
@tailwind utilities;
|
src/lib/components/Icons/IconCaret.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
@@ -12,8 +12,5 @@
|
|
12 |
height="1em"
|
13 |
preserveAspectRatio="xMidYMid meet"
|
14 |
viewBox="0 0 24 24"
|
15 |
-
><path
|
16 |
-
d="M16.293 9.293L12 13.586L7.707 9.293l-1.414 1.414L12 16.414l5.707-5.707z"
|
17 |
-
fill="currentColor"
|
18 |
-
/>
|
19 |
</svg>
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
12 |
height="1em"
|
13 |
preserveAspectRatio="xMidYMid meet"
|
14 |
viewBox="0 0 24 24"
|
15 |
+
><path d="M16.293 9.293L12 13.586L7.707 9.293l-1.414 1.414L12 16.414l5.707-5.707z" fill="currentColor" />
|
|
|
|
|
|
|
16 |
</svg>
|
src/lib/components/Icons/IconCode.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
src/lib/components/Icons/IconCopyCode.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
src/lib/components/Icons/IconCross.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
src/lib/components/Icons/IconDelete.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
@@ -14,10 +14,7 @@
|
|
14 |
preserveAspectRatio="xMidYMid meet"
|
15 |
viewBox="0 0 32 32"
|
16 |
>
|
17 |
-
<path d="M12 12h2v12h-2z" fill="currentColor" /><path
|
18 |
-
d="M18 12h2v12h-2z"
|
19 |
-
fill="currentColor"
|
20 |
-
/><path
|
21 |
d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z"
|
22 |
fill="currentColor"
|
23 |
/><path d="M12 2h8v2h-8z" fill="currentColor" />
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
14 |
preserveAspectRatio="xMidYMid meet"
|
15 |
viewBox="0 0 32 32"
|
16 |
>
|
17 |
+
<path d="M12 12h2v12h-2z" fill="currentColor" /><path d="M18 12h2v12h-2z" fill="currentColor" /><path
|
|
|
|
|
|
|
18 |
d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z"
|
19 |
fill="currentColor"
|
20 |
/><path d="M12 2h8v2h-8z" fill="currentColor" />
|
src/lib/components/Icons/IconPlus.svelte
CHANGED
@@ -1,13 +1,8 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
-
<svg
|
6 |
-
class={classNames}
|
7 |
-
xmlns="http://www.w3.org/2000/svg"
|
8 |
-
width="1em"
|
9 |
-
height="1em"
|
10 |
-
viewBox="0 0 32 32"
|
11 |
><path
|
12 |
fill="currentColor"
|
13 |
d="M16 2A14.172 14.172 0 0 0 2 16a14.172 14.172 0 0 0 14 14a14.172 14.172 0 0 0 14-14A14.172 14.172 0 0 0 16 2Zm8 15h-7v7h-2v-7H8v-2h7V8h2v7h7Z"
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
+
<svg class={classNames} xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32"
|
|
|
|
|
|
|
|
|
|
|
6 |
><path
|
7 |
fill="currentColor"
|
8 |
d="M16 2A14.172 14.172 0 0 0 2 16a14.172 14.172 0 0 0 14 14a14.172 14.172 0 0 0 14-14A14.172 14.172 0 0 0 16 2Zm8 15h-7v7h-2v-7H8v-2h7V8h2v7h7Z"
|
src/lib/components/Icons/IconSearch.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
@@ -14,8 +14,5 @@
|
|
14 |
preserveAspectRatio="xMidYMid meet"
|
15 |
viewBox="0 0 32 32"
|
16 |
>
|
17 |
-
<path
|
18 |
-
d="M30 28.59L22.45 21A11 11 0 1 0 21 22.45L28.59 30zM5 14a9 9 0 1 1 9 9a9 9 0 0 1-9-9z"
|
19 |
-
fill="currentColor"
|
20 |
-
/>
|
21 |
</svg>
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
14 |
preserveAspectRatio="xMidYMid meet"
|
15 |
viewBox="0 0 32 32"
|
16 |
>
|
17 |
+
<path d="M30 28.59L22.45 21A11 11 0 1 0 21 22.45L28.59 30zM5 14a9 9 0 1 1 9 9a9 9 0 0 1-9-9z" fill="currentColor" />
|
|
|
|
|
|
|
18 |
</svg>
|
src/lib/components/Icons/IconShare.svelte
CHANGED
@@ -1,15 +1,8 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
-
<svg
|
6 |
-
class={classNames}
|
7 |
-
width="1em"
|
8 |
-
height="1em"
|
9 |
-
viewBox="0 0 24 25"
|
10 |
-
fill="none"
|
11 |
-
xmlns="http://www.w3.org/2000/svg"
|
12 |
-
>
|
13 |
<path
|
14 |
fill-rule="evenodd"
|
15 |
clip-rule="evenodd"
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
+
<svg class={classNames} width="1em" height="1em" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
<path
|
7 |
fill-rule="evenodd"
|
8 |
clip-rule="evenodd"
|
src/lib/components/Icons/IconStar.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
export let classNames =
|
3 |
</script>
|
4 |
|
5 |
<svg
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
</script>
|
4 |
|
5 |
<svg
|
src/lib/components/InferencePlayground/InferencePlayground.svelte
CHANGED
@@ -3,32 +3,32 @@
|
|
3 |
createHfInference,
|
4 |
handleStreamingResponse,
|
5 |
handleNonStreamingResponse,
|
6 |
-
isSystemPromptSupported
|
7 |
-
} from
|
8 |
-
import GenerationConfig from
|
9 |
-
import HFTokenModal from
|
10 |
-
import ModelSelector from
|
11 |
-
import Conversation from
|
12 |
-
import { onDestroy } from
|
13 |
-
import { type ChatCompletionInputMessage } from
|
14 |
-
import type { ModelEntryWithTokenizer } from
|
15 |
-
import { defaultGenerationConfig } from
|
16 |
-
import IconShare from
|
17 |
-
import IconDelete from
|
18 |
-
import IconCode from
|
19 |
|
20 |
export let models: ModelEntryWithTokenizer[];
|
21 |
|
22 |
-
const startMessages: ChatCompletionInputMessage[] = [{ role:
|
23 |
|
24 |
let conversation: Conversation = {
|
25 |
model: models[0],
|
26 |
config: defaultGenerationConfig,
|
27 |
messages: startMessages,
|
28 |
-
streaming: true
|
29 |
};
|
30 |
|
31 |
-
let systemMessage: ChatCompletionInputMessage = { role:
|
32 |
let hfToken: string | undefined = import.meta.env.VITE_HF_TOKEN;
|
33 |
let viewCode = false;
|
34 |
let showTokenModal = false;
|
@@ -47,9 +47,9 @@
|
|
47 |
conversation.messages = [
|
48 |
...conversation.messages,
|
49 |
{
|
50 |
-
role: conversation.messages.at(-1)?.role ===
|
51 |
-
content:
|
52 |
-
}
|
53 |
];
|
54 |
}
|
55 |
|
@@ -59,7 +59,7 @@
|
|
59 |
}
|
60 |
|
61 |
function reset() {
|
62 |
-
systemMessage.content =
|
63 |
conversation.messages = [...startMessages];
|
64 |
}
|
65 |
|
@@ -88,14 +88,14 @@
|
|
88 |
const hf = createHfInference(hfToken);
|
89 |
|
90 |
if (conversation.streaming) {
|
91 |
-
const streamingMessage = { role:
|
92 |
conversation.messages = [...conversation.messages, streamingMessage];
|
93 |
abortController = new AbortController();
|
94 |
|
95 |
await handleStreamingResponse(
|
96 |
hf,
|
97 |
conversation,
|
98 |
-
|
99 |
if (streamingMessage) {
|
100 |
streamingMessage.content = content;
|
101 |
conversation.messages = [...conversation.messages];
|
@@ -118,8 +118,8 @@
|
|
118 |
|
119 |
addMessage();
|
120 |
} catch (error) {
|
121 |
-
if (error.name !==
|
122 |
-
alert(
|
123 |
}
|
124 |
} finally {
|
125 |
loading = false;
|
@@ -128,7 +128,7 @@
|
|
128 |
}
|
129 |
|
130 |
function onKeydown(event: KeyboardEvent) {
|
131 |
-
if (!event.shiftKey && event.key ===
|
132 |
submit();
|
133 |
}
|
134 |
}
|
@@ -137,9 +137,9 @@
|
|
137 |
{#if showTokenModal}
|
138 |
<HFTokenModal
|
139 |
on:close={() => (showTokenModal = false)}
|
140 |
-
on:submit={
|
141 |
const formData = new FormData(e.target);
|
142 |
-
hfToken = formData.get(
|
143 |
submit();
|
144 |
showTokenModal = false;
|
145 |
}}
|
@@ -161,8 +161,8 @@
|
|
161 |
name=""
|
162 |
id=""
|
163 |
placeholder={systemPromptSupported
|
164 |
-
?
|
165 |
-
:
|
166 |
bind:value={systemMessage.content}
|
167 |
class="absolute inset-x-0 bottom-0 h-full resize-none bg-transparent px-3 pt-10 text-sm outline-none"
|
168 |
></textarea>
|
@@ -176,7 +176,7 @@
|
|
176 |
index={0}
|
177 |
{viewCode}
|
178 |
on:addMessage={addMessage}
|
179 |
-
on:deleteMessage={
|
180 |
/>
|
181 |
</div>
|
182 |
<div
|
@@ -186,9 +186,7 @@
|
|
186 |
type="button"
|
187 |
class="flex h-[39px] flex-none gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 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"
|
188 |
>
|
189 |
-
<div
|
190 |
-
class="flex size-5 items-center justify-center rounded border border-black/5 bg-black/5 text-xs"
|
191 |
-
>
|
192 |
<IconShare />
|
193 |
</div>
|
194 |
|
@@ -211,7 +209,7 @@
|
|
211 |
class="flex h-[39px] items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 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"
|
212 |
>
|
213 |
<IconCode />
|
214 |
-
{!viewCode ?
|
215 |
>
|
216 |
<button
|
217 |
on:click={() => {
|
@@ -240,8 +238,7 @@
|
|
240 |
/>
|
241 |
</div>
|
242 |
{:else}
|
243 |
-
Run <span
|
244 |
-
class="inline-flex gap-0.5 rounded border border-white/20 bg-white/10 px-0.5 text-xs text-white/70"
|
245 |
>↵</span
|
246 |
>
|
247 |
{/if}
|
@@ -257,9 +254,7 @@
|
|
257 |
<GenerationConfig bind:conversation />
|
258 |
<div class="mt-auto">
|
259 |
<div class="mb-3 flex items-center justify-between gap-2">
|
260 |
-
<label for="default-range" class="block text-sm font-medium text-gray-900 dark:text-white"
|
261 |
-
>API Quota</label
|
262 |
-
>
|
263 |
<span
|
264 |
class="rounded bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 dark:bg-gray-700 dark:text-gray-300"
|
265 |
>Free</span
|
|
|
3 |
createHfInference,
|
4 |
handleStreamingResponse,
|
5 |
handleNonStreamingResponse,
|
6 |
+
isSystemPromptSupported,
|
7 |
+
} from "./inferencePlaygroundUtils";
|
8 |
+
import GenerationConfig from "./InferencePlaygroundGenerationConfig.svelte";
|
9 |
+
import HFTokenModal from "./InferencePlaygroundHFTokenModal.svelte";
|
10 |
+
import ModelSelector from "./InferencePlaygroundModelSelector.svelte";
|
11 |
+
import Conversation from "./InferencePlaygroundConversation.svelte";
|
12 |
+
import { onDestroy } from "svelte";
|
13 |
+
import { type ChatCompletionInputMessage } from "@huggingface/tasks";
|
14 |
+
import type { ModelEntryWithTokenizer } from "$lib/types";
|
15 |
+
import { defaultGenerationConfig } from "./generationConfigSettings";
|
16 |
+
import IconShare from "../Icons/IconShare.svelte";
|
17 |
+
import IconDelete from "../Icons/IconDelete.svelte";
|
18 |
+
import IconCode from "../Icons/IconCode.svelte";
|
19 |
|
20 |
export let models: ModelEntryWithTokenizer[];
|
21 |
|
22 |
+
const startMessages: ChatCompletionInputMessage[] = [{ role: "user", content: "" }];
|
23 |
|
24 |
let conversation: Conversation = {
|
25 |
model: models[0],
|
26 |
config: defaultGenerationConfig,
|
27 |
messages: startMessages,
|
28 |
+
streaming: true,
|
29 |
};
|
30 |
|
31 |
+
let systemMessage: ChatCompletionInputMessage = { role: "system", content: "" };
|
32 |
let hfToken: string | undefined = import.meta.env.VITE_HF_TOKEN;
|
33 |
let viewCode = false;
|
34 |
let showTokenModal = false;
|
|
|
47 |
conversation.messages = [
|
48 |
...conversation.messages,
|
49 |
{
|
50 |
+
role: conversation.messages.at(-1)?.role === "user" ? "assistant" : "user",
|
51 |
+
content: "",
|
52 |
+
},
|
53 |
];
|
54 |
}
|
55 |
|
|
|
59 |
}
|
60 |
|
61 |
function reset() {
|
62 |
+
systemMessage.content = "";
|
63 |
conversation.messages = [...startMessages];
|
64 |
}
|
65 |
|
|
|
88 |
const hf = createHfInference(hfToken);
|
89 |
|
90 |
if (conversation.streaming) {
|
91 |
+
const streamingMessage = { role: "assistant", content: "" };
|
92 |
conversation.messages = [...conversation.messages, streamingMessage];
|
93 |
abortController = new AbortController();
|
94 |
|
95 |
await handleStreamingResponse(
|
96 |
hf,
|
97 |
conversation,
|
98 |
+
content => {
|
99 |
if (streamingMessage) {
|
100 |
streamingMessage.content = content;
|
101 |
conversation.messages = [...conversation.messages];
|
|
|
118 |
|
119 |
addMessage();
|
120 |
} catch (error) {
|
121 |
+
if (error.name !== "AbortError") {
|
122 |
+
alert("error: " + (error as Error).message);
|
123 |
}
|
124 |
} finally {
|
125 |
loading = false;
|
|
|
128 |
}
|
129 |
|
130 |
function onKeydown(event: KeyboardEvent) {
|
131 |
+
if (!event.shiftKey && event.key === "Enter") {
|
132 |
submit();
|
133 |
}
|
134 |
}
|
|
|
137 |
{#if showTokenModal}
|
138 |
<HFTokenModal
|
139 |
on:close={() => (showTokenModal = false)}
|
140 |
+
on:submit={e => {
|
141 |
const formData = new FormData(e.target);
|
142 |
+
hfToken = formData.get("hf-token");
|
143 |
submit();
|
144 |
showTokenModal = false;
|
145 |
}}
|
|
|
161 |
name=""
|
162 |
id=""
|
163 |
placeholder={systemPromptSupported
|
164 |
+
? "Enter a custom prompt"
|
165 |
+
: "System prompt is not supported with the chosen model."}
|
166 |
bind:value={systemMessage.content}
|
167 |
class="absolute inset-x-0 bottom-0 h-full resize-none bg-transparent px-3 pt-10 text-sm outline-none"
|
168 |
></textarea>
|
|
|
176 |
index={0}
|
177 |
{viewCode}
|
178 |
on:addMessage={addMessage}
|
179 |
+
on:deleteMessage={e => deleteMessage(e.detail)}
|
180 |
/>
|
181 |
</div>
|
182 |
<div
|
|
|
186 |
type="button"
|
187 |
class="flex h-[39px] flex-none gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 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"
|
188 |
>
|
189 |
+
<div class="flex size-5 items-center justify-center rounded border border-black/5 bg-black/5 text-xs">
|
|
|
|
|
190 |
<IconShare />
|
191 |
</div>
|
192 |
|
|
|
209 |
class="flex h-[39px] items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 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"
|
210 |
>
|
211 |
<IconCode />
|
212 |
+
{!viewCode ? "View Code" : "Hide Code"}</button
|
213 |
>
|
214 |
<button
|
215 |
on:click={() => {
|
|
|
238 |
/>
|
239 |
</div>
|
240 |
{:else}
|
241 |
+
Run <span class="inline-flex gap-0.5 rounded border border-white/20 bg-white/10 px-0.5 text-xs text-white/70"
|
|
|
242 |
>↵</span
|
243 |
>
|
244 |
{/if}
|
|
|
254 |
<GenerationConfig bind:conversation />
|
255 |
<div class="mt-auto">
|
256 |
<div class="mb-3 flex items-center justify-between gap-2">
|
257 |
+
<label for="default-range" class="block text-sm font-medium text-gray-900 dark:text-white">API Quota</label>
|
|
|
|
|
258 |
<span
|
259 |
class="rounded bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 dark:bg-gray-700 dark:text-gray-300"
|
260 |
>Free</span
|
src/lib/components/InferencePlayground/InferencePlaygroundCodeSnippets.svelte
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import hljs from
|
3 |
-
import javascript from
|
4 |
-
import python from
|
5 |
-
import http from
|
6 |
-
import type { Conversation } from
|
7 |
-
import IconCopyCode from
|
8 |
-
import { onDestroy } from
|
9 |
-
|
10 |
-
hljs.registerLanguage(
|
11 |
-
hljs.registerLanguage(
|
12 |
-
hljs.registerLanguage(
|
13 |
|
14 |
export let conversation: Conversation;
|
15 |
|
16 |
-
const lanuages = [
|
17 |
type Language = (typeof lanuages)[number];
|
18 |
const labelsByLanguage: Record<Language, string> = {
|
19 |
-
javascript:
|
20 |
-
python:
|
21 |
-
http:
|
22 |
};
|
23 |
|
24 |
interface Snippet {
|
@@ -30,16 +30,16 @@
|
|
30 |
$: snippetsByLanguage = {
|
31 |
javascript: getJavascriptSnippets(conversation),
|
32 |
python: getPythonSnippets(conversation),
|
33 |
-
http: getHttpSnippets(conversation)
|
34 |
};
|
35 |
|
36 |
-
let selectedLanguage: Language =
|
37 |
let timeout: ReturnType<typeof setTimeout>;
|
38 |
|
39 |
function getMessages() {
|
40 |
-
const placeholder = [{ role:
|
41 |
let messages = conversation.messages;
|
42 |
-
if (messages.length === 1 && messages[0].role ===
|
43 |
messages = placeholder;
|
44 |
}
|
45 |
return messages;
|
@@ -66,13 +66,13 @@
|
|
66 |
|
67 |
const snippets: Snippet[] = [];
|
68 |
snippets.push({
|
69 |
-
label:
|
70 |
-
language:
|
71 |
-
code: `npm install --save @huggingface/inference
|
72 |
});
|
73 |
if (conversation.streaming) {
|
74 |
snippets.push({
|
75 |
-
label:
|
76 |
code: `import { HfInference } from "@huggingface/inference"
|
77 |
|
78 |
const inference = new HfInference("your HF token")
|
@@ -81,8 +81,8 @@ let out = "";
|
|
81 |
|
82 |
for await (const chunk of inference.chatCompletionStream({
|
83 |
model: "${conversation.model.id}",
|
84 |
-
messages: ${formattedMessages({ sep:
|
85 |
-
${formattedConfig({ sep:
|
86 |
seed: 0,
|
87 |
})) {
|
88 |
if (chunk.choices && chunk.choices.length > 0) {
|
@@ -91,24 +91,24 @@ for await (const chunk of inference.chatCompletionStream({
|
|
91 |
console.clear();
|
92 |
console.log(out);
|
93 |
}
|
94 |
-
}
|
95 |
});
|
96 |
} else {
|
97 |
// non-streaming
|
98 |
snippets.push({
|
99 |
-
label:
|
100 |
code: `import { HfInference } from '@huggingface/inference'
|
101 |
|
102 |
const inference = new HfInference("your access token")
|
103 |
|
104 |
const out = await inference.chatCompletion({
|
105 |
model: "${conversation.model.id}",
|
106 |
-
messages: ${formattedMessages({ sep:
|
107 |
-
${formattedConfig({ sep:
|
108 |
seed: 0,
|
109 |
});
|
110 |
|
111 |
-
console.log(out.choices[0].message)
|
112 |
});
|
113 |
}
|
114 |
|
@@ -132,13 +132,13 @@ console.log(out.choices[0].message);`
|
|
132 |
|
133 |
const snippets: Snippet[] = [];
|
134 |
snippets.push({
|
135 |
-
label:
|
136 |
-
language:
|
137 |
-
code: `pip install huggingface_hub
|
138 |
});
|
139 |
if (conversation.streaming) {
|
140 |
snippets.push({
|
141 |
-
label:
|
142 |
code: `from huggingface_hub import InferenceClient
|
143 |
|
144 |
model_id="${conversation.model.id}"
|
@@ -147,28 +147,28 @@ inference_client = InferenceClient(model_id, token=hf_token)
|
|
147 |
|
148 |
output = ""
|
149 |
|
150 |
-
messages = ${formattedMessages({ sep:
|
151 |
|
152 |
-
for token in client.chat_completion(messages, stream=True, ${formattedConfig({ sep:
|
153 |
new_content = token.choices[0].delta.content
|
154 |
print(new_content, end="")
|
155 |
-
output += new_content
|
156 |
});
|
157 |
} else {
|
158 |
// non-streaming
|
159 |
snippets.push({
|
160 |
-
label:
|
161 |
code: `from huggingface_hub import InferenceClient
|
162 |
|
163 |
model_id="${conversation.model.id}"
|
164 |
hf_token = "your HF token"
|
165 |
inference_client = InferenceClient(model_id, token=hf_token)
|
166 |
|
167 |
-
messages = ${formattedMessages({ sep:
|
168 |
|
169 |
-
output = inference_client.chat_completion(messages, ${formattedConfig({ sep:
|
170 |
|
171 |
-
print(output.choices[0].message)
|
172 |
});
|
173 |
}
|
174 |
|
@@ -194,29 +194,29 @@ print(output.choices[0].message)`
|
|
194 |
|
195 |
if (conversation.streaming) {
|
196 |
snippets.push({
|
197 |
-
label:
|
198 |
code: `curl 'https://api-inference.huggingface.co/models/${conversation.model.id}/v1/chat/completions' \\
|
199 |
--header "Authorization: Bearer {YOUR_HF_TOKEN}" \\
|
200 |
--header 'Content-Type: application/json' \\
|
201 |
--data '{
|
202 |
"model": "${conversation.model.id}",
|
203 |
-
"messages": ${formattedMessages({ sep:
|
204 |
-
${formattedConfig({ sep:
|
205 |
"stream": true
|
206 |
-
}'
|
207 |
});
|
208 |
} else {
|
209 |
// non-streaming
|
210 |
snippets.push({
|
211 |
-
label:
|
212 |
code: `curl 'https://api-inference.huggingface.co/models/${conversation.model.id}/v1/chat/completions' \\
|
213 |
--header "Authorization: Bearer {YOUR_HF_TOKEN}" \\
|
214 |
--header 'Content-Type: application/json' \\
|
215 |
--data '{
|
216 |
"model": "${conversation.model.id}",
|
217 |
-
"messages": ${formattedMessages({ sep:
|
218 |
-
${formattedConfig({ sep:
|
219 |
-
}'
|
220 |
});
|
221 |
}
|
222 |
|
@@ -254,15 +254,15 @@ print(output.choices[0].message)`
|
|
254 |
<h2 class="font-semibold">{label}</h2>
|
255 |
<button
|
256 |
class="flex items-center gap-x-1.5 rounded-md bg-gray-200 px-1.5 py-0.5 text-sm transition dark:bg-gray-950"
|
257 |
-
on:click={
|
258 |
const el = e.currentTarget;
|
259 |
-
el.classList.add(
|
260 |
navigator.clipboard.writeText(code);
|
261 |
if (timeout) {
|
262 |
clearTimeout(timeout);
|
263 |
}
|
264 |
timeout = setTimeout(() => {
|
265 |
-
el.classList.remove(
|
266 |
}, 1000);
|
267 |
}}
|
268 |
>
|
|
|
1 |
<script lang="ts">
|
2 |
+
import hljs from "highlight.js/lib/core";
|
3 |
+
import javascript from "highlight.js/lib/languages/javascript";
|
4 |
+
import python from "highlight.js/lib/languages/python";
|
5 |
+
import http from "highlight.js/lib/languages/http";
|
6 |
+
import type { Conversation } from "$lib/types";
|
7 |
+
import IconCopyCode from "../Icons/IconCopyCode.svelte";
|
8 |
+
import { onDestroy } from "svelte";
|
9 |
+
|
10 |
+
hljs.registerLanguage("javascript", javascript);
|
11 |
+
hljs.registerLanguage("python", python);
|
12 |
+
hljs.registerLanguage("http", http);
|
13 |
|
14 |
export let conversation: Conversation;
|
15 |
|
16 |
+
const lanuages = ["javascript", "python", "http"];
|
17 |
type Language = (typeof lanuages)[number];
|
18 |
const labelsByLanguage: Record<Language, string> = {
|
19 |
+
javascript: "JavaScript",
|
20 |
+
python: "Python",
|
21 |
+
http: "Curl",
|
22 |
};
|
23 |
|
24 |
interface Snippet {
|
|
|
30 |
$: snippetsByLanguage = {
|
31 |
javascript: getJavascriptSnippets(conversation),
|
32 |
python: getPythonSnippets(conversation),
|
33 |
+
http: getHttpSnippets(conversation),
|
34 |
};
|
35 |
|
36 |
+
let selectedLanguage: Language = "javascript";
|
37 |
let timeout: ReturnType<typeof setTimeout>;
|
38 |
|
39 |
function getMessages() {
|
40 |
+
const placeholder = [{ role: "user", content: "Tell me a story" }];
|
41 |
let messages = conversation.messages;
|
42 |
+
if (messages.length === 1 && messages[0].role === "user" && !messages[0].content) {
|
43 |
messages = placeholder;
|
44 |
}
|
45 |
return messages;
|
|
|
66 |
|
67 |
const snippets: Snippet[] = [];
|
68 |
snippets.push({
|
69 |
+
label: "Install @huggingface/inference",
|
70 |
+
language: "http",
|
71 |
+
code: `npm install --save @huggingface/inference`,
|
72 |
});
|
73 |
if (conversation.streaming) {
|
74 |
snippets.push({
|
75 |
+
label: "Streaming API",
|
76 |
code: `import { HfInference } from "@huggingface/inference"
|
77 |
|
78 |
const inference = new HfInference("your HF token")
|
|
|
81 |
|
82 |
for await (const chunk of inference.chatCompletionStream({
|
83 |
model: "${conversation.model.id}",
|
84 |
+
messages: ${formattedMessages({ sep: ",\n ", start: "[\n ", end: "\n ]" })},
|
85 |
+
${formattedConfig({ sep: ",\n ", start: "", end: "" })},
|
86 |
seed: 0,
|
87 |
})) {
|
88 |
if (chunk.choices && chunk.choices.length > 0) {
|
|
|
91 |
console.clear();
|
92 |
console.log(out);
|
93 |
}
|
94 |
+
}`,
|
95 |
});
|
96 |
} else {
|
97 |
// non-streaming
|
98 |
snippets.push({
|
99 |
+
label: "Non-Streaming API",
|
100 |
code: `import { HfInference } from '@huggingface/inference'
|
101 |
|
102 |
const inference = new HfInference("your access token")
|
103 |
|
104 |
const out = await inference.chatCompletion({
|
105 |
model: "${conversation.model.id}",
|
106 |
+
messages: ${formattedMessages({ sep: ",\n ", start: "[\n ", end: "\n ]" })},
|
107 |
+
${formattedConfig({ sep: ",\n ", start: "", end: "" })},
|
108 |
seed: 0,
|
109 |
});
|
110 |
|
111 |
+
console.log(out.choices[0].message);`,
|
112 |
});
|
113 |
}
|
114 |
|
|
|
132 |
|
133 |
const snippets: Snippet[] = [];
|
134 |
snippets.push({
|
135 |
+
label: "Install huggingface_hub",
|
136 |
+
language: "http",
|
137 |
+
code: `pip install huggingface_hub`,
|
138 |
});
|
139 |
if (conversation.streaming) {
|
140 |
snippets.push({
|
141 |
+
label: "Streaming API",
|
142 |
code: `from huggingface_hub import InferenceClient
|
143 |
|
144 |
model_id="${conversation.model.id}"
|
|
|
147 |
|
148 |
output = ""
|
149 |
|
150 |
+
messages = ${formattedMessages({ sep: ",\n ", start: `[\n `, end: `\n]` })}
|
151 |
|
152 |
+
for token in client.chat_completion(messages, stream=True, ${formattedConfig({ sep: ", ", start: "", end: "" })}):
|
153 |
new_content = token.choices[0].delta.content
|
154 |
print(new_content, end="")
|
155 |
+
output += new_content`,
|
156 |
});
|
157 |
} else {
|
158 |
// non-streaming
|
159 |
snippets.push({
|
160 |
+
label: "Non-Streaming API",
|
161 |
code: `from huggingface_hub import InferenceClient
|
162 |
|
163 |
model_id="${conversation.model.id}"
|
164 |
hf_token = "your HF token"
|
165 |
inference_client = InferenceClient(model_id, token=hf_token)
|
166 |
|
167 |
+
messages = ${formattedMessages({ sep: ",\n ", start: `[\n `, end: `\n]` })}
|
168 |
|
169 |
+
output = inference_client.chat_completion(messages, ${formattedConfig({ sep: ", ", start: "", end: "" })})
|
170 |
|
171 |
+
print(output.choices[0].message)`,
|
172 |
});
|
173 |
}
|
174 |
|
|
|
194 |
|
195 |
if (conversation.streaming) {
|
196 |
snippets.push({
|
197 |
+
label: "Streaming API",
|
198 |
code: `curl 'https://api-inference.huggingface.co/models/${conversation.model.id}/v1/chat/completions' \\
|
199 |
--header "Authorization: Bearer {YOUR_HF_TOKEN}" \\
|
200 |
--header 'Content-Type: application/json' \\
|
201 |
--data '{
|
202 |
"model": "${conversation.model.id}",
|
203 |
+
"messages": ${formattedMessages({ sep: ",\n ", start: `[\n `, end: `\n]` })},
|
204 |
+
${formattedConfig({ sep: ",\n ", start: "", end: "" })},
|
205 |
"stream": true
|
206 |
+
}'`,
|
207 |
});
|
208 |
} else {
|
209 |
// non-streaming
|
210 |
snippets.push({
|
211 |
+
label: "Non-Streaming API",
|
212 |
code: `curl 'https://api-inference.huggingface.co/models/${conversation.model.id}/v1/chat/completions' \\
|
213 |
--header "Authorization: Bearer {YOUR_HF_TOKEN}" \\
|
214 |
--header 'Content-Type: application/json' \\
|
215 |
--data '{
|
216 |
"model": "${conversation.model.id}",
|
217 |
+
"messages": ${formattedMessages({ sep: ",\n ", start: `[\n `, end: `\n]` })},
|
218 |
+
${formattedConfig({ sep: ",\n ", start: "", end: "" })}
|
219 |
+
}'`,
|
220 |
});
|
221 |
}
|
222 |
|
|
|
254 |
<h2 class="font-semibold">{label}</h2>
|
255 |
<button
|
256 |
class="flex items-center gap-x-1.5 rounded-md bg-gray-200 px-1.5 py-0.5 text-sm transition dark:bg-gray-950"
|
257 |
+
on:click={e => {
|
258 |
const el = e.currentTarget;
|
259 |
+
el.classList.add("text-green-500");
|
260 |
navigator.clipboard.writeText(code);
|
261 |
if (timeout) {
|
262 |
clearTimeout(timeout);
|
263 |
}
|
264 |
timeout = setTimeout(() => {
|
265 |
+
el.classList.remove("text-green-500");
|
266 |
}, 1000);
|
267 |
}}
|
268 |
>
|
src/lib/components/InferencePlayground/InferencePlaygroundConversation.svelte
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import { createEventDispatcher } from
|
3 |
-
import CodeSnippets from
|
4 |
-
import Message from
|
5 |
-
import IconPlus from
|
6 |
-
import type { Conversation } from
|
7 |
|
8 |
export let loading;
|
9 |
export let conversation: Conversation;
|
@@ -40,14 +40,14 @@
|
|
40 |
<Message
|
41 |
class="border-b"
|
42 |
{message}
|
43 |
-
on:delete={() => dispatch(
|
44 |
autofocus={!loading && messageIdx === conversation.messages.length - 1}
|
45 |
/>
|
46 |
{/each}
|
47 |
|
48 |
<button
|
49 |
class="flex px-6 py-6 hover:bg-gray-50 dark:hover:bg-gray-800/50"
|
50 |
-
on:click={() => dispatch(
|
51 |
disabled={loading}
|
52 |
>
|
53 |
<div class="flex items-center gap-2 !p-0 text-sm font-semibold">
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { createEventDispatcher } from "svelte";
|
3 |
+
import CodeSnippets from "./InferencePlaygroundCodeSnippets.svelte";
|
4 |
+
import Message from "./InferencePlaygroundMessage.svelte";
|
5 |
+
import IconPlus from "../Icons/IconPlus.svelte";
|
6 |
+
import type { Conversation } from "$lib/types";
|
7 |
|
8 |
export let loading;
|
9 |
export let conversation: Conversation;
|
|
|
40 |
<Message
|
41 |
class="border-b"
|
42 |
{message}
|
43 |
+
on:delete={() => dispatch("deleteMessage", messageIdx)}
|
44 |
autofocus={!loading && messageIdx === conversation.messages.length - 1}
|
45 |
/>
|
46 |
{/each}
|
47 |
|
48 |
<button
|
49 |
class="flex px-6 py-6 hover:bg-gray-50 dark:hover:bg-gray-800/50"
|
50 |
+
on:click={() => dispatch("addMessage")}
|
51 |
disabled={loading}
|
52 |
>
|
53 |
<div class="flex items-center gap-2 !p-0 text-sm font-semibold">
|
src/lib/components/InferencePlayground/InferencePlaygroundGenerationConfig.svelte
CHANGED
@@ -1,27 +1,26 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type { Conversation } from
|
3 |
import {
|
4 |
GENERATION_CONFIG_KEYS,
|
5 |
GENERATION_CONFIG_KEYS_ADVANCED,
|
6 |
-
GENERATION_CONFIG_SETTINGS
|
7 |
-
} from
|
8 |
|
9 |
export let conversation: Conversation;
|
10 |
-
export let classNames =
|
11 |
|
12 |
$: modelMaxLength = conversation.model.tokenizerConfig.model_max_length;
|
13 |
-
$: maxTokens = Math.min(modelMaxLength ?? GENERATION_CONFIG_SETTINGS[
|
14 |
</script>
|
15 |
|
16 |
<div class="flex flex-col gap-y-7 {classNames}">
|
17 |
{#each GENERATION_CONFIG_KEYS as key}
|
18 |
{@const { label, min, step } = GENERATION_CONFIG_SETTINGS[key]}
|
19 |
-
{@const max = key ===
|
20 |
<div>
|
21 |
<div class="flex items-center justify-between">
|
22 |
-
<label
|
23 |
-
|
24 |
-
class="mb-2 block text-sm font-medium text-gray-900 dark:text-white">{label}</label
|
25 |
>
|
26 |
<input
|
27 |
type="number"
|
@@ -51,9 +50,7 @@
|
|
51 |
{@const settings = GENERATION_CONFIG_SETTINGS[key]}
|
52 |
<div>
|
53 |
<div class="flex items-center justify-between">
|
54 |
-
<label
|
55 |
-
for="temperature-range"
|
56 |
-
class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
|
57 |
>{settings.label}</label
|
58 |
>
|
59 |
<input
|
@@ -63,7 +60,7 @@
|
|
63 |
max={settings.max}
|
64 |
step={settings.step}
|
65 |
value={conversation.config[key] ?? settings.default}
|
66 |
-
on:input={
|
67 |
/>
|
68 |
</div>
|
69 |
<input
|
@@ -73,7 +70,7 @@
|
|
73 |
max={settings.max}
|
74 |
step={settings.step}
|
75 |
value={conversation.config[key] ?? settings.default}
|
76 |
-
on:input={
|
77 |
class="h-2 w-full cursor-pointer appearance-none rounded-lg bg-gray-200 accent-black dark:bg-gray-700 dark:accent-blue-500"
|
78 |
/>
|
79 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
+
import type { Conversation } from "$lib/types";
|
3 |
import {
|
4 |
GENERATION_CONFIG_KEYS,
|
5 |
GENERATION_CONFIG_KEYS_ADVANCED,
|
6 |
+
GENERATION_CONFIG_SETTINGS,
|
7 |
+
} from "./generationConfigSettings";
|
8 |
|
9 |
export let conversation: Conversation;
|
10 |
+
export let classNames = "";
|
11 |
|
12 |
$: modelMaxLength = conversation.model.tokenizerConfig.model_max_length;
|
13 |
+
$: maxTokens = Math.min(modelMaxLength ?? GENERATION_CONFIG_SETTINGS["max_tokens"].max, 64_000);
|
14 |
</script>
|
15 |
|
16 |
<div class="flex flex-col gap-y-7 {classNames}">
|
17 |
{#each GENERATION_CONFIG_KEYS as key}
|
18 |
{@const { label, min, step } = GENERATION_CONFIG_SETTINGS[key]}
|
19 |
+
{@const max = key === "max_tokens" ? maxTokens : GENERATION_CONFIG_SETTINGS[key].max}
|
20 |
<div>
|
21 |
<div class="flex items-center justify-between">
|
22 |
+
<label for="temperature-range" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
|
23 |
+
>{label}</label
|
|
|
24 |
>
|
25 |
<input
|
26 |
type="number"
|
|
|
50 |
{@const settings = GENERATION_CONFIG_SETTINGS[key]}
|
51 |
<div>
|
52 |
<div class="flex items-center justify-between">
|
53 |
+
<label for="temperature-range" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
|
|
|
|
|
54 |
>{settings.label}</label
|
55 |
>
|
56 |
<input
|
|
|
60 |
max={settings.max}
|
61 |
step={settings.step}
|
62 |
value={conversation.config[key] ?? settings.default}
|
63 |
+
on:input={e => (conversation.config[key] = Number(e.currentTarget.value))}
|
64 |
/>
|
65 |
</div>
|
66 |
<input
|
|
|
70 |
max={settings.max}
|
71 |
step={settings.step}
|
72 |
value={conversation.config[key] ?? settings.default}
|
73 |
+
on:input={e => (conversation.config[key] = Number(e.currentTarget.value))}
|
74 |
class="h-2 w-full cursor-pointer appearance-none rounded-lg bg-gray-200 accent-black dark:bg-gray-700 dark:accent-blue-500"
|
75 |
/>
|
76 |
</div>
|
src/lib/components/InferencePlayground/InferencePlaygroundHFTokenModal.svelte
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
<!-- Main modal -->
|
2 |
<script lang="ts">
|
3 |
-
import { createEventDispatcher, onDestroy, onMount } from
|
4 |
-
import { browser } from
|
5 |
-
import IconCross from
|
6 |
|
7 |
let backdropEl: HTMLDivElement;
|
8 |
let modalEl: HTMLDivElement;
|
@@ -11,9 +11,9 @@
|
|
11 |
|
12 |
function handleKeydown(event: KeyboardEvent) {
|
13 |
// close on ESC
|
14 |
-
if (event.key ===
|
15 |
event.preventDefault();
|
16 |
-
dispatch(
|
17 |
}
|
18 |
}
|
19 |
|
@@ -22,12 +22,12 @@
|
|
22 |
return;
|
23 |
}
|
24 |
if (event.target === backdropEl) {
|
25 |
-
dispatch(
|
26 |
}
|
27 |
}
|
28 |
|
29 |
onMount(() => {
|
30 |
-
document.getElementById(
|
31 |
modalEl.focus();
|
32 |
});
|
33 |
|
@@ -35,7 +35,7 @@
|
|
35 |
if (!browser) return;
|
36 |
// remove inert attribute if this is the last modal
|
37 |
if (document.querySelectorAll('[role="dialog"]:not(#app *)').length === 1) {
|
38 |
-
document.getElementById(
|
39 |
}
|
40 |
});
|
41 |
</script>
|
@@ -56,9 +56,7 @@
|
|
56 |
on:keydown={handleKeydown}
|
57 |
>
|
58 |
<form on:submit|preventDefault class="relative rounded-lg bg-white shadow dark:bg-gray-900">
|
59 |
-
<div
|
60 |
-
class="flex items-center justify-between rounded-t border-b p-4 md:px-5 md:py-4 dark:border-gray-600"
|
61 |
-
>
|
62 |
<h3 class="flex items-center gap-2.5 text-lg font-semibold text-gray-900 dark:text-white">
|
63 |
<img
|
64 |
alt="Hugging Face's logo"
|
@@ -68,7 +66,7 @@
|
|
68 |
</h3>
|
69 |
<button
|
70 |
type="button"
|
71 |
-
on:click={() => dispatch(
|
72 |
class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white"
|
73 |
>
|
74 |
<IconCross classNames="text-xl" />
|
@@ -98,9 +96,7 @@
|
|
98 |
</div>
|
99 |
|
100 |
<!-- Modal footer -->
|
101 |
-
<div
|
102 |
-
class="flex items-center justify-between rounded-b border-t border-gray-200 p-4 md:p-5 dark:border-gray-600"
|
103 |
-
>
|
104 |
<a
|
105 |
href="https://huggingface.co/settings/tokens?new_token=true"
|
106 |
tabindex="-1"
|
|
|
1 |
<!-- Main modal -->
|
2 |
<script lang="ts">
|
3 |
+
import { createEventDispatcher, onDestroy, onMount } from "svelte";
|
4 |
+
import { browser } from "$app/environment";
|
5 |
+
import IconCross from "../Icons/IconCross.svelte";
|
6 |
|
7 |
let backdropEl: HTMLDivElement;
|
8 |
let modalEl: HTMLDivElement;
|
|
|
11 |
|
12 |
function handleKeydown(event: KeyboardEvent) {
|
13 |
// close on ESC
|
14 |
+
if (event.key === "Escape") {
|
15 |
event.preventDefault();
|
16 |
+
dispatch("close");
|
17 |
}
|
18 |
}
|
19 |
|
|
|
22 |
return;
|
23 |
}
|
24 |
if (event.target === backdropEl) {
|
25 |
+
dispatch("close");
|
26 |
}
|
27 |
}
|
28 |
|
29 |
onMount(() => {
|
30 |
+
document.getElementById("app")?.setAttribute("inert", "true");
|
31 |
modalEl.focus();
|
32 |
});
|
33 |
|
|
|
35 |
if (!browser) return;
|
36 |
// remove inert attribute if this is the last modal
|
37 |
if (document.querySelectorAll('[role="dialog"]:not(#app *)').length === 1) {
|
38 |
+
document.getElementById("app")?.removeAttribute("inert");
|
39 |
}
|
40 |
});
|
41 |
</script>
|
|
|
56 |
on:keydown={handleKeydown}
|
57 |
>
|
58 |
<form on:submit|preventDefault class="relative rounded-lg bg-white shadow dark:bg-gray-900">
|
59 |
+
<div class="flex items-center justify-between rounded-t border-b p-4 md:px-5 md:py-4 dark:border-gray-600">
|
|
|
|
|
60 |
<h3 class="flex items-center gap-2.5 text-lg font-semibold text-gray-900 dark:text-white">
|
61 |
<img
|
62 |
alt="Hugging Face's logo"
|
|
|
66 |
</h3>
|
67 |
<button
|
68 |
type="button"
|
69 |
+
on:click={() => dispatch("close")}
|
70 |
class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white"
|
71 |
>
|
72 |
<IconCross classNames="text-xl" />
|
|
|
96 |
</div>
|
97 |
|
98 |
<!-- Modal footer -->
|
99 |
+
<div class="flex items-center justify-between rounded-b border-t border-gray-200 p-4 md:p-5 dark:border-gray-600">
|
|
|
|
|
100 |
<a
|
101 |
href="https://huggingface.co/settings/tokens?new_token=true"
|
102 |
tabindex="-1"
|
src/lib/components/InferencePlayground/InferencePlaygroundMessage.svelte
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import { createEventDispatcher } from
|
3 |
-
import { type ChatCompletionInputMessage } from
|
4 |
|
5 |
export let message: ChatCompletionInputMessage;
|
6 |
export let autofocus: boolean = false;
|
@@ -24,7 +24,7 @@
|
|
24 |
<button
|
25 |
tabindex="1"
|
26 |
on:click={() => {
|
27 |
-
dispatch(
|
28 |
}}
|
29 |
type="button"
|
30 |
class="mt-1.5 hidden size-8 rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 group-hover/message:block 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"
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { createEventDispatcher } from "svelte";
|
3 |
+
import { type ChatCompletionInputMessage } from "@huggingface/tasks";
|
4 |
|
5 |
export let message: ChatCompletionInputMessage;
|
6 |
export let autofocus: boolean = false;
|
|
|
24 |
<button
|
25 |
tabindex="1"
|
26 |
on:click={() => {
|
27 |
+
dispatch("delete");
|
28 |
}}
|
29 |
type="button"
|
30 |
class="mt-1.5 hidden size-8 rounded-lg border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 group-hover/message:block 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"
|
src/lib/components/InferencePlayground/InferencePlaygroundModelSelector.svelte
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type { Conversation, ModelEntryWithTokenizer } from
|
3 |
-
import IconCaret from
|
4 |
-
import ModelSelectorModal from
|
5 |
|
6 |
export let models: ModelEntryWithTokenizer[] = [];
|
7 |
export let conversation: Conversation;
|
@@ -21,28 +21,26 @@
|
|
21 |
}
|
22 |
|
23 |
function changeModel(modelId: string) {
|
24 |
-
const model = models.find(
|
25 |
if (!model) {
|
26 |
return;
|
27 |
}
|
28 |
conversation.model = model;
|
29 |
}
|
30 |
|
31 |
-
$: [nameSpace, modelName] = conversation.model.id.split(
|
32 |
</script>
|
33 |
|
34 |
{#if showModelPickerModal}
|
35 |
<ModelSelectorModal
|
36 |
{models}
|
37 |
-
on:modelSelected={
|
38 |
-
on:close={
|
39 |
/>
|
40 |
{/if}
|
41 |
|
42 |
<div class="flex flex-col gap-2">
|
43 |
-
<label
|
44 |
-
for="countries"
|
45 |
-
class="flex items-baseline text-sm font-medium text-gray-900 dark:text-white"
|
46 |
>Models<span class="ml-4 font-normal text-gray-400">{models.length}</span>
|
47 |
</label>
|
48 |
|
@@ -53,11 +51,7 @@
|
|
53 |
<div class="flex flex-col items-start">
|
54 |
<div class="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-300">
|
55 |
{#await getAvatarUrl(nameSpace) then avatarUrl}
|
56 |
-
<img
|
57 |
-
class="size-3 flex-none rounded bg-gray-200 object-cover"
|
58 |
-
src={avatarUrl}
|
59 |
-
alt="{nameSpace} avatar"
|
60 |
-
/>
|
61 |
{/await}
|
62 |
{nameSpace}
|
63 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
+
import type { Conversation, ModelEntryWithTokenizer } from "$lib/types";
|
3 |
+
import IconCaret from "../Icons/IconCaret.svelte";
|
4 |
+
import ModelSelectorModal from "./InferencePlaygroundModelSelectorModal.svelte";
|
5 |
|
6 |
export let models: ModelEntryWithTokenizer[] = [];
|
7 |
export let conversation: Conversation;
|
|
|
21 |
}
|
22 |
|
23 |
function changeModel(modelId: string) {
|
24 |
+
const model = models.find(m => m.id === modelId);
|
25 |
if (!model) {
|
26 |
return;
|
27 |
}
|
28 |
conversation.model = model;
|
29 |
}
|
30 |
|
31 |
+
$: [nameSpace, modelName] = conversation.model.id.split("/");
|
32 |
</script>
|
33 |
|
34 |
{#if showModelPickerModal}
|
35 |
<ModelSelectorModal
|
36 |
{models}
|
37 |
+
on:modelSelected={e => changeModel(e.detail)}
|
38 |
+
on:close={e => (showModelPickerModal = false)}
|
39 |
/>
|
40 |
{/if}
|
41 |
|
42 |
<div class="flex flex-col gap-2">
|
43 |
+
<label for="countries" class="flex items-baseline text-sm font-medium text-gray-900 dark:text-white"
|
|
|
|
|
44 |
>Models<span class="ml-4 font-normal text-gray-400">{models.length}</span>
|
45 |
</label>
|
46 |
|
|
|
51 |
<div class="flex flex-col items-start">
|
52 |
<div class="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-300">
|
53 |
{#await getAvatarUrl(nameSpace) then avatarUrl}
|
54 |
+
<img class="size-3 flex-none rounded bg-gray-200 object-cover" src={avatarUrl} alt="{nameSpace} avatar" />
|
|
|
|
|
|
|
|
|
55 |
{/await}
|
56 |
{nameSpace}
|
57 |
</div>
|
src/lib/components/InferencePlayground/InferencePlaygroundModelSelectorModal.svelte
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type { ModelEntryWithTokenizer } from
|
3 |
-
import { createEventDispatcher } from
|
4 |
-
import IconSearch from
|
5 |
-
import IconStar from
|
6 |
|
7 |
export let models: ModelEntryWithTokenizer[];
|
8 |
|
@@ -12,9 +12,9 @@
|
|
12 |
|
13 |
function handleKeydown(event: KeyboardEvent) {
|
14 |
// close on ESC
|
15 |
-
if (event.key ===
|
16 |
event.preventDefault();
|
17 |
-
dispatch(
|
18 |
}
|
19 |
}
|
20 |
|
@@ -23,7 +23,7 @@
|
|
23 |
return;
|
24 |
}
|
25 |
if (event.target === backdropEl) {
|
26 |
-
dispatch(
|
27 |
}
|
28 |
}
|
29 |
</script>
|
@@ -36,9 +36,7 @@
|
|
36 |
on:click|stopPropagation={handleBackdropClick}
|
37 |
>
|
38 |
<div class="flex w-full max-w-[600px] items-start justify-center p-10">
|
39 |
-
<div
|
40 |
-
class="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md"
|
41 |
-
>
|
42 |
<div class="flex items-center border-b px-3">
|
43 |
<IconSearch classNames="mr-2 text-sm" />
|
44 |
<input
|
@@ -55,15 +53,17 @@
|
|
55 |
<div class="flex cursor-pointer items-center px-2 py-1.5 text-sm hover:bg-gray-100">
|
56 |
<IconStar classNames="lucide lucide-star mr-2 h-4 w-4 text-yellow-400" />
|
57 |
<span class="inline-flex items-center"
|
58 |
-
><span class="text-gray-500">meta-llama</span><span class="mx-1 text-black">/</span
|
59 |
-
|
|
|
60 |
>
|
61 |
</div>
|
62 |
<div class="flex cursor-pointer items-center px-2 py-1.5 text-sm hover:bg-gray-100">
|
63 |
<IconStar classNames="lucide lucide-star mr-2 h-4 w-4 text-yellow-400" />
|
64 |
<span class="inline-flex items-center"
|
65 |
-
><span class="text-gray-500">mistralai</span><span class="mx-1 text-black">/</span
|
66 |
-
|
|
|
67 |
>
|
68 |
</div>
|
69 |
</div>
|
@@ -73,18 +73,18 @@
|
|
73 |
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Other Models</div>
|
74 |
<div>
|
75 |
{#each models as model}
|
76 |
-
{@const [nameSpace, modelName] = model.id.split(
|
77 |
<button
|
78 |
class="flex cursor-pointer items-center px-2 py-1.5 text-sm hover:bg-gray-100"
|
79 |
on:click={() => {
|
80 |
-
dispatch(
|
81 |
-
dispatch(
|
82 |
}}
|
83 |
>
|
84 |
<span class="inline-flex items-center"
|
85 |
-
><span class="text-gray-500">{nameSpace}</span><span class="mx-1 text-black"
|
86 |
-
|
87 |
-
|
88 |
>
|
89 |
</button>
|
90 |
{/each}
|
|
|
1 |
<script lang="ts">
|
2 |
+
import type { ModelEntryWithTokenizer } from "$lib/types";
|
3 |
+
import { createEventDispatcher } from "svelte";
|
4 |
+
import IconSearch from "../Icons/IconSearch.svelte";
|
5 |
+
import IconStar from "../Icons/IconStar.svelte";
|
6 |
|
7 |
export let models: ModelEntryWithTokenizer[];
|
8 |
|
|
|
12 |
|
13 |
function handleKeydown(event: KeyboardEvent) {
|
14 |
// close on ESC
|
15 |
+
if (event.key === "Escape") {
|
16 |
event.preventDefault();
|
17 |
+
dispatch("close");
|
18 |
}
|
19 |
}
|
20 |
|
|
|
23 |
return;
|
24 |
}
|
25 |
if (event.target === backdropEl) {
|
26 |
+
dispatch("close");
|
27 |
}
|
28 |
}
|
29 |
</script>
|
|
|
36 |
on:click|stopPropagation={handleBackdropClick}
|
37 |
>
|
38 |
<div class="flex w-full max-w-[600px] items-start justify-center p-10">
|
39 |
+
<div class="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md">
|
|
|
|
|
40 |
<div class="flex items-center border-b px-3">
|
41 |
<IconSearch classNames="mr-2 text-sm" />
|
42 |
<input
|
|
|
53 |
<div class="flex cursor-pointer items-center px-2 py-1.5 text-sm hover:bg-gray-100">
|
54 |
<IconStar classNames="lucide lucide-star mr-2 h-4 w-4 text-yellow-400" />
|
55 |
<span class="inline-flex items-center"
|
56 |
+
><span class="text-gray-500">meta-llama</span><span class="mx-1 text-black">/</span><span
|
57 |
+
class="text-black">Meta-Llama-3-70B-Instruct</span
|
58 |
+
></span
|
59 |
>
|
60 |
</div>
|
61 |
<div class="flex cursor-pointer items-center px-2 py-1.5 text-sm hover:bg-gray-100">
|
62 |
<IconStar classNames="lucide lucide-star mr-2 h-4 w-4 text-yellow-400" />
|
63 |
<span class="inline-flex items-center"
|
64 |
+
><span class="text-gray-500">mistralai</span><span class="mx-1 text-black">/</span><span
|
65 |
+
class="text-black">Mixtral-8x7B-Instruct-v0.1</span
|
66 |
+
></span
|
67 |
>
|
68 |
</div>
|
69 |
</div>
|
|
|
73 |
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Other Models</div>
|
74 |
<div>
|
75 |
{#each models as model}
|
76 |
+
{@const [nameSpace, modelName] = model.id.split("/")}
|
77 |
<button
|
78 |
class="flex cursor-pointer items-center px-2 py-1.5 text-sm hover:bg-gray-100"
|
79 |
on:click={() => {
|
80 |
+
dispatch("modelSelected", model.id);
|
81 |
+
dispatch("close");
|
82 |
}}
|
83 |
>
|
84 |
<span class="inline-flex items-center"
|
85 |
+
><span class="text-gray-500">{nameSpace}</span><span class="mx-1 text-black">/</span><span
|
86 |
+
class="text-black">{modelName}</span
|
87 |
+
></span
|
88 |
>
|
89 |
</button>
|
90 |
{/each}
|
src/lib/components/InferencePlayground/generationConfigSettings.ts
CHANGED
@@ -12,47 +12,43 @@ export const GENERATION_CONFIG_SETTINGS: Record<string, GenerationKeySettings> =
|
|
12 |
step: 0.01,
|
13 |
min: 0,
|
14 |
max: 2,
|
15 |
-
label:
|
16 |
},
|
17 |
max_tokens: {
|
18 |
default: 512,
|
19 |
step: 1,
|
20 |
min: 1,
|
21 |
max: 8192, // changed dynamically based on model
|
22 |
-
label:
|
23 |
},
|
24 |
top_p: {
|
25 |
default: 0.7,
|
26 |
step: 0.01,
|
27 |
min: 0,
|
28 |
max: 1,
|
29 |
-
label:
|
30 |
},
|
31 |
top_k: {
|
32 |
default: 50,
|
33 |
step: 1,
|
34 |
min: 1,
|
35 |
max: 100,
|
36 |
-
label:
|
37 |
},
|
38 |
repetition_penalty: {
|
39 |
default: 1,
|
40 |
step: 0.01,
|
41 |
min: 1,
|
42 |
max: 2,
|
43 |
-
label:
|
44 |
-
}
|
45 |
};
|
46 |
|
47 |
export type GenerationConfigKey = keyof typeof GENERATION_CONFIG_SETTINGS;
|
48 |
|
49 |
-
export const GENERATION_CONFIG_KEYS: GenerationConfigKey[] = [
|
50 |
|
51 |
-
export const GENERATION_CONFIG_KEYS_ADVANCED: GenerationConfigKey[] = [
|
52 |
-
'top_p',
|
53 |
-
'top_k',
|
54 |
-
'repetition_penalty'
|
55 |
-
];
|
56 |
|
57 |
export type GenerationConfig = Record<GenerationConfigKey, number>;
|
58 |
|
|
|
12 |
step: 0.01,
|
13 |
min: 0,
|
14 |
max: 2,
|
15 |
+
label: "Temperature",
|
16 |
},
|
17 |
max_tokens: {
|
18 |
default: 512,
|
19 |
step: 1,
|
20 |
min: 1,
|
21 |
max: 8192, // changed dynamically based on model
|
22 |
+
label: "Max Tokens",
|
23 |
},
|
24 |
top_p: {
|
25 |
default: 0.7,
|
26 |
step: 0.01,
|
27 |
min: 0,
|
28 |
max: 1,
|
29 |
+
label: "Top-P",
|
30 |
},
|
31 |
top_k: {
|
32 |
default: 50,
|
33 |
step: 1,
|
34 |
min: 1,
|
35 |
max: 100,
|
36 |
+
label: "Top-K",
|
37 |
},
|
38 |
repetition_penalty: {
|
39 |
default: 1,
|
40 |
step: 0.01,
|
41 |
min: 1,
|
42 |
max: 2,
|
43 |
+
label: "Repetition Penalty",
|
44 |
+
},
|
45 |
};
|
46 |
|
47 |
export type GenerationConfigKey = keyof typeof GENERATION_CONFIG_SETTINGS;
|
48 |
|
49 |
+
export const GENERATION_CONFIG_KEYS: GenerationConfigKey[] = ["temperature", "max_tokens"];
|
50 |
|
51 |
+
export const GENERATION_CONFIG_KEYS_ADVANCED: GenerationConfigKey[] = ["top_p", "top_k", "repetition_penalty"];
|
|
|
|
|
|
|
|
|
52 |
|
53 |
export type GenerationConfig = Record<GenerationConfigKey, number>;
|
54 |
|
src/lib/components/InferencePlayground/inferencePlaygroundUtils.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
import { type ChatCompletionInputMessage } from
|
2 |
-
import { HfInference } from
|
3 |
-
import type { Conversation, ModelEntryWithTokenizer } from
|
4 |
|
5 |
export function createHfInference(token: string): HfInference {
|
6 |
return new HfInference(token);
|
@@ -14,18 +14,16 @@ export async function handleStreamingResponse(
|
|
14 |
systemMessage?: ChatCompletionInputMessage
|
15 |
): Promise<void> {
|
16 |
const messages = [
|
17 |
-
...(isSystemPromptSupported(conversation.model) && systemMessage?.content?.length
|
18 |
-
|
19 |
-
: []),
|
20 |
-
...conversation.messages
|
21 |
];
|
22 |
-
let out =
|
23 |
for await (const chunk of hf.chatCompletionStream(
|
24 |
{
|
25 |
model: conversation.model.id,
|
26 |
messages,
|
27 |
temperature: conversation.config.temperature,
|
28 |
-
max_tokens: conversation.config.maxTokens
|
29 |
},
|
30 |
{ signal: abortController.signal }
|
31 |
)) {
|
@@ -42,25 +40,23 @@ export async function handleNonStreamingResponse(
|
|
42 |
systemMessage?: ChatCompletionInputMessage
|
43 |
): Promise<ChatCompletionInputMessage> {
|
44 |
const messages = [
|
45 |
-
...(isSystemPromptSupported(conversation.model) && systemMessage?.content?.length
|
46 |
-
|
47 |
-
: []),
|
48 |
-
...conversation.messages
|
49 |
];
|
50 |
|
51 |
const response = await hf.chatCompletion({
|
52 |
model: conversation.model,
|
53 |
messages,
|
54 |
temperature: conversation.config.temperature,
|
55 |
-
max_tokens: conversation.config.maxTokens
|
56 |
});
|
57 |
|
58 |
if (response.choices && response.choices.length > 0) {
|
59 |
return response.choices[0].message;
|
60 |
}
|
61 |
-
throw new Error(
|
62 |
}
|
63 |
|
64 |
export function isSystemPromptSupported(model: ModelEntryWithTokenizer) {
|
65 |
-
return model.tokenizerConfig?.chat_template?.includes(
|
66 |
}
|
|
|
1 |
+
import { type ChatCompletionInputMessage } from "@huggingface/tasks";
|
2 |
+
import { HfInference } from "@huggingface/inference";
|
3 |
+
import type { Conversation, ModelEntryWithTokenizer } from "$lib/types";
|
4 |
|
5 |
export function createHfInference(token: string): HfInference {
|
6 |
return new HfInference(token);
|
|
|
14 |
systemMessage?: ChatCompletionInputMessage
|
15 |
): Promise<void> {
|
16 |
const messages = [
|
17 |
+
...(isSystemPromptSupported(conversation.model) && systemMessage?.content?.length ? [systemMessage] : []),
|
18 |
+
...conversation.messages,
|
|
|
|
|
19 |
];
|
20 |
+
let out = "";
|
21 |
for await (const chunk of hf.chatCompletionStream(
|
22 |
{
|
23 |
model: conversation.model.id,
|
24 |
messages,
|
25 |
temperature: conversation.config.temperature,
|
26 |
+
max_tokens: conversation.config.maxTokens,
|
27 |
},
|
28 |
{ signal: abortController.signal }
|
29 |
)) {
|
|
|
40 |
systemMessage?: ChatCompletionInputMessage
|
41 |
): Promise<ChatCompletionInputMessage> {
|
42 |
const messages = [
|
43 |
+
...(isSystemPromptSupported(conversation.model) && systemMessage?.content?.length ? [systemMessage] : []),
|
44 |
+
...conversation.messages,
|
|
|
|
|
45 |
];
|
46 |
|
47 |
const response = await hf.chatCompletion({
|
48 |
model: conversation.model,
|
49 |
messages,
|
50 |
temperature: conversation.config.temperature,
|
51 |
+
max_tokens: conversation.config.maxTokens,
|
52 |
});
|
53 |
|
54 |
if (response.choices && response.choices.length > 0) {
|
55 |
return response.choices[0].message;
|
56 |
}
|
57 |
+
throw new Error("No response from the model");
|
58 |
}
|
59 |
|
60 |
export function isSystemPromptSupported(model: ModelEntryWithTokenizer) {
|
61 |
+
return model.tokenizerConfig?.chat_template?.includes("system");
|
62 |
}
|
src/lib/types/index.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
import type { GenerationConfig } from
|
2 |
-
import type { ModelEntry } from
|
3 |
-
import type { ChatCompletionInputMessage } from
|
4 |
|
5 |
type Conversation = {
|
6 |
model: ModelEntryWithTokenizer;
|
|
|
1 |
+
import type { GenerationConfig } from "$lib/components/InferencePlayground/generationConfigSettings";
|
2 |
+
import type { ModelEntry } from "@huggingface/hub";
|
3 |
+
import type { ChatCompletionInputMessage } from "@huggingface/tasks";
|
4 |
|
5 |
type Conversation = {
|
6 |
model: ModelEntryWithTokenizer;
|
src/routes/+layout.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script>
|
2 |
-
import
|
3 |
</script>
|
4 |
|
5 |
<slot></slot>
|
|
|
1 |
<script>
|
2 |
+
import "../app.css";
|
3 |
</script>
|
4 |
|
5 |
<slot></slot>
|
src/routes/+page.server.ts
CHANGED
@@ -1,22 +1,21 @@
|
|
1 |
-
import type { ModelEntryWithTokenizer } from
|
2 |
-
import type { ModelEntry } from
|
3 |
-
import type { PageServerLoad } from
|
4 |
-
import { env } from
|
5 |
|
6 |
export const load: PageServerLoad = async ({ fetch }) => {
|
7 |
-
const apiUrl =
|
8 |
-
'https://huggingface.co/api/models?pipeline_tag=text-generation&inference=Warm&filter=conversational';
|
9 |
const HF_TOKEN = env.HF_TOKEN;
|
10 |
|
11 |
const res = await fetch(apiUrl, {
|
12 |
headers: {
|
13 |
-
Authorization: `Bearer ${HF_TOKEN}
|
14 |
-
}
|
15 |
});
|
16 |
const compatibleModels: ModelEntry[] = await res.json();
|
17 |
compatibleModels.sort((a, b) => a.id.toLowerCase().localeCompare(b.id.toLowerCase()));
|
18 |
|
19 |
-
const promises = compatibleModels.map(async
|
20 |
const configUrl = `https://huggingface.co/${model.modelId}/raw/main/tokenizer_config.json`;
|
21 |
const res = await fetch(configUrl);
|
22 |
if (!res.ok) {
|
@@ -26,9 +25,7 @@ export const load: PageServerLoad = async ({ fetch }) => {
|
|
26 |
return { ...model, tokenizerConfig } satisfies ModelEntryWithTokenizer;
|
27 |
});
|
28 |
|
29 |
-
const models: ModelEntryWithTokenizer[] = (await Promise.all(promises)).filter(
|
30 |
-
(model) => model !== null
|
31 |
-
);
|
32 |
|
33 |
return { models };
|
34 |
};
|
|
|
1 |
+
import type { ModelEntryWithTokenizer } from "$lib/types";
|
2 |
+
import type { ModelEntry } from "@huggingface/hub";
|
3 |
+
import type { PageServerLoad } from "./$types";
|
4 |
+
import { env } from "$env/dynamic/private";
|
5 |
|
6 |
export const load: PageServerLoad = async ({ fetch }) => {
|
7 |
+
const apiUrl = "https://huggingface.co/api/models?pipeline_tag=text-generation&inference=Warm&filter=conversational";
|
|
|
8 |
const HF_TOKEN = env.HF_TOKEN;
|
9 |
|
10 |
const res = await fetch(apiUrl, {
|
11 |
headers: {
|
12 |
+
Authorization: `Bearer ${HF_TOKEN}`,
|
13 |
+
},
|
14 |
});
|
15 |
const compatibleModels: ModelEntry[] = await res.json();
|
16 |
compatibleModels.sort((a, b) => a.id.toLowerCase().localeCompare(b.id.toLowerCase()));
|
17 |
|
18 |
+
const promises = compatibleModels.map(async model => {
|
19 |
const configUrl = `https://huggingface.co/${model.modelId}/raw/main/tokenizer_config.json`;
|
20 |
const res = await fetch(configUrl);
|
21 |
if (!res.ok) {
|
|
|
25 |
return { ...model, tokenizerConfig } satisfies ModelEntryWithTokenizer;
|
26 |
});
|
27 |
|
28 |
+
const models: ModelEntryWithTokenizer[] = (await Promise.all(promises)).filter(model => model !== null);
|
|
|
|
|
29 |
|
30 |
return { models };
|
31 |
};
|
src/routes/+page.svelte
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<script lang="ts">
|
2 |
export let data;
|
3 |
-
import InferencePlayground from
|
4 |
</script>
|
5 |
|
6 |
<InferencePlayground models={data.models} />
|
|
|
1 |
<script lang="ts">
|
2 |
export let data;
|
3 |
+
import InferencePlayground from "$lib/components/InferencePlayground/InferencePlayground.svelte";
|
4 |
</script>
|
5 |
|
6 |
<InferencePlayground models={data.models} />
|
svelte.config.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
import adapter from
|
2 |
-
import { vitePreprocess } from
|
3 |
|
4 |
/** @type {import('@sveltejs/kit').Config} */
|
5 |
const config = {
|
@@ -11,8 +11,8 @@ const config = {
|
|
11 |
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
12 |
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
13 |
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
14 |
-
adapter: adapter()
|
15 |
-
}
|
16 |
};
|
17 |
|
18 |
export default config;
|
|
|
1 |
+
import adapter from "@sveltejs/adapter-node";
|
2 |
+
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
3 |
|
4 |
/** @type {import('@sveltejs/kit').Config} */
|
5 |
const config = {
|
|
|
11 |
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
12 |
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
13 |
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
14 |
+
adapter: adapter(),
|
15 |
+
},
|
16 |
};
|
17 |
|
18 |
export default config;
|
tailwind.config.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1 |
-
import type { Config } from
|
2 |
-
import containerQueries from
|
3 |
|
4 |
export default {
|
5 |
-
content: [
|
6 |
|
7 |
theme: {
|
8 |
-
extend: {}
|
9 |
},
|
10 |
|
11 |
-
plugins: [containerQueries]
|
12 |
} as Config;
|
|
|
1 |
+
import type { Config } from "tailwindcss";
|
2 |
+
import containerQueries from "@tailwindcss/container-queries";
|
3 |
|
4 |
export default {
|
5 |
+
content: ["./src/**/*.{html,js,svelte,ts}"],
|
6 |
|
7 |
theme: {
|
8 |
+
extend: {},
|
9 |
},
|
10 |
|
11 |
+
plugins: [containerQueries],
|
12 |
} as Config;
|
vite.config.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
import { sveltekit } from
|
2 |
-
import { defineConfig } from
|
3 |
|
4 |
export default defineConfig({
|
5 |
-
plugins: [sveltekit()]
|
6 |
});
|
|
|
1 |
+
import { sveltekit } from "@sveltejs/kit/vite";
|
2 |
+
import { defineConfig } from "vite";
|
3 |
|
4 |
export default defineConfig({
|
5 |
+
plugins: [sveltekit()],
|
6 |
});
|