Skip to content

Commit c507b1e

Browse files
committed
draft: add hyperbolic support
1 parent c17a753 commit c507b1e

File tree

11 files changed

+147
-13
lines changed

11 files changed

+147
-13
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
HF_REPLICATE_KEY: dummy
4646
HF_SAMBANOVA_KEY: dummy
4747
HF_TOGETHER_KEY: dummy
48-
48+
HF_HYPERBOLIC_KEY: dummy
4949
browser:
5050
runs-on: ubuntu-latest
5151
timeout-minutes: 10
@@ -85,7 +85,7 @@ jobs:
8585
HF_REPLICATE_KEY: dummy
8686
HF_SAMBANOVA_KEY: dummy
8787
HF_TOGETHER_KEY: dummy
88-
88+
HF_HYPERBOLIC_KEY: dummy
8989
e2e:
9090
runs-on: ubuntu-latest
9191
timeout-minutes: 10
@@ -152,3 +152,4 @@ jobs:
152152
HF_REPLICATE_KEY: dummy
153153
HF_SAMBANOVA_KEY: dummy
154154
HF_TOGETHER_KEY: dummy
155+
HF_HYPERBOLIC_KEY: dummy

packages/inference/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Your access token should be kept private. If you need to protect it in front-end
4646

4747
You can send inference requests to third-party providers with the inference client.
4848

49-
Currently, we support the following providers: [Fal.ai](https://fal.ai), [Replicate](https://replicate.com), [Together](https://together.xyz) and [Sambanova](https://sambanova.ai).
49+
Currently, we support the following providers: [Fal.ai](https://fal.ai), [Replicate](https://replicate.com), [Together](https://together.xyz), [Sambanova](https://sambanova.ai) and [Hyperbolic](https://hyperbolic.xyz).
5050

5151
To send requests to a third-party provider, you have to pass the `provider` parameter to the inference function. Make sure your request is authenticated with an access token.
5252
```ts
@@ -68,6 +68,7 @@ Only a subset of models are supported when requesting third-party providers. You
6868
- [Replicate supported models](./src/providers/replicate.ts)
6969
- [Sambanova supported models](./src/providers/sambanova.ts)
7070
- [Together supported models](./src/providers/together.ts)
71+
- [Hyperbolic supported models](./src/providers/hyperbolic.ts)
7172
- [HF Inference API (serverless)](https://huggingface.co/models?inference=warm&sort=trending)
7273

7374
**Important note:** To be compatible, the third-party API must adhere to the "standard" shape API we expect on HF model pages for each pipeline task type.

packages/inference/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export { FAL_AI_SUPPORTED_MODEL_IDS } from "./providers/fal-ai";
55
export { REPLICATE_SUPPORTED_MODEL_IDS } from "./providers/replicate";
66
export { SAMBANOVA_SUPPORTED_MODEL_IDS } from "./providers/sambanova";
77
export { TOGETHER_SUPPORTED_MODEL_IDS } from "./providers/together";
8+
export { HYPERBOLIC_SUPPORTED_MODEL_IDS } from "./providers/hyperbolic";
89
export * from "./types";
910
export * from "./tasks";

packages/inference/src/lib/makeRequestOptions.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FAL_AI_API_BASE_URL, FAL_AI_SUPPORTED_MODEL_IDS } from "../providers/fa
44
import { REPLICATE_API_BASE_URL, REPLICATE_SUPPORTED_MODEL_IDS } from "../providers/replicate";
55
import { SAMBANOVA_API_BASE_URL, SAMBANOVA_SUPPORTED_MODEL_IDS } from "../providers/sambanova";
66
import { TOGETHER_API_BASE_URL, TOGETHER_SUPPORTED_MODEL_IDS } from "../providers/together";
7+
import { HYPERBOLIC_API_BASE_URL, HYPERBOLIC_SUPPORTED_MODEL_IDS } from "../providers/hyperbolic";
78
import type { InferenceProvider } from "../types";
89
import type { InferenceTask, Options, RequestArgs } from "../types";
910
import { isUrl } from "./isUrl";
@@ -177,6 +178,8 @@ function mapModel(params: {
177178
return SAMBANOVA_SUPPORTED_MODEL_IDS[task]?.[params.model];
178179
case "together":
179180
return TOGETHER_SUPPORTED_MODEL_IDS[task]?.[params.model];
181+
case "hyperbolic":
182+
return HYPERBOLIC_SUPPORTED_MODEL_IDS[task]?.[params.model];
180183
}
181184
})();
182185

@@ -243,6 +246,12 @@ function makeUrl(params: {
243246
}
244247
return baseUrl;
245248
}
249+
case "hyperbolic": {
250+
const baseUrl = shouldProxy
251+
? HF_HUB_INFERENCE_PROXY_TEMPLATE.replace("{{PROVIDER}}", params.provider)
252+
: HYPERBOLIC_API_BASE_URL;
253+
return `${baseUrl}/v1/chat/completions`;
254+
}
246255
default: {
247256
const baseUrl = HF_HUB_INFERENCE_PROXY_TEMPLATE.replaceAll("{{PROVIDER}}", "hf-inference");
248257
const url = params.forceTask
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { ProviderMapping } from "./types";
2+
3+
export const HYPERBOLIC_API_BASE_URL = "https://api.hyperbolic.xyz";
4+
5+
type HyperbolicId = string;
6+
7+
/**
8+
* https://docs.together.ai/reference/models-1
9+
*/
10+
export const HYPERBOLIC_SUPPORTED_MODEL_IDS: ProviderMapping<HyperbolicId> = {
11+
"text-to-image": {
12+
"black-forest-labs/FLUX.1-dev": "black-forest-labs/FLUX.1-dev",
13+
"stabilityai/stable-diffusion-xl-base-1.0": "SDXL1.0-base",
14+
"stable-diffusion-v1-5/stable-diffusion-v1-5": "stable-diffusion-v1-5/stable-diffusion-v1-5",
15+
"segmind/SSD-1B": "segmind/SSD-1B",
16+
"stabilityai/stable-diffusion-2": "stabilityai/stable-diffusion-2",
17+
"stabilityai/sdxl-turbo": "stabilityai/sdxl-turbo",
18+
},
19+
"image-text-to-text": {
20+
"Qwen/Qwen2-VL-72B-Instruct": "Qwen/Qwen2-VL-72B-Instruct",
21+
"mistralai/Pixtral-12B-2409": "mistralai/Pixtral-12B-2409",
22+
"Qwen/Qwen2-VL-7B-Instruct": "Qwen/Qwen2-VL-7B-Instruct",
23+
},
24+
"text-generation": {
25+
"meta-llama/Llama-3.1-405B-BASE-BF16": "meta-llama/Llama-3.1-405B-BASE-BF16",
26+
"meta-llama/Llama-3.1-405B-BASE-FP8": "meta-llama/Llama-3.1-405B-BASE-FP8",
27+
"Qwen/Qwen2.5-72B-Instruct": "Qwen/Qwen2.5-72B-Instruct-BF16",
28+
},
29+
"text-to-audio": {
30+
"myshell-ai/MeloTTS-English-v3": "myshell-ai/MeloTTS-English-v3",
31+
},
32+
conversational: {
33+
"deepseek-ai/DeepSeek-R1": "deepseek-ai/DeepSeek-R1",
34+
"deepseek-ai/DeepSeek-R1-Zero": "deepseek-ai/DeepSeek-R1-Zero",
35+
"deepseek-ai/DeepSeek-V3": "deepseek-ai/DeepSeek-V3",
36+
"meta-llama/Llama-3.2-3B-Instruct": "meta-llama/Llama-3.2-3B-Instruct",
37+
"meta-llama/Llama-3.3-70B-Instruct": "meta-llama/Llama-3.3-70B-Instruct",
38+
"meta-llama/Llama-3.1-70B-Instruct": "meta-llama/Llama-3.1-70B-Instruct-BF16",
39+
"meta-llama/Meta-Llama-3-70B-Instruct": "meta-llama/Llama-3-70b-BF16",
40+
"meta-llama/Llama-3.1-8B-Instruct": "meta-llama/Llama-3.1-8B-Instruct-BF16",
41+
"NousResearch/Hermes-3-Llama-3.1-70B": "NousResearch/Hermes-3-Llama-3.1-70B-BF16",
42+
"Qwen/Qwen2.5-72B-Instruct": "Qwen/Qwen2.5-72B-Instruct-BF16",
43+
"Qwen/Qwen2.5-Coder-32B-Instruct": "Qwen/Qwen2.5-Coder-32B-Instruct-BF16",
44+
"Qwen/QwQ-32B-Preview": "Qwen/QwQ-32B-Preview-BF16",
45+
},
46+
};

packages/inference/src/tasks/custom/request.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ export async function request<T>(
3636
}
3737
if (output.error || output.detail) {
3838
throw new Error(JSON.stringify(output.error ?? output.detail));
39+
} else if (typeof output === "object") {
40+
throw new Error(JSON.stringify(output));
3941
} else {
40-
throw new Error(output);
42+
throw new Error(String(output));
4143
}
4244
}
4345
const message = contentType?.startsWith("text/plain;") ? await response.text() : undefined;

packages/inference/src/types.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,14 @@ export interface Options {
4444

4545
export type InferenceTask = Exclude<PipelineType, "other">;
4646

47-
export const INFERENCE_PROVIDERS = ["fal-ai", "replicate", "sambanova", "together", "hf-inference"] as const;
47+
export const INFERENCE_PROVIDERS = [
48+
"fal-ai",
49+
"replicate",
50+
"sambanova",
51+
"together",
52+
"hf-inference",
53+
"hyperbolic",
54+
] as const;
4855
export type InferenceProvider = (typeof INFERENCE_PROVIDERS)[number];
4956

5057
export interface BaseArgs {

packages/inference/test/HfInference.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,4 +1080,69 @@ describe.concurrent("HfInference", () => {
10801080
);
10811081
});
10821082
});
1083+
1084+
describe.concurrent(
1085+
"Hyperbolic",
1086+
() => {
1087+
const client = new HfInference(env.HF_HYPERBOLIC_KEY);
1088+
1089+
it("chatCompletion - hyperbolic", async () => {
1090+
const res = await client.chatCompletion({
1091+
model: "meta-llama/Llama-3.2-3B-Instruct",
1092+
provider: "hyperbolic",
1093+
messages: [{ role: "user", content: "Complete this sentence with words, one plus one is equal " }],
1094+
temperature: 0.1,
1095+
});
1096+
1097+
expect(res).toBeDefined();
1098+
expect(res.choices).toBeDefined();
1099+
expect(res.choices?.length).toBeGreaterThan(0);
1100+
1101+
if (res.choices && res.choices.length > 0) {
1102+
const completion = res.choices[0].message?.content;
1103+
expect(completion).toBeDefined();
1104+
expect(typeof completion).toBe("string");
1105+
expect(completion).toContain("two");
1106+
}
1107+
});
1108+
1109+
it("chatCompletion stream", async () => {
1110+
const stream = client.chatCompletionStream({
1111+
model: "meta-llama/Llama-3.3-70B-Instruct",
1112+
provider: "hyperbolic",
1113+
messages: [{ role: "user", content: "Complete the equation 1 + 1 = , just the answer" }],
1114+
}) as AsyncGenerator<ChatCompletionStreamOutput>;
1115+
let out = "";
1116+
for await (const chunk of stream) {
1117+
if (chunk.choices && chunk.choices.length > 0) {
1118+
out += chunk.choices[0].delta.content;
1119+
}
1120+
}
1121+
expect(out).toContain("2");
1122+
});
1123+
1124+
it("textToImage", async () => {
1125+
const res = await client.textToImage({
1126+
model: "stabilityai/stable-diffusion-2",
1127+
provider: "hyperbolic",
1128+
inputs: "award winning high resolution photo of a giant tortoise",
1129+
});
1130+
expect(res).toBeInstanceOf(Blob);
1131+
});
1132+
1133+
it("textGeneration", async () => {
1134+
const res = await client.textGeneration({
1135+
model: "meta-llama/Llama-3.1-405B-BASE-FP8",
1136+
provider: "hyperbolic",
1137+
inputs: "Paris is",
1138+
parameters: {
1139+
temperature: 0,
1140+
max_tokens: 10,
1141+
},
1142+
});
1143+
expect(res).toMatchObject({ generated_text: " city of love" });
1144+
});
1145+
},
1146+
TIMEOUT
1147+
);
10831148
});

packages/tasks/src/inference-providers.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
export const INFERENCE_PROVIDERS = ["hf-inference", "fal-ai", "replicate", "sambanova", "together"] as const;
1+
export const INFERENCE_PROVIDERS = [
2+
"hf-inference",
3+
"fal-ai",
4+
"replicate",
5+
"sambanova",
6+
"together",
7+
"hyperbolic",
8+
] as const;
29

310
export type InferenceProvider = (typeof INFERENCE_PROVIDERS)[number];
411

packages/tasks/src/tasks/feature-extraction/spec/input.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
"properties": {
99
"inputs": {
1010
"title": "FeatureExtractionInputs",
11-
"oneOf": [
12-
{ "type": "string" },
13-
{ "type": "array", "items": { "type": "string" } }
14-
],
11+
"oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }],
1512
"description": "The text or list of texts to embed."
1613
},
1714
"normalize": {

packages/tasks/src/tasks/text-generation/data.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ const taskData: TaskDataCustom = {
6161
},
6262
],
6363
models: [
64-
{ description: "A text-generation model trained to follow instructions.",
65-
id: "google/gemma-2-2b-it",
66-
},
64+
{ description: "A text-generation model trained to follow instructions.", id: "google/gemma-2-2b-it" },
6765
{
6866
description: "Smaller variant of one of the most powerful models.",
6967
id: "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",

0 commit comments

Comments
 (0)