Thomas G. Lopes
commited on
Adjustments (#86)
Browse files- src/lib/components/dialog.svelte +3 -2
- src/lib/components/inference-playground/checkpoints-menu.svelte +6 -1
- src/lib/components/inference-playground/custom-provider-select.svelte +1 -1
- src/lib/components/inference-playground/generation-config.svelte +23 -18
- src/lib/components/inference-playground/model-selector.svelte +0 -2
- src/lib/components/inference-playground/playground.svelte +4 -5
- src/lib/components/inference-playground/schema-property.svelte +309 -0
- src/lib/components/inference-playground/structured-output-modal.svelte +48 -147
- src/lib/components/inference-playground/utils.svelte.ts +44 -29
- src/lib/components/local-toasts.svelte +81 -9
- src/lib/components/share-modal.svelte +1 -1
- src/lib/data/context_length.json +20 -21
- src/lib/state/conversations.svelte.ts +0 -8
- src/lib/state/models.svelte.ts +8 -1
- src/lib/state/projects.svelte.ts +10 -7
- src/lib/utils/object.svelte.ts +18 -0
src/lib/components/dialog.svelte
CHANGED
@@ -11,9 +11,10 @@
|
|
11 |
onClose?: () => void;
|
12 |
open: boolean;
|
13 |
onSubmit?: EventHandler<SubmitEvent>;
|
|
|
14 |
}
|
15 |
|
16 |
-
let { children, onClose, open, title, footer, onSubmit }: Props = $props();
|
17 |
|
18 |
let dialog: HTMLDialogElement | undefined = $state();
|
19 |
|
@@ -30,7 +31,7 @@
|
|
30 |
{#if open}
|
31 |
<form class="fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-black/85" onsubmit={onSubmit}>
|
32 |
<div
|
33 |
-
class="relative w-xl rounded-xl bg-white shadow-sm dark:bg-gray-900"
|
34 |
{@attach clickOutside(() => onClose?.())}
|
35 |
>
|
36 |
<div class="flex items-center justify-between rounded-t border-b p-4 md:px-5 md:py-4 dark:border-gray-800">
|
|
|
11 |
onClose?: () => void;
|
12 |
open: boolean;
|
13 |
onSubmit?: EventHandler<SubmitEvent>;
|
14 |
+
class?: string;
|
15 |
}
|
16 |
|
17 |
+
let { children, onClose, open, title, footer, onSubmit, class: classes }: Props = $props();
|
18 |
|
19 |
let dialog: HTMLDialogElement | undefined = $state();
|
20 |
|
|
|
31 |
{#if open}
|
32 |
<form class="fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-black/85" onsubmit={onSubmit}>
|
33 |
<div
|
34 |
+
class={["relative w-xl rounded-xl bg-white shadow-sm dark:bg-gray-900", classes]}
|
35 |
{@attach clickOutside(() => onClose?.())}
|
36 |
>
|
37 |
<div class="flex items-center justify-between rounded-t border-b p-4 md:px-5 md:py-4 dark:border-gray-800">
|
src/lib/components/inference-playground/checkpoints-menu.svelte
CHANGED
@@ -147,7 +147,12 @@
|
|
147 |
>
|
148 |
<p class="text-2xs pl-1.5 font-mono font-medium text-gray-500 uppercase">
|
149 |
temp: {conversation.config.temperature}
|
150 |
-
|
|
|
|
|
|
|
|
|
|
|
151 |
</p>
|
152 |
{#each iterate(sliced) as [msg, isLast]}
|
153 |
<div class="flex flex-col gap-1 p-2">
|
|
|
147 |
>
|
148 |
<p class="text-2xs pl-1.5 font-mono font-medium text-gray-500 uppercase">
|
149 |
temp: {conversation.config.temperature}
|
150 |
+
{#if conversation.config.max_tokens}
|
151 |
+
| max tokens: {conversation.config.max_tokens}
|
152 |
+
{/if}
|
153 |
+
{#if conversation.structuredOutput?.enabled}
|
154 |
+
| structured output
|
155 |
+
{/if}
|
156 |
</p>
|
157 |
{#each iterate(sliced) as [msg, isLast]}
|
158 |
<div class="flex flex-col gap-1 p-2">
|
src/lib/components/inference-playground/custom-provider-select.svelte
CHANGED
@@ -30,7 +30,7 @@
|
|
30 |
},
|
31 |
});
|
32 |
|
33 |
-
const nameMap: Record<InferenceProvider, string
|
34 |
"sambanova": "SambaNova",
|
35 |
"fal-ai": "fal",
|
36 |
"cerebras": "Cerebras",
|
|
|
30 |
},
|
31 |
});
|
32 |
|
33 |
+
const nameMap: Partial<Record<InferenceProvider, string>> = {
|
34 |
"sambanova": "SambaNova",
|
35 |
"fal-ai": "fal",
|
36 |
"cerebras": "Cerebras",
|
src/lib/components/inference-playground/generation-config.svelte
CHANGED
@@ -6,6 +6,7 @@
|
|
6 |
import { GENERATION_CONFIG_KEYS, GENERATION_CONFIG_SETTINGS } from "./generation-config-settings.js";
|
7 |
import StructuredOutputModal from "./structured-output-modal.svelte";
|
8 |
import { maxAllowedTokens } from "./utils.svelte.js";
|
|
|
9 |
|
10 |
interface Props {
|
11 |
conversation: ConversationClass;
|
@@ -99,24 +100,28 @@
|
|
99 |
></div>
|
100 |
</label>
|
101 |
|
102 |
-
|
103 |
-
|
104 |
-
<
|
105 |
-
<
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
|
|
|
|
|
|
|
|
120 |
</div>
|
121 |
|
122 |
<StructuredOutputModal {conversation} bind:open={editingStructuredOutput} />
|
|
|
6 |
import { GENERATION_CONFIG_KEYS, GENERATION_CONFIG_SETTINGS } from "./generation-config-settings.js";
|
7 |
import StructuredOutputModal from "./structured-output-modal.svelte";
|
8 |
import { maxAllowedTokens } from "./utils.svelte.js";
|
9 |
+
import { structuredForbiddenProviders } from "$lib/state/models.svelte.js";
|
10 |
|
11 |
interface Props {
|
12 |
conversation: ConversationClass;
|
|
|
100 |
></div>
|
101 |
</label>
|
102 |
|
103 |
+
<!-- eslint-disable-next-line @typescript-eslint/no-explicit-any -->
|
104 |
+
{#if !structuredForbiddenProviders.includes(conversation.data.provider as any)}
|
105 |
+
<label class="mt-2 flex cursor-pointer items-center justify-between" for="structured-output">
|
106 |
+
<span class="text-sm font-medium text-gray-900 dark:text-gray-300">Structured Output</span>
|
107 |
+
<div class="flex items-center gap-2">
|
108 |
+
<input
|
109 |
+
type="checkbox"
|
110 |
+
bind:checked={
|
111 |
+
() => conversation.data.structuredOutput?.enabled,
|
112 |
+
v =>
|
113 |
+
conversation.update({ structuredOutput: { ...conversation.data.structuredOutput, enabled: v ?? false } })
|
114 |
+
}
|
115 |
+
class="peer sr-only"
|
116 |
+
id="structured-output"
|
117 |
+
/>
|
118 |
+
<button class="btn-mini" type="button" onclick={() => (editingStructuredOutput = true)}> edit </button>
|
119 |
+
<div
|
120 |
+
class="peer relative h-5 w-9 rounded-full bg-gray-200 peer-checked:bg-black peer-focus:outline-hidden after:absolute after:start-[2px] after:top-[2px] after:h-4 after:w-4 after:rounded-full after:border after:border-gray-300 after:bg-white after:transition-all after:content-[''] peer-checked:after:translate-x-full peer-checked:after:border-white dark:border-gray-600 dark:bg-gray-700 dark:peer-checked:bg-blue-600"
|
121 |
+
></div>
|
122 |
+
</div>
|
123 |
+
</label>
|
124 |
+
{/if}
|
125 |
</div>
|
126 |
|
127 |
<StructuredOutputModal {conversation} bind:open={editingStructuredOutput} />
|
src/lib/components/inference-playground/model-selector.svelte
CHANGED
@@ -6,7 +6,6 @@
|
|
6 |
import Avatar from "../avatar.svelte";
|
7 |
import ModelSelectorModal from "./model-selector-modal.svelte";
|
8 |
import ProviderSelect from "./provider-select.svelte";
|
9 |
-
import { defaultSystemMessage } from "./utils.svelte.js";
|
10 |
|
11 |
interface Props {
|
12 |
conversation: ConversationClass;
|
@@ -24,7 +23,6 @@
|
|
24 |
}
|
25 |
conversation.update({
|
26 |
modelId: model.id,
|
27 |
-
systemMessage: { role: "system", content: defaultSystemMessage?.[modelId] ?? "" },
|
28 |
provider: undefined,
|
29 |
});
|
30 |
}
|
|
|
6 |
import Avatar from "../avatar.svelte";
|
7 |
import ModelSelectorModal from "./model-selector-modal.svelte";
|
8 |
import ProviderSelect from "./provider-select.svelte";
|
|
|
9 |
|
10 |
interface Props {
|
11 |
conversation: ConversationClass;
|
|
|
23 |
}
|
24 |
conversation.update({
|
25 |
modelId: model.id,
|
|
|
26 |
provider: undefined,
|
27 |
});
|
28 |
}
|
src/lib/components/inference-playground/playground.svelte
CHANGED
@@ -105,11 +105,10 @@
|
|
105 |
placeholder={systemPromptSupported
|
106 |
? "Enter a custom prompt"
|
107 |
: "System prompt is not supported with the chosen model."}
|
108 |
-
value={systemPromptSupported ?
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
}
|
113 |
}}
|
114 |
class="absolute inset-x-0 bottom-0 h-full resize-none bg-transparent px-3 pt-10 text-sm outline-hidden"
|
115 |
></textarea>
|
|
|
105 |
placeholder={systemPromptSupported
|
106 |
? "Enter a custom prompt"
|
107 |
: "System prompt is not supported with the chosen model."}
|
108 |
+
value={systemPromptSupported ? (projects.current?.systemMessage ?? "") : ""}
|
109 |
+
onchange={e => {
|
110 |
+
if (!projects.current) return;
|
111 |
+
projects.update({ ...projects.current, systemMessage: e.currentTarget.value });
|
|
|
112 |
}}
|
113 |
class="absolute inset-x-0 bottom-0 h-full resize-none bg-transparent px-3 pt-10 text-sm outline-hidden"
|
114 |
></textarea>
|
src/lib/components/inference-playground/schema-property.svelte
ADDED
@@ -0,0 +1,309 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts" module>
|
2 |
+
const propertyTypes = ["string", "integer", "number", "boolean", "object", "enum", "array"] as const;
|
3 |
+
export type PropertyType = (typeof propertyTypes)[number];
|
4 |
+
|
5 |
+
export type PropertyDefinition = {
|
6 |
+
type: PropertyType;
|
7 |
+
description?: string;
|
8 |
+
enum?: string[];
|
9 |
+
properties?: { [key: string]: PropertyDefinition };
|
10 |
+
items?: PropertyDefinition;
|
11 |
+
};
|
12 |
+
|
13 |
+
// Example:
|
14 |
+
// {
|
15 |
+
// "type": "object",
|
16 |
+
// "properties": {
|
17 |
+
// "static": {
|
18 |
+
// "type": "string"
|
19 |
+
// },
|
20 |
+
// "array": {
|
21 |
+
// "type": "array",
|
22 |
+
// "items": {
|
23 |
+
// "type": "string"
|
24 |
+
// }
|
25 |
+
// },
|
26 |
+
// "enum": {
|
27 |
+
// "type": "string",
|
28 |
+
// "enum": [
|
29 |
+
// "V1",
|
30 |
+
// "V2",
|
31 |
+
// "V3"
|
32 |
+
// ]
|
33 |
+
// },
|
34 |
+
// "object": {
|
35 |
+
// "type": "object",
|
36 |
+
// "properties": {
|
37 |
+
// "key1": {
|
38 |
+
// "type": "string"
|
39 |
+
// },
|
40 |
+
// "key2": {
|
41 |
+
// "type": "string"
|
42 |
+
// }
|
43 |
+
// }
|
44 |
+
// }
|
45 |
+
// }
|
46 |
+
// }
|
47 |
+
</script>
|
48 |
+
|
49 |
+
<script lang="ts">
|
50 |
+
import { onchange } from "$lib/utils/template.js";
|
51 |
+
import IconX from "~icons/carbon/close";
|
52 |
+
import IconAdd from "~icons/carbon/add-large";
|
53 |
+
import SchemaProperty from "./schema-property.svelte";
|
54 |
+
import Tooltip from "../tooltip.svelte";
|
55 |
+
|
56 |
+
type Props = {
|
57 |
+
name: string;
|
58 |
+
definition: PropertyDefinition;
|
59 |
+
required?: boolean;
|
60 |
+
nesting?: number;
|
61 |
+
onDelete: () => void;
|
62 |
+
};
|
63 |
+
|
64 |
+
let { name = $bindable(), definition = $bindable(), onDelete, required = $bindable(), nesting = 0 }: Props = $props();
|
65 |
+
|
66 |
+
// If isArray, this will be the inner type of the array. Otherwise it will be the definition itself.
|
67 |
+
const innerDefinition = {
|
68 |
+
get $() {
|
69 |
+
if (definition.type === "array") {
|
70 |
+
return definition.items ?? { type: "string" };
|
71 |
+
}
|
72 |
+
return definition;
|
73 |
+
},
|
74 |
+
set $(v) {
|
75 |
+
if (isArray.current) {
|
76 |
+
definition = { ...definition, items: v };
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
|
80 |
+
definition = v;
|
81 |
+
},
|
82 |
+
};
|
83 |
+
|
84 |
+
const type = {
|
85 |
+
get $() {
|
86 |
+
return "enum" in innerDefinition.$ ? "enum" : innerDefinition.$.type;
|
87 |
+
},
|
88 |
+
set $(v) {
|
89 |
+
delete definition.enum;
|
90 |
+
delete definition.properties;
|
91 |
+
|
92 |
+
const inner = { type: v === "enum" ? "string" : v } as PropertyDefinition;
|
93 |
+
if (v === "enum") inner.enum = [];
|
94 |
+
|
95 |
+
if (definition.type === "array") {
|
96 |
+
definition = { ...definition, items: inner };
|
97 |
+
}
|
98 |
+
|
99 |
+
definition = { ...definition, ...inner };
|
100 |
+
},
|
101 |
+
};
|
102 |
+
|
103 |
+
const isArray = {
|
104 |
+
get current() {
|
105 |
+
return definition.type === "array";
|
106 |
+
},
|
107 |
+
set current(v) {
|
108 |
+
delete definition.enum;
|
109 |
+
delete definition.properties;
|
110 |
+
|
111 |
+
if (v) {
|
112 |
+
definition = { ...definition, type: "array", items: { type: definition.type } };
|
113 |
+
} else {
|
114 |
+
const prevType = definition.items?.type ?? "string";
|
115 |
+
delete definition.items;
|
116 |
+
definition = { ...definition, type: prevType };
|
117 |
+
}
|
118 |
+
},
|
119 |
+
};
|
120 |
+
|
121 |
+
const nestingClasses = [
|
122 |
+
"border-gray-300 dark:border-gray-700",
|
123 |
+
"border-gray-300 dark:border-gray-600",
|
124 |
+
"border-gray-300 dark:border-gray-500",
|
125 |
+
"border-gray-300 dark:border-gray-600",
|
126 |
+
];
|
127 |
+
</script>
|
128 |
+
|
129 |
+
<div
|
130 |
+
class={[
|
131 |
+
"relative space-y-2 border-l-2 bg-white py-2 pl-4 dark:bg-gray-900",
|
132 |
+
...nestingClasses.map((c, i) => {
|
133 |
+
return nesting % nestingClasses.length === i && c;
|
134 |
+
}),
|
135 |
+
]}
|
136 |
+
>
|
137 |
+
<div class="flex gap-2">
|
138 |
+
<div class="grow">
|
139 |
+
<label for="{name}-name" class="block text-xs font-medium text-gray-500 dark:text-gray-400"> Name </label>
|
140 |
+
<input
|
141 |
+
type="text"
|
142 |
+
id="{name}-name"
|
143 |
+
class="mt-1 w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
144 |
+
value={name}
|
145 |
+
{...onchange(v => (name = v))}
|
146 |
+
/>
|
147 |
+
</div>
|
148 |
+
|
149 |
+
<div class="grow">
|
150 |
+
<label for="{name}-type" class="block text-xs font-medium text-gray-500 dark:text-gray-400"> Type </label>
|
151 |
+
<select
|
152 |
+
id="{name}-type"
|
153 |
+
class="mt-1 w-full rounded-md border border-gray-300 bg-white px-2 py-1.25 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
154 |
+
bind:value={() => type.$, v => (type.$ = v)}
|
155 |
+
>
|
156 |
+
{#each propertyTypes.filter(t => t !== "array") as type}
|
157 |
+
<option value={type}>{type}</option>
|
158 |
+
{/each}
|
159 |
+
</select>
|
160 |
+
</div>
|
161 |
+
{#if type.$ === "object"}
|
162 |
+
<Tooltip>
|
163 |
+
{#snippet trigger(tooltip)}
|
164 |
+
<button
|
165 |
+
type="button"
|
166 |
+
class="btn-xs self-end rounded-md"
|
167 |
+
onclick={() => {
|
168 |
+
const prevProperties = innerDefinition.$.properties || {};
|
169 |
+
innerDefinition.$ = { ...innerDefinition.$, properties: { ...prevProperties, "": { type: "string" } } };
|
170 |
+
}}
|
171 |
+
aria-label="Add nested"
|
172 |
+
{...tooltip.trigger}
|
173 |
+
>
|
174 |
+
<IconAdd />
|
175 |
+
</button>
|
176 |
+
{/snippet}
|
177 |
+
Add nested property
|
178 |
+
</Tooltip>
|
179 |
+
{/if}
|
180 |
+
{#if type.$ === "enum"}
|
181 |
+
<Tooltip>
|
182 |
+
{#snippet trigger(tooltip)}
|
183 |
+
<button
|
184 |
+
type="button"
|
185 |
+
class="btn-xs self-end rounded-md"
|
186 |
+
onclick={() => {
|
187 |
+
const prevValues = innerDefinition.$.enum || [];
|
188 |
+
innerDefinition.$ = { ...innerDefinition.$, enum: [...prevValues, ""] };
|
189 |
+
}}
|
190 |
+
aria-label="Add enum value"
|
191 |
+
{...tooltip.trigger}
|
192 |
+
>
|
193 |
+
<IconAdd />
|
194 |
+
</button>
|
195 |
+
{/snippet}
|
196 |
+
Add enum value
|
197 |
+
</Tooltip>
|
198 |
+
{/if}
|
199 |
+
<button
|
200 |
+
type="button"
|
201 |
+
class="btn-xs self-end rounded-md text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-500"
|
202 |
+
onclick={onDelete}
|
203 |
+
aria-label="delete"
|
204 |
+
>
|
205 |
+
<IconX />
|
206 |
+
</button>
|
207 |
+
</div>
|
208 |
+
|
209 |
+
{#if !nesting}
|
210 |
+
<div class="flex items-start">
|
211 |
+
<div class="flex h-5 items-center">
|
212 |
+
<input
|
213 |
+
id="required-{name}"
|
214 |
+
name="required-{name}"
|
215 |
+
type="checkbox"
|
216 |
+
class="h-4 w-4 rounded border border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800"
|
217 |
+
bind:checked={required}
|
218 |
+
/>
|
219 |
+
</div>
|
220 |
+
<div class="ml-3 text-sm">
|
221 |
+
<label for="required-{name}" class="font-medium text-gray-700 dark:text-gray-300"> Required </label>
|
222 |
+
</div>
|
223 |
+
</div>
|
224 |
+
{/if}
|
225 |
+
|
226 |
+
<div class="flex items-start">
|
227 |
+
<div class="flex h-5 items-center">
|
228 |
+
<input
|
229 |
+
id="is-array-{name}"
|
230 |
+
name="is-array-{name}"
|
231 |
+
type="checkbox"
|
232 |
+
class="h-4 w-4 rounded border border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800"
|
233 |
+
bind:checked={isArray.current}
|
234 |
+
/>
|
235 |
+
</div>
|
236 |
+
<div class="ml-3 text-sm">
|
237 |
+
<label for="is-array-{name}" class="font-medium text-gray-700 dark:text-gray-300"> Array </label>
|
238 |
+
</div>
|
239 |
+
</div>
|
240 |
+
|
241 |
+
{#if type.$ === "object"}
|
242 |
+
{#each Object.entries(innerDefinition.$.properties ?? {}) as [propertyName, propertyDefinition], index (index)}
|
243 |
+
<SchemaProperty
|
244 |
+
bind:name={
|
245 |
+
() => propertyName,
|
246 |
+
value => {
|
247 |
+
const nd = { ...innerDefinition.$ };
|
248 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
249 |
+
nd.properties![value] = innerDefinition.$.properties![propertyName] as any;
|
250 |
+
delete nd.properties![propertyName];
|
251 |
+
innerDefinition.$ = nd;
|
252 |
+
}
|
253 |
+
}
|
254 |
+
bind:definition={
|
255 |
+
() => propertyDefinition,
|
256 |
+
v => {
|
257 |
+
innerDefinition.$.properties![propertyName] = v;
|
258 |
+
innerDefinition.$ = innerDefinition.$;
|
259 |
+
}
|
260 |
+
}
|
261 |
+
onDelete={() => {
|
262 |
+
delete innerDefinition.$.properties![propertyName];
|
263 |
+
innerDefinition.$ = innerDefinition.$;
|
264 |
+
}}
|
265 |
+
nesting={nesting + 1}
|
266 |
+
/>
|
267 |
+
{/each}
|
268 |
+
{/if}
|
269 |
+
|
270 |
+
{#if "enum" in innerDefinition.$}
|
271 |
+
<p class="text-xs font-medium text-gray-500 dark:text-gray-400">Values</p>
|
272 |
+
{#each innerDefinition.$.enum ?? [] as val, index (index)}
|
273 |
+
<div
|
274 |
+
class={[
|
275 |
+
"flex border-l-2 pl-2",
|
276 |
+
...nestingClasses.map((c, i) => {
|
277 |
+
return (nesting + 1) % nestingClasses.length === i && c;
|
278 |
+
}),
|
279 |
+
]}
|
280 |
+
>
|
281 |
+
<input
|
282 |
+
id="{name}-enum-{index}"
|
283 |
+
class="block w-full rounded-md border border-gray-300 bg-white px-2 py-1
|
284 |
+
text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
285 |
+
type="text"
|
286 |
+
value={val}
|
287 |
+
{...onchange(v => {
|
288 |
+
innerDefinition.$.enum = innerDefinition.$.enum ?? [];
|
289 |
+
innerDefinition.$.enum[index] = v;
|
290 |
+
innerDefinition.$ = innerDefinition.$;
|
291 |
+
})}
|
292 |
+
/>
|
293 |
+
<button
|
294 |
+
type="button"
|
295 |
+
class="btn-xs ml-2 rounded-md text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-500"
|
296 |
+
onclick={() => {
|
297 |
+
innerDefinition.$.enum = innerDefinition.$.enum ?? [];
|
298 |
+
innerDefinition.$.enum.splice(index, 1);
|
299 |
+
innerDefinition.$ = innerDefinition.$;
|
300 |
+
}}
|
301 |
+
>
|
302 |
+
<IconX />
|
303 |
+
</button>
|
304 |
+
</div>
|
305 |
+
{:else}
|
306 |
+
<p class="mt-2 text-xs italic text-gray-400">No enum values defined.</p>
|
307 |
+
{/each}
|
308 |
+
{/if}
|
309 |
+
</div>
|
src/lib/components/inference-playground/structured-output-modal.svelte
CHANGED
@@ -1,16 +1,16 @@
|
|
1 |
<script lang="ts">
|
|
|
2 |
import { Synced } from "$lib/spells/synced.svelte";
|
3 |
import { TextareaAutosize } from "$lib/spells/textarea-autosize.svelte";
|
4 |
import type { ConversationClass } from "$lib/state/conversations.svelte.js";
|
5 |
import { safeParse } from "$lib/utils/json.js";
|
6 |
-
import { keys } from "$lib/utils/object.svelte";
|
7 |
import { onchange, oninput } from "$lib/utils/template.js";
|
8 |
import { RadioGroup } from "melt/builders";
|
9 |
import { codeToHtml } from "shiki";
|
10 |
import typia from "typia";
|
11 |
-
import IconX from "~icons/carbon/close";
|
12 |
import Dialog from "../dialog.svelte";
|
13 |
-
import {
|
14 |
|
15 |
interface Props {
|
16 |
conversation: ConversationClass;
|
@@ -27,11 +27,9 @@
|
|
27 |
});
|
28 |
|
29 |
type Schema = {
|
30 |
-
name?: string;
|
31 |
-
description?: string;
|
32 |
schema?: {
|
33 |
type?: string;
|
34 |
-
properties?: { [key: string]:
|
35 |
required?: string[];
|
36 |
additionalProperties?: boolean;
|
37 |
};
|
@@ -76,8 +74,6 @@
|
|
76 |
keys(v.schema?.properties ?? {}).includes(name)
|
77 |
);
|
78 |
const validated: Schema = {
|
79 |
-
name: v.name,
|
80 |
-
description: v.description,
|
81 |
schema: {
|
82 |
...v.schema,
|
83 |
required,
|
@@ -110,7 +106,7 @@
|
|
110 |
});
|
111 |
</script>
|
112 |
|
113 |
-
<Dialog title="Edit Structured Output" {open} onClose={() => (open = false)}>
|
114 |
<div class="flex justify-end">
|
115 |
<div
|
116 |
class="flex items-center gap-0.5 rounded-md border border-gray-300 bg-white p-0.5 text-sm dark:border-gray-600 dark:bg-gray-800"
|
@@ -133,150 +129,55 @@
|
|
133 |
|
134 |
{#if radioGroup.value === "form"}
|
135 |
<div class="fade-y -mx-2 mt-2 -mb-4 max-h-200 space-y-4 overflow-auto px-2 py-4 text-left">
|
136 |
-
<!-- Top-level properties -->
|
137 |
-
<div>
|
138 |
-
<label for="schema-name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Name</label>
|
139 |
-
<input
|
140 |
-
type="text"
|
141 |
-
id="schema-name"
|
142 |
-
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
143 |
-
value={schemaObj.current.name}
|
144 |
-
{...onchange(value => updateSchema({ name: value }))}
|
145 |
-
/>
|
146 |
-
</div>
|
147 |
-
|
148 |
-
<div>
|
149 |
-
<label for="schema-description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
150 |
-
Description
|
151 |
-
</label>
|
152 |
-
<textarea
|
153 |
-
id="schema-description"
|
154 |
-
rows="3"
|
155 |
-
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
156 |
-
value={schemaObj.current.description}
|
157 |
-
{...onchange(value => updateSchema({ description: value }))}
|
158 |
-
></textarea>
|
159 |
-
</div>
|
160 |
-
|
161 |
<!-- Properties Section -->
|
162 |
<div class="border-t border-gray-200 pt-4 dark:border-gray-700">
|
163 |
<h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100">Properties</h3>
|
164 |
{#if schemaObj.current.schema?.properties}
|
165 |
<div class="mt-3 space-y-3">
|
166 |
-
{#each Object.entries(schemaObj.current.schema.properties) as [propertyName, propertyDefinition]
|
167 |
-
<
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
id="{propertyName}-name"
|
177 |
-
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
178 |
-
value={propertyName}
|
179 |
-
{...onchange(value => {
|
180 |
-
const updatedProperties = { ...schemaObj.current.schema?.properties };
|
181 |
-
if (!updatedProperties || !updatedProperties[propertyName]) return;
|
182 |
-
updatedProperties[value] = updatedProperties[propertyName];
|
183 |
-
delete updatedProperties[propertyName];
|
184 |
-
updateSchemaNested({ properties: updatedProperties });
|
185 |
-
})}
|
186 |
-
/>
|
187 |
-
</div>
|
188 |
-
|
189 |
-
<button
|
190 |
-
type="button"
|
191 |
-
class="absolute top-2 right-2 text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-500"
|
192 |
-
onclick={() => {
|
193 |
-
const updatedProperties = { ...schemaObj.current.schema?.properties };
|
194 |
-
if (!updatedProperties || !updatedProperties[propertyName]) return;
|
195 |
-
delete updatedProperties[propertyName];
|
196 |
updateSchemaNested({ properties: updatedProperties });
|
197 |
-
}
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
updateSchemaNested({ properties: updatedProperties });
|
217 |
-
}
|
218 |
}
|
|
|
|
|
219 |
}
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
</div>
|
231 |
-
|
232 |
-
<div>
|
233 |
-
<label
|
234 |
-
for="{propertyName}-description"
|
235 |
-
class="block text-xs font-medium text-gray-500 dark:text-gray-400">Description</label
|
236 |
-
>
|
237 |
-
<input
|
238 |
-
type="text"
|
239 |
-
id="{propertyName}-description"
|
240 |
-
class="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
241 |
-
value={propertyDefinition.description}
|
242 |
-
{...onchange(value => {
|
243 |
-
const updatedProperties = { ...schemaObj.current.schema?.properties };
|
244 |
-
if (!updatedProperties || !updatedProperties[propertyName]) return;
|
245 |
-
updatedProperties[propertyName].description = value;
|
246 |
-
updateSchemaNested({ properties: updatedProperties });
|
247 |
-
})}
|
248 |
-
/>
|
249 |
-
</div>
|
250 |
-
|
251 |
-
<div class="flex items-start">
|
252 |
-
<div class="flex h-5 items-center">
|
253 |
-
<input
|
254 |
-
id="required-{propertyName}"
|
255 |
-
aria-describedby="required-{propertyName}-description"
|
256 |
-
name="required-{propertyName}"
|
257 |
-
type="checkbox"
|
258 |
-
class="h-4 w-4 rounded border border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:bg-gray-800"
|
259 |
-
checked={schemaObj.current.schema?.required?.includes(propertyName)}
|
260 |
-
onchange={e => {
|
261 |
-
let updatedRequired = [...(schemaObj.current.schema?.required || [])];
|
262 |
-
if (e.currentTarget.checked) {
|
263 |
-
if (!updatedRequired.includes(propertyName)) {
|
264 |
-
updatedRequired.push(propertyName);
|
265 |
-
}
|
266 |
-
} else {
|
267 |
-
updatedRequired = updatedRequired.filter(name => name !== propertyName);
|
268 |
-
}
|
269 |
-
updateSchemaNested({ required: updatedRequired });
|
270 |
-
}}
|
271 |
-
/>
|
272 |
-
</div>
|
273 |
-
<div class="ml-3 text-sm">
|
274 |
-
<label for="required-{propertyName}" class="font-medium text-gray-700 dark:text-gray-300">
|
275 |
-
Required
|
276 |
-
</label>
|
277 |
-
</div>
|
278 |
-
</div>
|
279 |
-
</div>
|
280 |
{:else}
|
281 |
<p class="mt-3 text-sm text-gray-500">No properties defined yet.</p>
|
282 |
{/each}
|
@@ -292,12 +193,12 @@
|
|
292 |
const newPropertyName = `newProperty${Object.keys(schemaObj.current.schema?.properties || {}).length + 1}`;
|
293 |
const updatedProperties = {
|
294 |
...(schemaObj.current.schema?.properties || {}),
|
295 |
-
[newPropertyName]: { type: "string"
|
296 |
};
|
297 |
updateSchemaNested({ properties: updatedProperties });
|
298 |
}}
|
299 |
>
|
300 |
-
Add
|
301 |
</button>
|
302 |
</div>
|
303 |
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { isDark } from "$lib/spells/is-dark.svelte";
|
3 |
import { Synced } from "$lib/spells/synced.svelte";
|
4 |
import { TextareaAutosize } from "$lib/spells/textarea-autosize.svelte";
|
5 |
import type { ConversationClass } from "$lib/state/conversations.svelte.js";
|
6 |
import { safeParse } from "$lib/utils/json.js";
|
7 |
+
import { keys, renameKey } from "$lib/utils/object.svelte";
|
8 |
import { onchange, oninput } from "$lib/utils/template.js";
|
9 |
import { RadioGroup } from "melt/builders";
|
10 |
import { codeToHtml } from "shiki";
|
11 |
import typia from "typia";
|
|
|
12 |
import Dialog from "../dialog.svelte";
|
13 |
+
import SchemaProperty, { type PropertyDefinition } from "./schema-property.svelte";
|
14 |
|
15 |
interface Props {
|
16 |
conversation: ConversationClass;
|
|
|
27 |
});
|
28 |
|
29 |
type Schema = {
|
|
|
|
|
30 |
schema?: {
|
31 |
type?: string;
|
32 |
+
properties?: { [key: string]: PropertyDefinition };
|
33 |
required?: string[];
|
34 |
additionalProperties?: boolean;
|
35 |
};
|
|
|
74 |
keys(v.schema?.properties ?? {}).includes(name)
|
75 |
);
|
76 |
const validated: Schema = {
|
|
|
|
|
77 |
schema: {
|
78 |
...v.schema,
|
79 |
required,
|
|
|
106 |
});
|
107 |
</script>
|
108 |
|
109 |
+
<Dialog class="!w-2xl max-w-[90vw]" title="Edit Structured Output" {open} onClose={() => (open = false)}>
|
110 |
<div class="flex justify-end">
|
111 |
<div
|
112 |
class="flex items-center gap-0.5 rounded-md border border-gray-300 bg-white p-0.5 text-sm dark:border-gray-600 dark:bg-gray-800"
|
|
|
129 |
|
130 |
{#if radioGroup.value === "form"}
|
131 |
<div class="fade-y -mx-2 mt-2 -mb-4 max-h-200 space-y-4 overflow-auto px-2 py-4 text-left">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
<!-- Properties Section -->
|
133 |
<div class="border-t border-gray-200 pt-4 dark:border-gray-700">
|
134 |
<h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100">Properties</h3>
|
135 |
{#if schemaObj.current.schema?.properties}
|
136 |
<div class="mt-3 space-y-3">
|
137 |
+
{#each Object.entries(schemaObj.current.schema.properties) as [propertyName, propertyDefinition]}
|
138 |
+
<SchemaProperty
|
139 |
+
bind:name={
|
140 |
+
() => propertyName,
|
141 |
+
value => {
|
142 |
+
const updatedProperties = renameKey(
|
143 |
+
schemaObj.current.schema?.properties ?? {},
|
144 |
+
propertyName,
|
145 |
+
value
|
146 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
updateSchemaNested({ properties: updatedProperties });
|
148 |
+
}
|
149 |
+
}
|
150 |
+
bind:definition={
|
151 |
+
() => propertyDefinition,
|
152 |
+
v => {
|
153 |
+
const updatedProperties = { ...schemaObj.current.schema?.properties };
|
154 |
+
if (updatedProperties && updatedProperties[propertyName]) {
|
155 |
+
updatedProperties[propertyName] = v;
|
156 |
+
updateSchemaNested({ properties: updatedProperties });
|
157 |
+
}
|
158 |
+
}
|
159 |
+
}
|
160 |
+
bind:required={
|
161 |
+
() => schemaObj.current.schema?.required?.includes(propertyName) ?? false,
|
162 |
+
v => {
|
163 |
+
let updatedRequired = [...(schemaObj.current.schema?.required || [])];
|
164 |
+
if (v) {
|
165 |
+
if (!updatedRequired.includes(propertyName)) {
|
166 |
+
updatedRequired.push(propertyName);
|
|
|
|
|
167 |
}
|
168 |
+
} else {
|
169 |
+
updatedRequired = updatedRequired.filter(name => name !== name);
|
170 |
}
|
171 |
+
updateSchemaNested({ required: updatedRequired });
|
172 |
+
}
|
173 |
+
}
|
174 |
+
onDelete={() => {
|
175 |
+
const updatedProperties = { ...schemaObj.current.schema?.properties };
|
176 |
+
if (!updatedProperties || !updatedProperties[propertyName]) return;
|
177 |
+
delete updatedProperties[propertyName];
|
178 |
+
updateSchemaNested({ properties: updatedProperties });
|
179 |
+
}}
|
180 |
+
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
{:else}
|
182 |
<p class="mt-3 text-sm text-gray-500">No properties defined yet.</p>
|
183 |
{/each}
|
|
|
193 |
const newPropertyName = `newProperty${Object.keys(schemaObj.current.schema?.properties || {}).length + 1}`;
|
194 |
const updatedProperties = {
|
195 |
...(schemaObj.current.schema?.properties || {}),
|
196 |
+
[newPropertyName]: { type: "string" as const },
|
197 |
};
|
198 |
updateSchemaNested({ properties: updatedProperties });
|
199 |
}}
|
200 |
>
|
201 |
+
Add property
|
202 |
</button>
|
203 |
</div>
|
204 |
|
src/lib/components/inference-playground/utils.svelte.ts
CHANGED
@@ -4,6 +4,7 @@ import { token } from "$lib/state/token.svelte";
|
|
4 |
import {
|
5 |
isCustomModel,
|
6 |
isHFModel,
|
|
|
7 |
type Conversation,
|
8 |
type ConversationMessage,
|
9 |
type CustomModel,
|
@@ -18,6 +19,8 @@ import { type ChatCompletionOutputMessage } from "@huggingface/tasks";
|
|
18 |
import { AutoTokenizer, PreTrainedTokenizer } from "@huggingface/transformers";
|
19 |
import OpenAI from "openai";
|
20 |
import { images } from "$lib/state/images.svelte.js";
|
|
|
|
|
21 |
|
22 |
type ChatCompletionInputMessageChunk =
|
23 |
NonNullable<ChatCompletionInputMessage["content"]> extends string | (infer U)[] ? U : never;
|
@@ -84,14 +87,50 @@ async function getCompletionMetadata(
|
|
84 |
): Promise<CompletionMetadata> {
|
85 |
const data = conversation instanceof ConversationClass ? conversation.data : conversation;
|
86 |
const model = conversation.model;
|
87 |
-
const
|
88 |
|
89 |
-
const messages = [
|
90 |
-
...(isSystemPromptSupported(model) && systemMessage
|
91 |
...data.messages,
|
92 |
];
|
93 |
const parsed = await Promise.all(messages.map(parseMessage));
|
94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
// Handle OpenAI-compatible models
|
96 |
if (isCustomModel(model)) {
|
97 |
const openai = new OpenAI({
|
@@ -104,22 +143,10 @@ async function getCompletionMetadata(
|
|
104 |
});
|
105 |
|
106 |
const args = {
|
107 |
-
|
108 |
-
...data.config,
|
109 |
-
model: model.id,
|
110 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
111 |
} as any;
|
112 |
|
113 |
-
if (data.structuredOutput?.enabled) {
|
114 |
-
const json = safeParse(data.structuredOutput.schema ?? "");
|
115 |
-
if (json) {
|
116 |
-
args.response_format = {
|
117 |
-
type: "json_schema",
|
118 |
-
json_schema: json,
|
119 |
-
};
|
120 |
-
}
|
121 |
-
}
|
122 |
-
|
123 |
return {
|
124 |
type: "openai",
|
125 |
client: openai,
|
@@ -127,24 +154,12 @@ async function getCompletionMetadata(
|
|
127 |
};
|
128 |
}
|
129 |
const args = {
|
130 |
-
|
131 |
-
messages: parsed,
|
132 |
provider: data.provider,
|
133 |
-
...data.config,
|
134 |
// max_tokens: maxAllowedTokens(conversation) - currTokens,
|
135 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
136 |
} as any;
|
137 |
|
138 |
-
if (data.structuredOutput?.enabled) {
|
139 |
-
const json = safeParse(data.structuredOutput.schema ?? "");
|
140 |
-
if (json) {
|
141 |
-
args.response_format = {
|
142 |
-
type: "json_schema",
|
143 |
-
json_schema: json,
|
144 |
-
};
|
145 |
-
}
|
146 |
-
}
|
147 |
-
|
148 |
// Handle HuggingFace models
|
149 |
return {
|
150 |
type: "huggingface",
|
|
|
4 |
import {
|
5 |
isCustomModel,
|
6 |
isHFModel,
|
7 |
+
Provider,
|
8 |
type Conversation,
|
9 |
type ConversationMessage,
|
10 |
type CustomModel,
|
|
|
19 |
import { AutoTokenizer, PreTrainedTokenizer } from "@huggingface/transformers";
|
20 |
import OpenAI from "openai";
|
21 |
import { images } from "$lib/state/images.svelte.js";
|
22 |
+
import { projects } from "$lib/state/projects.svelte.js";
|
23 |
+
import { structuredForbiddenProviders } from "$lib/state/models.svelte.js";
|
24 |
|
25 |
type ChatCompletionInputMessageChunk =
|
26 |
NonNullable<ChatCompletionInputMessage["content"]> extends string | (infer U)[] ? U : never;
|
|
|
87 |
): Promise<CompletionMetadata> {
|
88 |
const data = conversation instanceof ConversationClass ? conversation.data : conversation;
|
89 |
const model = conversation.model;
|
90 |
+
const systemMessage = projects.current?.systemMessage;
|
91 |
|
92 |
+
const messages: ConversationMessage[] = [
|
93 |
+
...(isSystemPromptSupported(model) && systemMessage?.length ? [{ role: "system", content: systemMessage }] : []),
|
94 |
...data.messages,
|
95 |
];
|
96 |
const parsed = await Promise.all(messages.map(parseMessage));
|
97 |
|
98 |
+
const baseArgs = {
|
99 |
+
...data.config,
|
100 |
+
messages: parsed,
|
101 |
+
model: model.id,
|
102 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
103 |
+
} as any;
|
104 |
+
|
105 |
+
const json = safeParse(data.structuredOutput?.schema ?? "");
|
106 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
107 |
+
if (json && data.structuredOutput?.enabled && !structuredForbiddenProviders.includes(data.provider as any)) {
|
108 |
+
switch (data.provider) {
|
109 |
+
case "cohere": {
|
110 |
+
baseArgs.response_format = {
|
111 |
+
type: "json_object",
|
112 |
+
...json,
|
113 |
+
};
|
114 |
+
break;
|
115 |
+
}
|
116 |
+
case Provider.Nebius: {
|
117 |
+
baseArgs.response_format = {
|
118 |
+
type: "json_object",
|
119 |
+
json_schema: { ...json, name: "schema" },
|
120 |
+
};
|
121 |
+
break;
|
122 |
+
}
|
123 |
+
default: {
|
124 |
+
baseArgs.response_format = {
|
125 |
+
type: "json_object",
|
126 |
+
json_schema: json,
|
127 |
+
};
|
128 |
+
|
129 |
+
break;
|
130 |
+
}
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
// Handle OpenAI-compatible models
|
135 |
if (isCustomModel(model)) {
|
136 |
const openai = new OpenAI({
|
|
|
143 |
});
|
144 |
|
145 |
const args = {
|
146 |
+
...baseArgs,
|
|
|
|
|
147 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
148 |
} as any;
|
149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
return {
|
151 |
type: "openai",
|
152 |
client: openai,
|
|
|
154 |
};
|
155 |
}
|
156 |
const args = {
|
157 |
+
...baseArgs,
|
|
|
158 |
provider: data.provider,
|
|
|
159 |
// max_tokens: maxAllowedTokens(conversation) - currTokens,
|
160 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
161 |
} as any;
|
162 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
// Handle HuggingFace models
|
164 |
return {
|
165 |
type: "huggingface",
|
src/lib/components/local-toasts.svelte
CHANGED
@@ -1,9 +1,8 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import { autoUpdate, computePosition } from "@floating-ui/dom";
|
3 |
import { Toaster } from "melt/builders";
|
4 |
import { type Snippet } from "svelte";
|
5 |
import { type Attachment } from "svelte/attachments";
|
6 |
-
import { fly } from "svelte/transition";
|
7 |
|
8 |
interface Props {
|
9 |
children: Snippet<[{ addToast: typeof toaster.addToast; trigger: typeof trigger }]>;
|
@@ -31,21 +30,96 @@
|
|
31 |
export const addToast = toaster.addToast;
|
32 |
|
33 |
const float: Attachment<HTMLElement> = function (node) {
|
|
|
|
|
34 |
const triggerEl = document.querySelector(`[data-local-toast-trigger=${id}]`);
|
35 |
if (!triggerEl) return;
|
36 |
|
37 |
const compute = () =>
|
38 |
computePosition(triggerEl, node, {
|
39 |
-
placement: "top",
|
40 |
strategy: "absolute",
|
41 |
-
|
|
|
|
|
|
|
42 |
Object.assign(node.style, {
|
43 |
-
left: `${x}px`,
|
44 |
-
top: `${y -
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
});
|
46 |
});
|
47 |
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
};
|
50 |
|
51 |
const classMap: Record<ToastData["variant"], string> = {
|
@@ -62,8 +136,6 @@
|
|
62 |
data-local-toast
|
63 |
data-variant={toast.data.variant}
|
64 |
class={[!toastSnippet && `${classMap[toast.data.variant]} rounded-full px-2 py-1 text-xs`]}
|
65 |
-
in:fly={{ y: 10 }}
|
66 |
-
out:fly={{ y: -4 }}
|
67 |
{@attach float}
|
68 |
>
|
69 |
{#if toastSnippet}
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { autoUpdate, computePosition, flip, type Placement } from "@floating-ui/dom";
|
3 |
import { Toaster } from "melt/builders";
|
4 |
import { type Snippet } from "svelte";
|
5 |
import { type Attachment } from "svelte/attachments";
|
|
|
6 |
|
7 |
interface Props {
|
8 |
children: Snippet<[{ addToast: typeof toaster.addToast; trigger: typeof trigger }]>;
|
|
|
30 |
export const addToast = toaster.addToast;
|
31 |
|
32 |
const float: Attachment<HTMLElement> = function (node) {
|
33 |
+
let placement: Placement = $state("top");
|
34 |
+
|
35 |
const triggerEl = document.querySelector(`[data-local-toast-trigger=${id}]`);
|
36 |
if (!triggerEl) return;
|
37 |
|
38 |
const compute = () =>
|
39 |
computePosition(triggerEl, node, {
|
|
|
40 |
strategy: "absolute",
|
41 |
+
placement: "top",
|
42 |
+
middleware: [flip({ fallbackPlacements: ["left"] })],
|
43 |
+
}).then(({ x, y, placement: _placement }) => {
|
44 |
+
placement = _placement;
|
45 |
Object.assign(node.style, {
|
46 |
+
left: placement === "top" ? `${x}px` : `${x - 4}px`,
|
47 |
+
top: placement === "top" ? `${y - 6}px` : `${y}px`,
|
48 |
+
});
|
49 |
+
|
50 |
+
// Animate
|
51 |
+
// Cancel any ongoing animations
|
52 |
+
node.getAnimations().forEach(anim => anim.cancel());
|
53 |
+
|
54 |
+
// Determine animation direction based on placement
|
55 |
+
let keyframes: Keyframe[] = [];
|
56 |
+
switch (placement) {
|
57 |
+
case "top":
|
58 |
+
keyframes = [
|
59 |
+
{ opacity: 0, transform: "translateY(8px)", scale: "0.8" },
|
60 |
+
{ opacity: 1, transform: "translateY(0)", scale: "1" },
|
61 |
+
];
|
62 |
+
break;
|
63 |
+
case "left":
|
64 |
+
keyframes = [
|
65 |
+
{ opacity: 0, transform: "translateX(8px)", scale: "0.8" },
|
66 |
+
{ opacity: 1, transform: "translateX(0)", scale: "1" },
|
67 |
+
];
|
68 |
+
break;
|
69 |
+
}
|
70 |
+
|
71 |
+
node.animate(keyframes, {
|
72 |
+
duration: 500,
|
73 |
+
easing: "cubic-bezier(0.22, 1, 0.36, 1)",
|
74 |
+
fill: "forwards",
|
75 |
});
|
76 |
});
|
77 |
|
78 |
+
const reference = node.cloneNode(true) as HTMLElement;
|
79 |
+
node.before(reference);
|
80 |
+
reference.style.visibility = "hidden";
|
81 |
+
|
82 |
+
const destroyers = [
|
83 |
+
autoUpdate(triggerEl, node, compute),
|
84 |
+
async () => {
|
85 |
+
// clone node
|
86 |
+
const cloned = node.cloneNode(true) as HTMLElement;
|
87 |
+
reference.before(cloned);
|
88 |
+
reference.remove();
|
89 |
+
cloned.getAnimations().forEach(anim => anim.cancel());
|
90 |
+
|
91 |
+
// Animate out
|
92 |
+
// Cancel any ongoing animations
|
93 |
+
cloned.getAnimations().forEach(anim => anim.cancel());
|
94 |
+
|
95 |
+
// Determine animation direction based on placement
|
96 |
+
let keyframes: Keyframe[] = [];
|
97 |
+
switch (placement) {
|
98 |
+
case "top":
|
99 |
+
keyframes = [
|
100 |
+
{ opacity: 1, transform: "translateY(0)" },
|
101 |
+
{ opacity: 0, transform: "translateY(-8px)" },
|
102 |
+
];
|
103 |
+
break;
|
104 |
+
case "left":
|
105 |
+
keyframes = [
|
106 |
+
{ opacity: 1, transform: "translateX(0)" },
|
107 |
+
{ opacity: 0, transform: "translateX(-8px)" },
|
108 |
+
];
|
109 |
+
break;
|
110 |
+
}
|
111 |
+
|
112 |
+
await cloned.animate(keyframes, {
|
113 |
+
duration: 400,
|
114 |
+
easing: "cubic-bezier(0.22, 1, 0.36, 1)",
|
115 |
+
fill: "forwards",
|
116 |
+
}).finished;
|
117 |
+
|
118 |
+
cloned.remove();
|
119 |
+
},
|
120 |
+
];
|
121 |
+
|
122 |
+
return () => destroyers.forEach(d => d());
|
123 |
};
|
124 |
|
125 |
const classMap: Record<ToastData["variant"], string> = {
|
|
|
136 |
data-local-toast
|
137 |
data-variant={toast.data.variant}
|
138 |
class={[!toastSnippet && `${classMap[toast.data.variant]} rounded-full px-2 py-1 text-xs`]}
|
|
|
|
|
139 |
{@attach float}
|
140 |
>
|
141 |
{#if toastSnippet}
|
src/lib/components/share-modal.svelte
CHANGED
@@ -153,7 +153,7 @@
|
|
153 |
saving = false;
|
154 |
return;
|
155 |
}
|
156 |
-
const projectId = await projects.create(`Saved - ${decoded.name}`);
|
157 |
await Promise.allSettled(
|
158 |
decoded.conversations.map(c => {
|
159 |
conversations.create({
|
|
|
153 |
saving = false;
|
154 |
return;
|
155 |
}
|
156 |
+
const projectId = await projects.create({ name: `Saved - ${decoded.name}` });
|
157 |
await Promise.allSettled(
|
158 |
decoded.conversations.map(c => {
|
159 |
conversations.create({
|
src/lib/data/context_length.json
CHANGED
@@ -101,19 +101,19 @@
|
|
101 |
"stability-ai/sdxl": 0
|
102 |
},
|
103 |
"novita": {
|
104 |
-
"deepseek/deepseek-prover-v2-671b": 160000,
|
105 |
-
"qwen/qwen3-235b-a22b-fp8": 128000,
|
106 |
-
"qwen/qwen3-30b-a3b-fp8": 128000,
|
107 |
-
"qwen/qwen3-32b-fp8": 128000,
|
108 |
"deepseek/deepseek-v3-0324": 128000,
|
|
|
|
|
|
|
109 |
"qwen/qwen2.5-vl-72b-instruct": 96000,
|
110 |
"deepseek/deepseek-v3-turbo": 64000,
|
111 |
-
"deepseek/deepseek-r1-turbo": 64000,
|
112 |
"meta-llama/llama-4-maverick-17b-128e-instruct-fp8": 1048576,
|
113 |
"google/gemma-3-27b-it": 32000,
|
114 |
"qwen/qwq-32b": 32768,
|
|
|
115 |
"Sao10K/L3-8B-Stheno-v3.2": 8192,
|
116 |
"gryphe/mythomax-l2-13b": 4096,
|
|
|
117 |
"meta-llama/llama-4-scout-17b-16e-instruct": 131072,
|
118 |
"deepseek/deepseek-r1-distill-llama-8b": 32000,
|
119 |
"deepseek/deepseek_v3": 64000,
|
@@ -141,7 +141,7 @@
|
|
141 |
"qwen/qwen3-1.7b-fp8": 32000,
|
142 |
"qwen/qwen3-8b-fp8": 128000,
|
143 |
"qwen/qwen3-4b-fp8": 128000,
|
144 |
-
"qwen/qwen3-14b-fp8":
|
145 |
"thudm/glm-4-9b-0414": 32000,
|
146 |
"thudm/glm-z1-9b-0414": 32000,
|
147 |
"thudm/glm-z1-32b-0414": 32000,
|
@@ -211,17 +211,18 @@
|
|
211 |
"together": {
|
212 |
"Qwen/QwQ-32B": 131072,
|
213 |
"meta-llama/Llama-4-Scout-17B-16E-Instruct": 1048576,
|
|
|
214 |
"meta-llama/Llama-Guard-4-12B": 1048576,
|
215 |
"togethercomputer/m2-bert-80M-32k-retrieval": 32768,
|
216 |
-
"google/gemma-2-9b-it": 8192,
|
217 |
"cartesia/sonic": 0,
|
|
|
218 |
"Qwen/Qwen2.5-7B-Instruct-Turbo": 32768,
|
219 |
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B-free": 8192,
|
220 |
"meta-llama-llama-2-70b-hf": 4096,
|
|
|
221 |
"BAAI/bge-base-en-v1.5": 512,
|
222 |
"Gryphe/MythoMax-L2-13b": 4096,
|
223 |
-
"
|
224 |
-
"mistralai/Mistral-7B-Instruct-v0.1": 32768,
|
225 |
"mistralai/Mixtral-8x7B-Instruct-v0.1": 32768,
|
226 |
"google/gemma-2-27b-it": 8192,
|
227 |
"Qwen/Qwen2-VL-72B-Instruct": 32768,
|
@@ -229,18 +230,21 @@
|
|
229 |
"cartesia/sonic-2": 0,
|
230 |
"togethercomputer/m2-bert-80M-8k-retrieval": 8192,
|
231 |
"meta-llama/Llama-3.3-70B-Instruct-Turbo-Free": 131072,
|
|
|
232 |
"scb10x/scb10x-llama3-1-typhoon2-70b-instruct": 8192,
|
233 |
"togethercomputer/Refuel-Llm-V2-Small": 8192,
|
234 |
"togethercomputer/MoA-1": 32768,
|
235 |
"meta-llama/Meta-Llama-3-70B-Instruct-Turbo": 8192,
|
236 |
-
"Qwen/Qwen3-235B-A22B-fp8-tput": 40960,
|
237 |
"google/gemma-2b-it": 8192,
|
238 |
"meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo": 131072,
|
239 |
"Gryphe/MythoMax-L2-13b-Lite": 4096,
|
|
|
240 |
"scb10x/scb10x-llama3-1-typhoon2-8b-instruct": 8192,
|
241 |
"meta-llama/Meta-Llama-Guard-3-8B": 8192,
|
242 |
-
"
|
243 |
"deepseek-ai/DeepSeek-R1": 163840,
|
|
|
|
|
244 |
"arcee-ai/arcee-blitz": 32768,
|
245 |
"arcee_ai/arcee-spotlight": 131072,
|
246 |
"arcee-ai/caller": 32768,
|
@@ -248,20 +252,19 @@
|
|
248 |
"arcee-ai/maestro-reasoning": 131072,
|
249 |
"arcee-ai/virtuoso-large": 131072,
|
250 |
"arcee-ai/virtuoso-medium-v2": 131072,
|
251 |
-
"
|
252 |
"meta-llama/Llama-3-8b-chat-hf": 8192,
|
|
|
|
|
|
|
253 |
"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": 1048576,
|
254 |
"togethercomputer/MoA-1-Turbo": 32768,
|
255 |
"meta-llama/Llama-3.3-70B-Instruct-Turbo": 131072,
|
256 |
-
"Qwen/Qwen3-235B-A22B-fp8": 40960,
|
257 |
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO": 32768,
|
258 |
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B": 131072,
|
259 |
"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B": 131072,
|
260 |
"meta-llama/Meta-Llama-3-8B-Instruct-Lite": 8192,
|
261 |
-
"meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo": 131072,
|
262 |
"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo": 131072,
|
263 |
-
"mistralai/Mixtral-8x7B-v0.1": 32768,
|
264 |
-
"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo": 131072,
|
265 |
"mistralai/Mistral-7B-Instruct-v0.2": 32768,
|
266 |
"deepseek-ai/DeepSeek-V3-p-dp": 131072,
|
267 |
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B": 131072,
|
@@ -274,13 +277,9 @@
|
|
274 |
"meta-llama/Llama-Vision-Free": 131072,
|
275 |
"meta-llama/Llama-Guard-3-11B-Vision-Turbo": 131072,
|
276 |
"meta-llama/Llama-3.2-3B-Instruct-Turbo": 131072,
|
277 |
-
"meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo": 130815,
|
278 |
"togethercomputer/Refuel-Llm-V2": 16384,
|
279 |
-
"Alibaba-NLP/gte-modernbert-base": 8192,
|
280 |
"Qwen/Qwen2.5-72B-Instruct-Turbo": 131072,
|
281 |
-
"
|
282 |
-
"meta-llama/Llama-2-70b-hf": 4096,
|
283 |
-
"Qwen/Qwen2.5-VL-72B-Instruct": 32768
|
284 |
},
|
285 |
"fireworks-ai": {
|
286 |
"accounts/fireworks/models/qwq-32b": 131072,
|
|
|
101 |
"stability-ai/sdxl": 0
|
102 |
},
|
103 |
"novita": {
|
|
|
|
|
|
|
|
|
104 |
"deepseek/deepseek-v3-0324": 128000,
|
105 |
+
"qwen/qwen3-235b-a22b-fp8": 40960,
|
106 |
+
"qwen/qwen3-30b-a3b-fp8": 40960,
|
107 |
+
"qwen/qwen3-32b-fp8": 40960,
|
108 |
"qwen/qwen2.5-vl-72b-instruct": 96000,
|
109 |
"deepseek/deepseek-v3-turbo": 64000,
|
|
|
110 |
"meta-llama/llama-4-maverick-17b-128e-instruct-fp8": 1048576,
|
111 |
"google/gemma-3-27b-it": 32000,
|
112 |
"qwen/qwq-32b": 32768,
|
113 |
+
"deepseek/deepseek-r1-turbo": 64000,
|
114 |
"Sao10K/L3-8B-Stheno-v3.2": 8192,
|
115 |
"gryphe/mythomax-l2-13b": 4096,
|
116 |
+
"deepseek/deepseek-prover-v2-671b": 160000,
|
117 |
"meta-llama/llama-4-scout-17b-16e-instruct": 131072,
|
118 |
"deepseek/deepseek-r1-distill-llama-8b": 32000,
|
119 |
"deepseek/deepseek_v3": 64000,
|
|
|
141 |
"qwen/qwen3-1.7b-fp8": 32000,
|
142 |
"qwen/qwen3-8b-fp8": 128000,
|
143 |
"qwen/qwen3-4b-fp8": 128000,
|
144 |
+
"qwen/qwen3-14b-fp8": 40960,
|
145 |
"thudm/glm-4-9b-0414": 32000,
|
146 |
"thudm/glm-z1-9b-0414": 32000,
|
147 |
"thudm/glm-z1-32b-0414": 32000,
|
|
|
211 |
"together": {
|
212 |
"Qwen/QwQ-32B": 131072,
|
213 |
"meta-llama/Llama-4-Scout-17B-16E-Instruct": 1048576,
|
214 |
+
"mistralai/Mistral-7B-Instruct-v0.1": 32768,
|
215 |
"meta-llama/Llama-Guard-4-12B": 1048576,
|
216 |
"togethercomputer/m2-bert-80M-32k-retrieval": 32768,
|
|
|
217 |
"cartesia/sonic": 0,
|
218 |
+
"meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo": 130815,
|
219 |
"Qwen/Qwen2.5-7B-Instruct-Turbo": 32768,
|
220 |
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B-free": 8192,
|
221 |
"meta-llama-llama-2-70b-hf": 4096,
|
222 |
+
"intfloat/multilingual-e5-large-instruct": 514,
|
223 |
"BAAI/bge-base-en-v1.5": 512,
|
224 |
"Gryphe/MythoMax-L2-13b": 4096,
|
225 |
+
"Alibaba-NLP/gte-modernbert-base": 8192,
|
|
|
226 |
"mistralai/Mixtral-8x7B-Instruct-v0.1": 32768,
|
227 |
"google/gemma-2-27b-it": 8192,
|
228 |
"Qwen/Qwen2-VL-72B-Instruct": 32768,
|
|
|
230 |
"cartesia/sonic-2": 0,
|
231 |
"togethercomputer/m2-bert-80M-8k-retrieval": 8192,
|
232 |
"meta-llama/Llama-3.3-70B-Instruct-Turbo-Free": 131072,
|
233 |
+
"deepseek-ai/DeepSeek-V3": 131072,
|
234 |
"scb10x/scb10x-llama3-1-typhoon2-70b-instruct": 8192,
|
235 |
"togethercomputer/Refuel-Llm-V2-Small": 8192,
|
236 |
"togethercomputer/MoA-1": 32768,
|
237 |
"meta-llama/Meta-Llama-3-70B-Instruct-Turbo": 8192,
|
|
|
238 |
"google/gemma-2b-it": 8192,
|
239 |
"meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo": 131072,
|
240 |
"Gryphe/MythoMax-L2-13b-Lite": 4096,
|
241 |
+
"Qwen/Qwen3-235B-A22B-fp8": 40960,
|
242 |
"scb10x/scb10x-llama3-1-typhoon2-8b-instruct": 8192,
|
243 |
"meta-llama/Meta-Llama-Guard-3-8B": 8192,
|
244 |
+
"marin-community/marin-8b-instruct": 131072,
|
245 |
"deepseek-ai/DeepSeek-R1": 163840,
|
246 |
+
"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo": 131072,
|
247 |
+
"Qwen/Qwen2.5-VL-72B-Instruct": 32768,
|
248 |
"arcee-ai/arcee-blitz": 32768,
|
249 |
"arcee_ai/arcee-spotlight": 131072,
|
250 |
"arcee-ai/caller": 32768,
|
|
|
252 |
"arcee-ai/maestro-reasoning": 131072,
|
253 |
"arcee-ai/virtuoso-large": 131072,
|
254 |
"arcee-ai/virtuoso-medium-v2": 131072,
|
255 |
+
"meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo": 131072,
|
256 |
"meta-llama/Llama-3-8b-chat-hf": 8192,
|
257 |
+
"mistralai/Mistral-Small-24B-Instruct-2501": 32768,
|
258 |
+
"Qwen/Qwen3-235B-A22B-fp8-tput": 40960,
|
259 |
+
"perplexity-ai/r1-1776": 163840,
|
260 |
"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": 1048576,
|
261 |
"togethercomputer/MoA-1-Turbo": 32768,
|
262 |
"meta-llama/Llama-3.3-70B-Instruct-Turbo": 131072,
|
|
|
263 |
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO": 32768,
|
264 |
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B": 131072,
|
265 |
"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B": 131072,
|
266 |
"meta-llama/Meta-Llama-3-8B-Instruct-Lite": 8192,
|
|
|
267 |
"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo": 131072,
|
|
|
|
|
268 |
"mistralai/Mistral-7B-Instruct-v0.2": 32768,
|
269 |
"deepseek-ai/DeepSeek-V3-p-dp": 131072,
|
270 |
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B": 131072,
|
|
|
277 |
"meta-llama/Llama-Vision-Free": 131072,
|
278 |
"meta-llama/Llama-Guard-3-11B-Vision-Turbo": 131072,
|
279 |
"meta-llama/Llama-3.2-3B-Instruct-Turbo": 131072,
|
|
|
280 |
"togethercomputer/Refuel-Llm-V2": 16384,
|
|
|
281 |
"Qwen/Qwen2.5-72B-Instruct-Turbo": 131072,
|
282 |
+
"meta-llama/Llama-2-70b-hf": 4096
|
|
|
|
|
283 |
},
|
284 |
"fireworks-ai": {
|
285 |
"accounts/fireworks/models/qwq-32b": 131072,
|
src/lib/state/conversations.svelte.ts
CHANGED
@@ -40,9 +40,6 @@ export class ConversationEntity {
|
|
40 |
@Fields.json()
|
41 |
messages!: ConversationMessage[];
|
42 |
|
43 |
-
@Fields.json()
|
44 |
-
systemMessage: ConversationMessage = { role: "system" };
|
45 |
-
|
46 |
@Fields.boolean()
|
47 |
streaming = false;
|
48 |
|
@@ -64,10 +61,6 @@ export type ConversationEntityMembers = MembersOnly<ConversationEntity>;
|
|
64 |
const conversationsRepo = repo(ConversationEntity, idb);
|
65 |
|
66 |
const startMessageUser: ConversationMessage = { role: "user", content: "" };
|
67 |
-
const systemMessage: ConversationMessage = {
|
68 |
-
role: "system",
|
69 |
-
content: "",
|
70 |
-
};
|
71 |
|
72 |
export const emptyModel: Model = {
|
73 |
_id: "",
|
@@ -89,7 +82,6 @@ function getDefaultConversation(projectId: string) {
|
|
89 |
modelId: models.trending[0]?.id ?? models.remote[0]?.id ?? emptyModel.id,
|
90 |
config: { ...defaultGenerationConfig },
|
91 |
messages: [{ ...startMessageUser }],
|
92 |
-
systemMessage,
|
93 |
streaming: true,
|
94 |
createdAt: new Date(),
|
95 |
} satisfies Partial<ConversationEntityMembers>;
|
|
|
40 |
@Fields.json()
|
41 |
messages!: ConversationMessage[];
|
42 |
|
|
|
|
|
|
|
43 |
@Fields.boolean()
|
44 |
streaming = false;
|
45 |
|
|
|
61 |
const conversationsRepo = repo(ConversationEntity, idb);
|
62 |
|
63 |
const startMessageUser: ConversationMessage = { role: "user", content: "" };
|
|
|
|
|
|
|
|
|
64 |
|
65 |
export const emptyModel: Model = {
|
66 |
_id: "",
|
|
|
82 |
modelId: models.trending[0]?.id ?? models.remote[0]?.id ?? emptyModel.id,
|
83 |
config: { ...defaultGenerationConfig },
|
84 |
messages: [{ ...startMessageUser }],
|
|
|
85 |
streaming: true,
|
86 |
createdAt: new Date(),
|
87 |
} satisfies Partial<ConversationEntityMembers>;
|
src/lib/state/models.svelte.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { page } from "$app/state";
|
2 |
-
import { type CustomModel } from "$lib/types.js";
|
3 |
import { edit, randomPick } from "$lib/utils/array.js";
|
4 |
import { safeParse } from "$lib/utils/json.js";
|
5 |
import typia from "typia";
|
@@ -10,6 +10,13 @@ const LOCAL_STORAGE_KEY = "hf_inference_playground_custom_models";
|
|
10 |
|
11 |
const pageData = $derived(page.data as PageData);
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
class Models {
|
14 |
remote = $derived(pageData.models);
|
15 |
trending = $derived(this.remote.toSorted((a, b) => b.trendingScore - a.trendingScore).slice(0, 5));
|
|
|
1 |
import { page } from "$app/state";
|
2 |
+
import { Provider, type CustomModel } from "$lib/types.js";
|
3 |
import { edit, randomPick } from "$lib/utils/array.js";
|
4 |
import { safeParse } from "$lib/utils/json.js";
|
5 |
import typia from "typia";
|
|
|
10 |
|
11 |
const pageData = $derived(page.data as PageData);
|
12 |
|
13 |
+
export const structuredForbiddenProviders: Provider[] = [
|
14 |
+
Provider.Hyperbolic,
|
15 |
+
Provider.Nebius,
|
16 |
+
Provider.Novita,
|
17 |
+
Provider.Sambanova,
|
18 |
+
];
|
19 |
+
|
20 |
class Models {
|
21 |
remote = $derived(pageData.models);
|
22 |
trending = $derived(this.remote.toSorted((a, b) => b.trendingScore - a.trendingScore).slice(0, 5));
|
src/lib/state/projects.svelte.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
import { idb } from "$lib/remult.js";
|
2 |
import { dequal } from "dequal";
|
3 |
import { Entity, Fields, repo, type MembersOnly } from "remult";
|
4 |
-
import { conversations } from "./conversations.svelte";
|
5 |
import { PersistedState } from "runed";
|
6 |
import { checkpoints } from "./checkpoints.svelte";
|
|
|
7 |
|
8 |
@Entity("project")
|
9 |
export class ProjectEntity {
|
@@ -12,6 +12,9 @@ export class ProjectEntity {
|
|
12 |
|
13 |
@Fields.string()
|
14 |
name!: string;
|
|
|
|
|
|
|
15 |
}
|
16 |
|
17 |
export type ProjectEntityMembers = MembersOnly<ProjectEntity>;
|
@@ -45,17 +48,17 @@ class Projects {
|
|
45 |
});
|
46 |
}
|
47 |
|
48 |
-
async create(
|
49 |
-
const
|
50 |
-
this.#projects[id] =
|
51 |
-
return id;
|
52 |
}
|
53 |
|
54 |
saveProject = async (args: { name: string; moveCheckpoints?: boolean }) => {
|
55 |
const defaultProject = this.all.find(p => p.id === DEFAULT_PROJECT_ID);
|
56 |
if (!defaultProject) return;
|
57 |
|
58 |
-
const id = await this.create(args.name);
|
59 |
|
60 |
if (args.moveCheckpoints) {
|
61 |
checkpoints.migrate(defaultProject.id, id);
|
@@ -87,7 +90,7 @@ class Projects {
|
|
87 |
|
88 |
async update(data: ProjectEntity) {
|
89 |
if (!data.id) return;
|
90 |
-
await projectsRepo.
|
91 |
this.#projects[data.id] = { ...data };
|
92 |
}
|
93 |
|
|
|
1 |
import { idb } from "$lib/remult.js";
|
2 |
import { dequal } from "dequal";
|
3 |
import { Entity, Fields, repo, type MembersOnly } from "remult";
|
|
|
4 |
import { PersistedState } from "runed";
|
5 |
import { checkpoints } from "./checkpoints.svelte";
|
6 |
+
import { conversations } from "./conversations.svelte";
|
7 |
|
8 |
@Entity("project")
|
9 |
export class ProjectEntity {
|
|
|
12 |
|
13 |
@Fields.string()
|
14 |
name!: string;
|
15 |
+
|
16 |
+
@Fields.string()
|
17 |
+
systemMessage?: string;
|
18 |
}
|
19 |
|
20 |
export type ProjectEntityMembers = MembersOnly<ProjectEntity>;
|
|
|
48 |
});
|
49 |
}
|
50 |
|
51 |
+
async create(args: Omit<ProjectEntity, "id">): Promise<string> {
|
52 |
+
const p = await projectsRepo.save({ ...args });
|
53 |
+
this.#projects[p.id] = p;
|
54 |
+
return p.id;
|
55 |
}
|
56 |
|
57 |
saveProject = async (args: { name: string; moveCheckpoints?: boolean }) => {
|
58 |
const defaultProject = this.all.find(p => p.id === DEFAULT_PROJECT_ID);
|
59 |
if (!defaultProject) return;
|
60 |
|
61 |
+
const id = await this.create({ name: args.name, systemMessage: defaultProject.systemMessage });
|
62 |
|
63 |
if (args.moveCheckpoints) {
|
64 |
checkpoints.migrate(defaultProject.id, id);
|
|
|
90 |
|
91 |
async update(data: ProjectEntity) {
|
92 |
if (!data.id) return;
|
93 |
+
await projectsRepo.upsert({ where: { id: data.id }, set: data });
|
94 |
this.#projects[data.id] = { ...data };
|
95 |
}
|
96 |
|
src/lib/utils/object.svelte.ts
CHANGED
@@ -84,3 +84,21 @@ export function deepMerge<T extends DeepMergeable, U extends DeepMergeable>(targ
|
|
84 |
|
85 |
return result as T & U;
|
86 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
return result as T & U;
|
86 |
}
|
87 |
+
|
88 |
+
export function renameKey<T extends object>(
|
89 |
+
obj: T,
|
90 |
+
oldKey: keyof T,
|
91 |
+
newKey: string
|
92 |
+
): { [K in keyof T as K extends typeof oldKey ? typeof newKey : K]: T[K] } {
|
93 |
+
const entries = Object.entries(obj);
|
94 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
95 |
+
const result: any = {};
|
96 |
+
for (const [key, value] of entries) {
|
97 |
+
if (key === oldKey) {
|
98 |
+
result[newKey] = value;
|
99 |
+
} else {
|
100 |
+
result[key] = value;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
return result;
|
104 |
+
}
|