Link to provider (#1938)
Browse files* Upgrade dep
* link to provider's page on the Hub
* add rounding
* Update ChatMessage.svelte
* Update provider type to InferenceProvider
Replaces the provider type from string to InferenceProvider in endpoint and message update types for improved type safety and consistency with @huggingface/inference.
* Remove model author avatar from chat message link
Eliminated the model author avatar image from the chat message model link and adjusted the link's padding for consistency. Also fixed the Hugging Face organization link to use curly braces for variable interpolation.
* Switch provider logos to dynamic avatars from Hugging Face
Replaces static SVG provider logos with dynamic avatars fetched from Hugging Face organization API. Removes all local SVG assets for provider logos and updates the settings page to use the new avatar URLs, improving maintainability and ensuring up-to-date branding.
* Remove unused variable and fix type in settings page
Deleted an unused 'modelAuthor' constant in ChatMessage.svelte. Updated type assertion for 'hubOrg' in the settings page to ensure correct key usage with PROVIDERS_HUB_ORGS.
---------
Co-authored-by: Victor Muštar <victor.mustar@gmail.com>
- package-lock.json +12 -12
- package.json +1 -1
- src/lib/components/chat/ChatMessage.svelte +10 -7
- src/lib/server/endpoints/endpoints.ts +6 -2
- src/lib/types/Message.ts +2 -1
- src/lib/types/MessageUpdate.ts +3 -1
- src/routes/settings/(nav)/[...model]/+page.svelte +6 -3
- static/huggingchat/providers/cerebras.svg +0 -3
- static/huggingchat/providers/cohere.svg +0 -3
- static/huggingchat/providers/featherless-ai.svg +0 -3
- static/huggingchat/providers/fireworks-ai.svg +0 -3
- static/huggingchat/providers/groq.svg +0 -3
- static/huggingchat/providers/hf-inference.svg +0 -3
- static/huggingchat/providers/hyperbolic.svg +0 -3
- static/huggingchat/providers/nebius.svg +0 -3
- static/huggingchat/providers/novita.svg +0 -3
- static/huggingchat/providers/nscale.svg +0 -3
- static/huggingchat/providers/publicai.svg +0 -3
- static/huggingchat/providers/sambanova.svg +0 -3
- static/huggingchat/providers/scaleway.svg +0 -3
- static/huggingchat/providers/together.svg +0 -3
- static/huggingchat/providers/zai-org.svg +0 -3
|
@@ -10,7 +10,7 @@
|
|
| 10 |
"dependencies": {
|
| 11 |
"@elysiajs/swagger": "^1.3.0",
|
| 12 |
"@huggingface/hub": "^2.2.0",
|
| 13 |
-
"@huggingface/inference": "^
|
| 14 |
"@iconify-json/bi": "^1.1.21",
|
| 15 |
"@resvg/resvg-js": "^2.6.2",
|
| 16 |
"autoprefixer": "^10.4.14",
|
|
@@ -970,31 +970,31 @@
|
|
| 970 |
}
|
| 971 |
},
|
| 972 |
"node_modules/@huggingface/inference": {
|
| 973 |
-
"version": "
|
| 974 |
-
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-
|
| 975 |
-
"integrity": "sha512-
|
| 976 |
"license": "MIT",
|
| 977 |
"dependencies": {
|
| 978 |
-
"@huggingface/jinja": "^0.5.
|
| 979 |
-
"@huggingface/tasks": "^0.19.
|
| 980 |
},
|
| 981 |
"engines": {
|
| 982 |
"node": ">=18"
|
| 983 |
}
|
| 984 |
},
|
| 985 |
"node_modules/@huggingface/jinja": {
|
| 986 |
-
"version": "0.5.
|
| 987 |
-
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.
|
| 988 |
-
"integrity": "sha512-
|
| 989 |
"license": "MIT",
|
| 990 |
"engines": {
|
| 991 |
"node": ">=18"
|
| 992 |
}
|
| 993 |
},
|
| 994 |
"node_modules/@huggingface/tasks": {
|
| 995 |
-
"version": "0.19.
|
| 996 |
-
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.19.
|
| 997 |
-
"integrity": "sha512-
|
| 998 |
"license": "MIT"
|
| 999 |
},
|
| 1000 |
"node_modules/@humanwhocodes/config-array": {
|
|
|
|
| 10 |
"dependencies": {
|
| 11 |
"@elysiajs/swagger": "^1.3.0",
|
| 12 |
"@huggingface/hub": "^2.2.0",
|
| 13 |
+
"@huggingface/inference": "^4.11.3",
|
| 14 |
"@iconify-json/bi": "^1.1.21",
|
| 15 |
"@resvg/resvg-js": "^2.6.2",
|
| 16 |
"autoprefixer": "^10.4.14",
|
|
|
|
| 970 |
}
|
| 971 |
},
|
| 972 |
"node_modules/@huggingface/inference": {
|
| 973 |
+
"version": "4.11.3",
|
| 974 |
+
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-4.11.3.tgz",
|
| 975 |
+
"integrity": "sha512-Fqpj89DuB6i9j+cos9i0bfUKlpx5NFFsmvED0OAdE1gUSTHR86GpUZ0xkKy58IYXV1yFyHLFxQaOn0XDmD2m7Q==",
|
| 976 |
"license": "MIT",
|
| 977 |
"dependencies": {
|
| 978 |
+
"@huggingface/jinja": "^0.5.1",
|
| 979 |
+
"@huggingface/tasks": "^0.19.52"
|
| 980 |
},
|
| 981 |
"engines": {
|
| 982 |
"node": ">=18"
|
| 983 |
}
|
| 984 |
},
|
| 985 |
"node_modules/@huggingface/jinja": {
|
| 986 |
+
"version": "0.5.1",
|
| 987 |
+
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.1.tgz",
|
| 988 |
+
"integrity": "sha512-yUZLld4lrM9iFxHCwFQ7D1HW2MWMwSbeB7WzWqFYDWK+rEb+WldkLdAJxUPOmgICMHZLzZGVcVjFh3w/YGubng==",
|
| 989 |
"license": "MIT",
|
| 990 |
"engines": {
|
| 991 |
"node": ">=18"
|
| 992 |
}
|
| 993 |
},
|
| 994 |
"node_modules/@huggingface/tasks": {
|
| 995 |
+
"version": "0.19.52",
|
| 996 |
+
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.19.52.tgz",
|
| 997 |
+
"integrity": "sha512-ERporbPcWOeeN22PG3UoC3n/kgk50/Gn03A1NPwO2fqlzaP01ADug0DazPi8W3HandT6LHycv7tAjo+sCOBRtw==",
|
| 998 |
"license": "MIT"
|
| 999 |
},
|
| 1000 |
"node_modules/@humanwhocodes/config-array": {
|
|
@@ -68,7 +68,7 @@
|
|
| 68 |
"dependencies": {
|
| 69 |
"@elysiajs/swagger": "^1.3.0",
|
| 70 |
"@huggingface/hub": "^2.2.0",
|
| 71 |
-
"@huggingface/inference": "^
|
| 72 |
"@iconify-json/bi": "^1.1.21",
|
| 73 |
"@resvg/resvg-js": "^2.6.2",
|
| 74 |
"autoprefixer": "^10.4.14",
|
|
|
|
| 68 |
"dependencies": {
|
| 69 |
"@elysiajs/swagger": "^1.3.0",
|
| 70 |
"@huggingface/hub": "^2.2.0",
|
| 71 |
+
"@huggingface/inference": "^4.11.3",
|
| 72 |
"@iconify-json/bi": "^1.1.21",
|
| 73 |
"@resvg/resvg-js": "^2.6.2",
|
| 74 |
"autoprefixer": "^10.4.14",
|
|
@@ -1,7 +1,6 @@
|
|
| 1 |
<script lang="ts">
|
| 2 |
import type { Message } from "$lib/types/Message";
|
| 3 |
import { tick } from "svelte";
|
| 4 |
-
import { base } from "$app/paths";
|
| 5 |
|
| 6 |
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
|
| 7 |
const publicConfig = usePublicConfig();
|
|
@@ -17,6 +16,7 @@
|
|
| 17 |
import OpenReasoningResults from "./OpenReasoningResults.svelte";
|
| 18 |
import Alternatives from "./Alternatives.svelte";
|
| 19 |
import MessageAvatar from "./MessageAvatar.svelte";
|
|
|
|
| 20 |
|
| 21 |
interface Props {
|
| 22 |
message: Message;
|
|
@@ -177,7 +177,7 @@
|
|
| 177 |
{#if publicConfig.isHuggingChat}
|
| 178 |
<a
|
| 179 |
href="/chat/settings/{message.routerMetadata.model}"
|
| 180 |
-
class="truncate rounded bg-gray-100 px-1 font-mono hover:text-gray-500 dark:bg-gray-800 dark:hover:text-gray-300 sm:py-px"
|
| 181 |
>
|
| 182 |
{message.routerMetadata.model.split("/").pop()}
|
| 183 |
</a>
|
|
@@ -190,18 +190,21 @@
|
|
| 190 |
{/if}
|
| 191 |
{/if}
|
| 192 |
{#if message.routerMetadata.provider}
|
|
|
|
| 193 |
<span class="text-gray-500 max-sm:hidden">via</span>
|
| 194 |
-
<
|
| 195 |
-
|
|
|
|
|
|
|
| 196 |
>
|
| 197 |
<img
|
| 198 |
-
src=
|
| 199 |
alt="{message.routerMetadata.provider} logo"
|
| 200 |
-
class="size-2.5 flex-none"
|
| 201 |
onerror={(e) => ((e.currentTarget as HTMLImageElement).style.display = "none")}
|
| 202 |
/>
|
| 203 |
{message.routerMetadata.provider}
|
| 204 |
-
</
|
| 205 |
{/if}
|
| 206 |
</div>
|
| 207 |
{/if}
|
|
|
|
| 1 |
<script lang="ts">
|
| 2 |
import type { Message } from "$lib/types/Message";
|
| 3 |
import { tick } from "svelte";
|
|
|
|
| 4 |
|
| 5 |
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
|
| 6 |
const publicConfig = usePublicConfig();
|
|
|
|
| 16 |
import OpenReasoningResults from "./OpenReasoningResults.svelte";
|
| 17 |
import Alternatives from "./Alternatives.svelte";
|
| 18 |
import MessageAvatar from "./MessageAvatar.svelte";
|
| 19 |
+
import { PROVIDERS_HUB_ORGS } from "@huggingface/inference";
|
| 20 |
|
| 21 |
interface Props {
|
| 22 |
message: Message;
|
|
|
|
| 177 |
{#if publicConfig.isHuggingChat}
|
| 178 |
<a
|
| 179 |
href="/chat/settings/{message.routerMetadata.model}"
|
| 180 |
+
class="flex items-center gap-1 truncate rounded bg-gray-100 px-1 font-mono hover:text-gray-500 dark:bg-gray-800 dark:hover:text-gray-300 sm:py-px"
|
| 181 |
>
|
| 182 |
{message.routerMetadata.model.split("/").pop()}
|
| 183 |
</a>
|
|
|
|
| 190 |
{/if}
|
| 191 |
{/if}
|
| 192 |
{#if message.routerMetadata.provider}
|
| 193 |
+
{@const hubOrg = PROVIDERS_HUB_ORGS[message.routerMetadata.provider]}
|
| 194 |
<span class="text-gray-500 max-sm:hidden">via</span>
|
| 195 |
+
<a
|
| 196 |
+
target="_blank"
|
| 197 |
+
href="https://huggingface.co/{hubOrg}"
|
| 198 |
+
class="flex items-center gap-1 truncate rounded bg-gray-100 px-1 font-mono hover:text-gray-500 dark:bg-gray-800 dark:hover:text-gray-300 max-sm:hidden sm:py-px"
|
| 199 |
>
|
| 200 |
<img
|
| 201 |
+
src="https://huggingface.co/api/organizations/{hubOrg}/avatar"
|
| 202 |
alt="{message.routerMetadata.provider} logo"
|
| 203 |
+
class="size-2.5 flex-none rounded-sm"
|
| 204 |
onerror={(e) => ((e.currentTarget as HTMLImageElement).style.display = "none")}
|
| 205 |
/>
|
| 206 |
{message.routerMetadata.provider}
|
| 207 |
+
</a>
|
| 208 |
{/if}
|
| 209 |
</div>
|
| 210 |
{/if}
|
|
@@ -1,6 +1,10 @@
|
|
| 1 |
import type { Conversation } from "$lib/types/Conversation";
|
| 2 |
import type { Message } from "$lib/types/Message";
|
| 3 |
-
import type {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
import { z } from "zod";
|
| 5 |
import { endpointOAIParametersSchema, endpointOai } from "./openai/endpointOai";
|
| 6 |
import type { Model } from "$lib/types/Model";
|
|
@@ -21,7 +25,7 @@ export interface EndpointParameters {
|
|
| 21 |
|
| 22 |
export type TextGenerationStreamOutputSimplified = TextGenerationStreamOutput & {
|
| 23 |
token: TextGenerationStreamToken;
|
| 24 |
-
routerMetadata?: { route?: string; model?: string; provider?:
|
| 25 |
};
|
| 26 |
// type signature for the endpoint
|
| 27 |
export type Endpoint = (
|
|
|
|
| 1 |
import type { Conversation } from "$lib/types/Conversation";
|
| 2 |
import type { Message } from "$lib/types/Message";
|
| 3 |
+
import type {
|
| 4 |
+
TextGenerationStreamOutput,
|
| 5 |
+
TextGenerationStreamToken,
|
| 6 |
+
InferenceProvider,
|
| 7 |
+
} from "@huggingface/inference";
|
| 8 |
import { z } from "zod";
|
| 9 |
import { endpointOAIParametersSchema, endpointOai } from "./openai/endpointOai";
|
| 10 |
import type { Model } from "$lib/types/Model";
|
|
|
|
| 25 |
|
| 26 |
export type TextGenerationStreamOutputSimplified = TextGenerationStreamOutput & {
|
| 27 |
token: TextGenerationStreamToken;
|
| 28 |
+
routerMetadata?: { route?: string; model?: string; provider?: InferenceProvider };
|
| 29 |
};
|
| 30 |
// type signature for the endpoint
|
| 31 |
export type Endpoint = (
|
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import type { MessageUpdate } from "./MessageUpdate";
|
| 2 |
import type { Timestamps } from "./Timestamps";
|
| 3 |
import type { v4 } from "uuid";
|
|
@@ -20,7 +21,7 @@ export type Message = Partial<Timestamps> & {
|
|
| 20 |
routerMetadata?: {
|
| 21 |
route: string;
|
| 22 |
model: string;
|
| 23 |
-
provider?:
|
| 24 |
};
|
| 25 |
|
| 26 |
// needed for conversation trees
|
|
|
|
| 1 |
+
import type { InferenceProvider } from "@huggingface/inference";
|
| 2 |
import type { MessageUpdate } from "./MessageUpdate";
|
| 3 |
import type { Timestamps } from "./Timestamps";
|
| 4 |
import type { v4 } from "uuid";
|
|
|
|
| 21 |
routerMetadata?: {
|
| 22 |
route: string;
|
| 23 |
model: string;
|
| 24 |
+
provider?: InferenceProvider;
|
| 25 |
};
|
| 26 |
|
| 27 |
// needed for conversation trees
|
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
export type MessageUpdate =
|
| 2 |
| MessageStatusUpdate
|
| 3 |
| MessageTitleUpdate
|
|
@@ -74,5 +76,5 @@ export interface MessageRouterMetadataUpdate {
|
|
| 74 |
type: MessageUpdateType.RouterMetadata;
|
| 75 |
route: string;
|
| 76 |
model: string;
|
| 77 |
-
provider?:
|
| 78 |
}
|
|
|
|
| 1 |
+
import type { InferenceProvider } from "@huggingface/inference";
|
| 2 |
+
|
| 3 |
export type MessageUpdate =
|
| 4 |
| MessageStatusUpdate
|
| 5 |
| MessageTitleUpdate
|
|
|
|
| 76 |
type: MessageUpdateType.RouterMetadata;
|
| 77 |
route: string;
|
| 78 |
model: string;
|
| 79 |
+
provider?: InferenceProvider;
|
| 80 |
}
|
|
@@ -14,6 +14,7 @@
|
|
| 14 |
import { goto } from "$app/navigation";
|
| 15 |
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
|
| 16 |
import Switch from "$lib/components/Switch.svelte";
|
|
|
|
| 17 |
|
| 18 |
const publicConfig = usePublicConfig();
|
| 19 |
const settings = useSettingsStore();
|
|
@@ -231,15 +232,17 @@
|
|
| 231 |
</div>
|
| 232 |
<ul class="mb-0.5 flex flex-wrap gap-2">
|
| 233 |
{#each providerList as prov, i (prov.provider || i)}
|
|
|
|
| 234 |
<li>
|
| 235 |
<span
|
| 236 |
class="flex items-center gap-1 rounded-md bg-gray-100 py-0.5 pl-1.5 pr-2 text-xs text-gray-700 dark:bg-gray-700/60 dark:text-gray-200"
|
| 237 |
>
|
| 238 |
-
{#if
|
| 239 |
<img
|
| 240 |
-
|
| 241 |
-
src={`${base}/huggingchat/providers/${prov.provider}.svg`}
|
| 242 |
alt="{prov.provider} logo"
|
|
|
|
|
|
|
| 243 |
/>
|
| 244 |
{/if}
|
| 245 |
{prov.provider}
|
|
|
|
| 14 |
import { goto } from "$app/navigation";
|
| 15 |
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
|
| 16 |
import Switch from "$lib/components/Switch.svelte";
|
| 17 |
+
import { PROVIDERS_HUB_ORGS } from "@huggingface/inference";
|
| 18 |
|
| 19 |
const publicConfig = usePublicConfig();
|
| 20 |
const settings = useSettingsStore();
|
|
|
|
| 232 |
</div>
|
| 233 |
<ul class="mb-0.5 flex flex-wrap gap-2">
|
| 234 |
{#each providerList as prov, i (prov.provider || i)}
|
| 235 |
+
{@const hubOrg = PROVIDERS_HUB_ORGS[prov.provider as keyof typeof PROVIDERS_HUB_ORGS]}
|
| 236 |
<li>
|
| 237 |
<span
|
| 238 |
class="flex items-center gap-1 rounded-md bg-gray-100 py-0.5 pl-1.5 pr-2 text-xs text-gray-700 dark:bg-gray-700/60 dark:text-gray-200"
|
| 239 |
>
|
| 240 |
+
{#if hubOrg}
|
| 241 |
<img
|
| 242 |
+
src="https://huggingface.co/api/organizations/{hubOrg}/avatar"
|
|
|
|
| 243 |
alt="{prov.provider} logo"
|
| 244 |
+
class="size-2.5 flex-none rounded-sm"
|
| 245 |
+
onerror={(e) => ((e.currentTarget as HTMLImageElement).style.display = "none")}
|
| 246 |
/>
|
| 247 |
{/if}
|
| 248 |
{prov.provider}
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|
Git LFS Details
|