Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
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 |
+
}
|