enzostvs HF Staff commited on
Commit
3cd60cd
·
1 Parent(s): 8aa7247

show what provider has been used

Browse files
src/lib/chat/triggerAiCall.ts CHANGED
@@ -89,6 +89,8 @@ export async function triggerAiCall(ctx: TriggerAiCallContext): Promise<void> {
89
  }
90
  if (!response.body) throw new Error('No response body');
91
 
 
 
92
  let content = '';
93
  let reasoning = '';
94
  let usage: TokenUsage | null = null;
@@ -124,7 +126,8 @@ export async function triggerAiCall(ctx: TriggerAiCallContext): Promise<void> {
124
  timestamp: end - start,
125
  loading: false,
126
  messages,
127
- usage
 
128
  } as Record<string, unknown>,
129
  { replace: true }
130
  );
 
89
  }
90
  if (!response.body) throw new Error('No response body');
91
 
92
+ const inferenceProvider = response.headers.get('x-inference-provider');
93
+
94
  let content = '';
95
  let reasoning = '';
96
  let usage: TokenUsage | null = null;
 
126
  timestamp: end - start,
127
  loading: false,
128
  messages,
129
+ usage,
130
+ inferenceProvider
131
  } as Record<string, unknown>,
132
  { replace: true }
133
  );
src/lib/components/chat/Assistant.svelte CHANGED
@@ -18,9 +18,8 @@
18
  import { Button } from '$lib/components/ui/button';
19
  import Message from './Message.svelte';
20
  import Spinner from '$lib/components/loading/Spinner.svelte';
21
- import { formatUsageCost } from '$lib';
22
  import { modelsState } from '$lib/state/models.svelte';
23
- import { PROVIDER_SELECTION_MODES } from '$lib/consts';
24
  import ListModels from '$lib/components/model/ListModels.svelte';
25
 
26
  let { id }: NodeProps = $props();
@@ -46,6 +45,9 @@
46
  } as unknown as ChatMessage)
47
  : null
48
  );
 
 
 
49
  let containerRef: HTMLDivElement | null = $state(null);
50
  let articleRef: HTMLElement | null = $state(null);
51
  let selectedText = $state<string | null>(null);
@@ -155,7 +157,7 @@
155
  {/if}
156
  {#if message}
157
  <div bind:this={containerRef}>
158
- <Message {message} />
159
  </div>
160
  {/if}
161
  </div>
@@ -180,21 +182,12 @@
180
  <span class="inline-flex items-center gap-0.5">
181
  Using
182
  <span class="inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-2 pl-1">
183
- {#if PROVIDER_SELECTION_MODES.find((m) => m.value === provider)}
184
- {@const mode = PROVIDER_SELECTION_MODES.find((m) => m.value === provider)!}
185
- <span
186
- class="inline-flex size-4 items-center justify-center rounded-full {mode.class}"
187
- >
188
- <mode.icon class="size-2.5 {mode.iconClass}" />
189
- </span>
190
- {:else}
191
- <img
192
- src={`https://huggingface.co/api/avatars/${provider}`}
193
- alt={provider}
194
- class="size-4 rounded-full"
195
- />
196
- {/if}
197
- {provider}
198
  </span>
199
  provider
200
  </span>
 
18
  import { Button } from '$lib/components/ui/button';
19
  import Message from './Message.svelte';
20
  import Spinner from '$lib/components/loading/Spinner.svelte';
21
+ import { formatUsageCost, getProviderName } from '$lib';
22
  import { modelsState } from '$lib/state/models.svelte';
 
23
  import ListModels from '$lib/components/model/ListModels.svelte';
24
 
25
  let { id }: NodeProps = $props();
 
45
  } as unknown as ChatMessage)
46
  : null
47
  );
48
+ let inferenceProvider = $derived(
49
+ getProviderName((nodeData.current?.data.inferenceProvider as string) ?? null)
50
+ );
51
  let containerRef: HTMLDivElement | null = $state(null);
52
  let articleRef: HTMLElement | null = $state(null);
53
  let selectedText = $state<string | null>(null);
 
157
  {/if}
158
  {#if message}
159
  <div bind:this={containerRef}>
160
+ <Message {message} nodeId={id} />
161
  </div>
162
  {/if}
163
  </div>
 
182
  <span class="inline-flex items-center gap-0.5">
183
  Using
184
  <span class="inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-2 pl-1">
185
+ <img
186
+ src={`https://huggingface.co/api/avatars/${inferenceProvider}`}
187
+ alt={inferenceProvider}
188
+ class="size-4 rounded-full"
189
+ />
190
+ {inferenceProvider}
 
 
 
 
 
 
 
 
 
191
  </span>
192
  provider
193
  </span>
src/lib/index.ts CHANGED
@@ -28,7 +28,8 @@ export function formatUsageCost(pricing: ChatModelProvider['pricing'], usage: To
28
 
29
  export function getProviderName(provider: string) {
30
  const providersMap = {
31
- together: 'togethercomputer'
 
32
  };
33
  return providersMap[provider as keyof typeof providersMap] ?? provider;
34
  }
 
28
 
29
  export function getProviderName(provider: string) {
30
  const providersMap = {
31
+ together: 'togethercomputer',
32
+ sambanova: 'sambanovasystems'
33
  };
34
  return providersMap[provider as keyof typeof providersMap] ?? provider;
35
  }
src/routes/api/+server.ts CHANGED
@@ -21,31 +21,43 @@ export async function POST({ request }: RequestEvent) {
21
 
22
  const client = new InferenceClient(token);
23
 
24
- const stream = client.chatCompletionStream(
25
- {
26
- model: model + (provider !== 'auto' ? `:${provider}` : ''),
27
- ...(options ?? {}),
28
- messages: [
29
- {
30
- role: 'system',
31
- content:
32
- "You are a helpful assistant. You are very helpful and friendly. Use markdown to format your responses, but don't include array start and end markers."
33
- },
34
- ...(messages ?? [])
35
- ]
36
- },
37
- {
38
- ...(billingTo === 'personal' ? {} : { billTo: billingTo })
39
- }
40
- );
 
 
 
 
 
 
 
 
 
41
 
42
- const readable = new ReadableStream({
43
- async start(controller) {
44
- const encoder = new TextEncoder();
45
- let lastUsage: Record<string, unknown> | null = null;
46
- let reasoning: string | null = '';
47
- try {
48
- for await (const chunk of stream) {
 
 
 
49
  const content = chunk.choices?.[0]?.delta?.content ?? '';
50
  const reasoningContent = chunk.choices?.[0]?.delta?.reasoning_content ?? '';
51
  if (chunk.usage) {
@@ -70,24 +82,40 @@ export async function POST({ request }: RequestEvent) {
70
  }
71
  controller.enqueue(encoder.encode(content));
72
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
- if (lastUsage) {
75
- controller.enqueue(encoder.encode(`\n\n__USAGE__${JSON.stringify(lastUsage)}`));
76
- }
77
- } catch (err) {
78
- const message = err instanceof Error ? err.message : 'An unknown error occurred';
79
- controller.enqueue(encoder.encode(`\n\n__ERROR__${message}`));
80
- } finally {
81
- controller.close();
82
  }
83
- }
84
- });
85
 
86
- return new Response(readable, {
87
- headers: {
88
  'Content-Type': 'text/plain; charset=utf-8',
89
  'Cache-Control': 'no-cache',
90
  Connection: 'keep-alive'
 
 
 
91
  }
92
- });
 
 
 
 
 
 
93
  }
 
21
 
22
  const client = new InferenceClient(token);
23
 
24
+ let resolvedProvider: string | null = null;
25
+ const interceptFetch: typeof fetch = async (...args) => {
26
+ const response = await fetch(...args);
27
+ resolvedProvider = response.headers.get('x-inference-provider');
28
+ return response;
29
+ };
30
+
31
+ try {
32
+ const stream = client.chatCompletionStream(
33
+ {
34
+ model: model + (provider !== 'auto' ? `:${provider}` : ''),
35
+ ...(options ?? {}),
36
+ messages: [
37
+ {
38
+ role: 'system',
39
+ content:
40
+ "You are a helpful assistant. You are very helpful and friendly. Use markdown to format your responses, but don't include array start and end markers."
41
+ },
42
+ ...(messages ?? [])
43
+ ]
44
+ },
45
+ {
46
+ ...(billingTo === 'personal' ? {} : { billTo: billingTo }),
47
+ fetch: interceptFetch
48
+ }
49
+ );
50
 
51
+ const firstResult = await stream.next();
52
+
53
+ const readable = new ReadableStream({
54
+ async start(controller) {
55
+ const encoder = new TextEncoder();
56
+ let lastUsage: Record<string, unknown> | null = null;
57
+ let reasoning: string | null = '';
58
+
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ const processChunk = (chunk: any) => {
61
  const content = chunk.choices?.[0]?.delta?.content ?? '';
62
  const reasoningContent = chunk.choices?.[0]?.delta?.reasoning_content ?? '';
63
  if (chunk.usage) {
 
82
  }
83
  controller.enqueue(encoder.encode(content));
84
  }
85
+ };
86
+
87
+ try {
88
+ if (!firstResult.done && firstResult.value) {
89
+ processChunk(firstResult.value);
90
+ }
91
+ for await (const chunk of stream) {
92
+ processChunk(chunk);
93
+ }
94
+ if (lastUsage) {
95
+ controller.enqueue(encoder.encode(`\n\n__USAGE__${JSON.stringify(lastUsage)}`));
96
+ }
97
+ } catch (err) {
98
+ const message = err instanceof Error ? err.message : 'An unknown error occurred';
99
+ controller.enqueue(encoder.encode(`\n\n__ERROR__${message}`));
100
+ } finally {
101
+ controller.close();
102
  }
 
 
 
 
 
 
 
 
103
  }
104
+ });
 
105
 
106
+ const responseHeaders: Record<string, string> = {
 
107
  'Content-Type': 'text/plain; charset=utf-8',
108
  'Cache-Control': 'no-cache',
109
  Connection: 'keep-alive'
110
+ };
111
+ if (resolvedProvider) {
112
+ responseHeaders['x-inference-provider'] = resolvedProvider;
113
  }
114
+ return new Response(readable, { headers: responseHeaders });
115
+ } catch (error) {
116
+ return json(
117
+ { error: error instanceof Error ? error.message : 'An unknown error occurred' },
118
+ { status: 500 }
119
+ );
120
+ }
121
  }