diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b488e42d3c..357b34b51b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,14 +41,15 @@ jobs: run: VCR_MODE=playback pnpm --filter ...[${{ steps.since.outputs.SINCE }}] test env: HF_TOKEN: ${{ secrets.HF_TOKEN }} + HF_BLACK_FOREST_LABS_KEY: dummy HF_FAL_KEY: dummy + HF_FIREWORKS_KEY: dummy + HF_HYPERBOLIC_KEY: dummy HF_NEBIUS_KEY: dummy + HF_NOVITA_KEY: dummy HF_REPLICATE_KEY: dummy HF_SAMBANOVA_KEY: dummy HF_TOGETHER_KEY: dummy - HF_NOVITA_KEY: dummy - HF_FIREWORKS_KEY: dummy - HF_BLACK_FOREST_LABS_KEY: dummy browser: runs-on: ubuntu-latest @@ -85,14 +86,15 @@ jobs: run: VCR_MODE=playback pnpm --filter ...[${{ steps.since.outputs.SINCE }}] test:browser env: HF_TOKEN: ${{ secrets.HF_TOKEN }} + HF_BLACK_FOREST_LABS_KEY: dummy HF_FAL_KEY: dummy + HF_FIREWORKS_KEY: dummy + HF_HYPERBOLIC_KEY: dummy HF_NEBIUS_KEY: dummy + HF_NOVITA_KEY: dummy HF_REPLICATE_KEY: dummy HF_SAMBANOVA_KEY: dummy HF_TOGETHER_KEY: dummy - HF_NOVITA_KEY: dummy - HF_FIREWORKS_KEY: dummy - HF_BLACK_FOREST_LABS_KEY: dummy e2e: runs-on: ubuntu-latest @@ -156,11 +158,12 @@ jobs: env: NPM_CONFIG_REGISTRY: http://localhost:4874/ HF_TOKEN: ${{ secrets.HF_TOKEN }} + HF_BLACK_FOREST_LABS_KEY: dummy HF_FAL_KEY: dummy + HF_FIREWORKS_KEY: dummy + HF_HYPERBOLIC_KEY: dummy HF_NEBIUS_KEY: dummy + HF_NOVITA_KEY: dummy HF_REPLICATE_KEY: dummy HF_SAMBANOVA_KEY: dummy HF_TOGETHER_KEY: dummy - HF_NOVITA_KEY: dummy - HF_FIREWORKS_KEY: dummy - HF_BLACK_FOREST_LABS_KEY: dummy diff --git a/packages/inference/README.md b/packages/inference/README.md index d537f81254..3289fc6746 100644 --- a/packages/inference/README.md +++ b/packages/inference/README.md @@ -49,6 +49,7 @@ You can send inference requests to third-party providers with the inference clie Currently, we support the following providers: - [Fal.ai](https://fal.ai) - [Fireworks AI](https://fireworks.ai) +- [Hyperbolic](https://hyperbolic.xyz) - [Nebius](https://studio.nebius.ai) - [Novita](https://novita.ai/?utm_source=github_huggingface&utm_medium=github_readme&utm_campaign=link) - [Replicate](https://replicate.com) @@ -74,6 +75,7 @@ When authenticated with a third-party provider key, the request is made directly Only a subset of models are supported when requesting third-party providers. You can check the list of supported models per pipeline tasks here: - [Fal.ai supported models](https://huggingface.co/api/partners/fal-ai/models) - [Fireworks AI supported models](https://huggingface.co/api/partners/fireworks-ai/models) +- [Hyperbolic supported models](https://huggingface.co/api/partners/hyperbolic/models) - [Nebius supported models](https://huggingface.co/api/partners/nebius/models) - [Replicate supported models](https://huggingface.co/api/partners/replicate/models) - [Sambanova supported models](https://huggingface.co/api/partners/sambanova/models) diff --git a/packages/inference/src/lib/makeRequestOptions.ts b/packages/inference/src/lib/makeRequestOptions.ts index ede35fa8c8..654c7b8b8c 100644 --- a/packages/inference/src/lib/makeRequestOptions.ts +++ b/packages/inference/src/lib/makeRequestOptions.ts @@ -6,6 +6,7 @@ import { SAMBANOVA_API_BASE_URL } from "../providers/sambanova"; import { TOGETHER_API_BASE_URL } from "../providers/together"; import { NOVITA_API_BASE_URL } from "../providers/novita"; import { FIREWORKS_AI_API_BASE_URL } from "../providers/fireworks-ai"; +import { HYPERBOLIC_API_BASE_URL } from "../providers/hyperbolic"; import { BLACKFORESTLABS_AI_API_BASE_URL } from "../providers/black-forest-labs"; import type { InferenceProvider } from "../types"; import type { InferenceTask, Options, RequestArgs } from "../types"; @@ -132,7 +133,11 @@ export async function makeRequestOptions( ? args.data : JSON.stringify({ ...otherArgs, - ...(chatCompletion || provider === "together" || provider === "nebius" ? { model } : undefined), + ...(taskHint === "text-to-image" && provider === "hyperbolic" + ? { model_name: model } + : chatCompletion || provider === "together" || provider === "nebius" || provider === "hyperbolic" + ? { model } + : undefined), }), ...(credentials ? { credentials } : undefined), signal: options?.signal, @@ -229,6 +234,16 @@ function makeUrl(params: { } return baseUrl; } + case "hyperbolic": { + const baseUrl = shouldProxy + ? HF_HUB_INFERENCE_PROXY_TEMPLATE.replace("{{PROVIDER}}", params.provider) + : HYPERBOLIC_API_BASE_URL; + + if (params.taskHint === "text-to-image") { + return `${baseUrl}/v1/images/generations`; + } + return `${baseUrl}/v1/chat/completions`; + } case "novita": { const baseUrl = shouldProxy ? HF_HUB_INFERENCE_PROXY_TEMPLATE.replace("{{PROVIDER}}", params.provider) diff --git a/packages/inference/src/providers/consts.ts b/packages/inference/src/providers/consts.ts index 2ad19bb0fd..c898064496 100644 --- a/packages/inference/src/providers/consts.ts +++ b/packages/inference/src/providers/consts.ts @@ -20,6 +20,7 @@ export const HARDCODED_MODEL_ID_MAPPING: Record Hyperbolic model ID here: + * + * https://huggingface.co/api/partners/hyperbolic/models + * + * This is a publicly available mapping. + * + * If you want to try to run inference for a new model locally before it's registered on huggingface.co, + * you can add it to the dictionary "HARDCODED_MODEL_ID_MAPPING" in consts.ts, for dev purposes. + * + * - If you work at Hyperbolic and want to update this mapping, please use the model mapping API we provide on huggingface.co + * - If you're a community member and want to add a new supported HF model to Hyperbolic, please open an issue on the present repo + * and we will tag Hyperbolic team members. + * + * Thanks! + */ diff --git a/packages/inference/src/tasks/cv/textToImage.ts b/packages/inference/src/tasks/cv/textToImage.ts index cd621861aa..79b79966f7 100644 --- a/packages/inference/src/tasks/cv/textToImage.ts +++ b/packages/inference/src/tasks/cv/textToImage.ts @@ -15,6 +15,10 @@ interface Base64ImageGeneration { interface OutputUrlImageGeneration { output: string[]; } +interface HyperbolicTextToImageOutput { + images: Array<{ image: string }>; +} + interface BlackForestLabsResponse { id: string; polling_url: string; @@ -50,7 +54,11 @@ export async function textToImage(args: TextToImageArgs, options?: Options): Pro prompt: args.inputs, }; const res = await request< - TextToImageOutput | Base64ImageGeneration | OutputUrlImageGeneration | BlackForestLabsResponse + | TextToImageOutput + | Base64ImageGeneration + | OutputUrlImageGeneration + | BlackForestLabsResponse + | HyperbolicTextToImageOutput >(payload, { ...options, taskHint: "text-to-image", @@ -64,6 +72,17 @@ export async function textToImage(args: TextToImageArgs, options?: Options): Pro const image = await fetch(res.images[0].url); return await image.blob(); } + if ( + args.provider === "hyperbolic" && + "images" in res && + Array.isArray(res.images) && + res.images[0] && + typeof res.images[0].image === "string" + ) { + const base64Response = await fetch(`data:image/jpeg;base64,${res.images[0].image}`); + const blob = await base64Response.blob(); + return blob; + } if ("data" in res && Array.isArray(res.data) && res.data[0].b64_json) { const base64Data = res.data[0].b64_json; const base64Response = await fetch(`data:image/jpeg;base64,${base64Data}`); diff --git a/packages/inference/src/tasks/nlp/textGeneration.ts b/packages/inference/src/tasks/nlp/textGeneration.ts index 7d5906f124..44faca3635 100644 --- a/packages/inference/src/tasks/nlp/textGeneration.ts +++ b/packages/inference/src/tasks/nlp/textGeneration.ts @@ -8,6 +8,7 @@ import { InferenceOutputError } from "../../lib/InferenceOutputError"; import type { BaseArgs, Options } from "../../types"; import { toArray } from "../../utils/toArray"; import { request } from "../custom/request"; +import { omit } from "../../utils/omit"; export type { TextGenerationInput, TextGenerationOutput }; @@ -21,6 +22,12 @@ interface TogeteherTextCompletionOutput extends Omit; } +interface HyperbolicTextCompletionOutput extends Omit { + choices: Array<{ + message: { content: string }; + }>; +} + /** * Use to continue text from a prompt. This is a very generic task. Recommended model: gpt2 (it’s a simple model, but fun to play with). */ @@ -43,6 +50,30 @@ export async function textGeneration( return { generated_text: completion.text, }; + } else if (args.provider === "hyperbolic") { + const payload = { + messages: [{ content: args.inputs, role: "user" }], + ...(args.parameters + ? { + max_tokens: args.parameters.max_new_tokens, + ...omit(args.parameters, "max_new_tokens"), + } + : undefined), + ...omit(args, ["inputs", "parameters"]), + }; + const raw = await request(payload, { + ...options, + taskHint: "text-generation", + }); + const isValidOutput = + typeof raw === "object" && "choices" in raw && Array.isArray(raw?.choices) && typeof raw?.model === "string"; + if (!isValidOutput) { + throw new InferenceOutputError("Expected ChatCompletionOutput"); + } + const completion = raw.choices[0]; + return { + generated_text: completion.message.content, + }; } else { const res = toArray( await request(args, { diff --git a/packages/inference/src/types.ts b/packages/inference/src/types.ts index d6eed1fc77..3e230c59f5 100644 --- a/packages/inference/src/types.ts +++ b/packages/inference/src/types.ts @@ -33,6 +33,7 @@ export const INFERENCE_PROVIDERS = [ "fal-ai", "fireworks-ai", "hf-inference", + "hyperbolic", "nebius", "novita", "replicate", diff --git a/packages/inference/test/HfInference.spec.ts b/packages/inference/test/HfInference.spec.ts index cebfd04d36..4a8c3abc03 100644 --- a/packages/inference/test/HfInference.spec.ts +++ b/packages/inference/test/HfInference.spec.ts @@ -2,7 +2,8 @@ import { assert, describe, expect, it } from "vitest"; import type { ChatCompletionStreamOutput } from "@huggingface/tasks"; -import { chatCompletion, HfInference, textToImage } from "../src"; +import type { TextToImageArgs } from "../src"; +import { chatCompletion, chatCompletionStream, HfInference, textGeneration, textToImage } from "../src"; import { textToVideo } from "../src/tasks/cv/textToVideo"; import { readTestFile } from "./test-files"; import "./vcr"; @@ -1176,6 +1177,85 @@ describe.concurrent("HfInference", () => { TIMEOUT ); + describe.concurrent( + "Hyperbolic", + () => { + HARDCODED_MODEL_ID_MAPPING.hyperbolic = { + "meta-llama/Llama-3.2-3B-Instruct": "meta-llama/Llama-3.2-3B-Instruct", + "meta-llama/Llama-3.3-70B-Instruct": "meta-llama/Llama-3.3-70B-Instruct", + "stabilityai/stable-diffusion-2": "SD2", + "meta-llama/Llama-3.1-405B": "meta-llama/Meta-Llama-3.1-405B-Instruct", + }; + + it("chatCompletion - hyperbolic", async () => { + const res = await chatCompletion({ + accessToken: env.HF_HYPERBOLIC_KEY, + model: "meta-llama/Llama-3.2-3B-Instruct", + provider: "hyperbolic", + messages: [{ role: "user", content: "Complete this sentence with words, one plus one is equal " }], + temperature: 0.1, + }); + + expect(res).toBeDefined(); + expect(res.choices).toBeDefined(); + expect(res.choices?.length).toBeGreaterThan(0); + + if (res.choices && res.choices.length > 0) { + const completion = res.choices[0].message?.content; + expect(completion).toBeDefined(); + expect(typeof completion).toBe("string"); + expect(completion).toContain("two"); + } + }); + + it("chatCompletion stream", async () => { + const stream = chatCompletionStream({ + accessToken: env.HF_HYPERBOLIC_KEY, + model: "meta-llama/Llama-3.3-70B-Instruct", + provider: "hyperbolic", + messages: [{ role: "user", content: "Complete the equation 1 + 1 = , just the answer" }], + }) as AsyncGenerator; + let out = ""; + for await (const chunk of stream) { + if (chunk.choices && chunk.choices.length > 0) { + out += chunk.choices[0].delta.content; + } + } + expect(out).toContain("2"); + }); + + it("textToImage", async () => { + const res = await textToImage({ + accessToken: env.HF_HYPERBOLIC_KEY, + model: "stabilityai/stable-diffusion-2", + provider: "hyperbolic", + inputs: "award winning high resolution photo of a giant tortoise", + parameters: { + height: 128, + width: 128, + }, + } satisfies TextToImageArgs); + expect(res).toBeInstanceOf(Blob); + }); + + it("textGeneration", async () => { + const res = await textGeneration({ + accessToken: env.HF_HYPERBOLIC_KEY, + model: "meta-llama/Llama-3.1-405B", + provider: "hyperbolic", + inputs: "Paris is", + parameters: { + temperature: 0, + top_p: 0.01, + max_new_tokens: 10, + }, + }); + expect(res).toMatchObject({ generated_text: "...the capital and most populous city of France," }); + }); + }, + TIMEOUT + ); + describe.concurrent( "Novita", () => { diff --git a/packages/inference/test/tapes.json b/packages/inference/test/tapes.json index 229654feb1..ca50d62ca3 100644 --- a/packages/inference/test/tapes.json +++ b/packages/inference/test/tapes.json @@ -7177,5 +7177,202 @@ "vary": "Accept-Encoding, Origin, Access-Control-Request-Method, Access-Control-Request-Headers" } } + }, + "cf350b7b8318fc99a88a75b2f30ae80eb99acdbc91e3507d8170a2e16f31bd52": { + "url": "https://api.hyperbolic.xyz/v1/images/generations", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"height\":128,\"width\":128,\"prompt\":\"award winning high resolution photo of a giant tortoise\",\"model\":\"SD2\"}" + }, + "response": { + "body": "{\"detail\":[{\"type\":\"missing\",\"loc\":[\"body\",\"model_name\"],\"msg\":\"Field required\",\"input\":{\"height\":128,\"width\":128,\"prompt\":\"award winning high resolution photo of a giant tortoise\",\"model\":\"SD2\"}}]}", + "status": 422, + "statusText": "Unprocessable Entity", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c432b8b660209-CDG", + "connection": "keep-alive", + "content-type": "application/json", + "server": "cloudflare" + } + } + }, + "69ced1ac246b195b512034ec57f26f29d69f669398293ac03ee12eee1623d743": { + "url": "https://api.hyperbolic.xyz/v1/chat/completions", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"messages\":[{\"role\":\"user\",\"content\":\"Complete the equation 1 + 1 = , just the answer\"}],\"stream\":true,\"model\":\"meta-llama/Llama-3.3-70B-Instruct\"}" + }, + "response": { + "body": "data: {\"id\": \"chatcmpl-384eff9930a94a08a35564ff77a93d1d\", \"object\": \"chat.completion.chunk\", \"created\": 1739527763, \"model\": \"meta-llama/Llama-3.3-70B-Instruct\", \"choices\": [{\"index\": 0, \"delta\": {\"role\": \"assistant\", \"content\": \"\"}, \"logprobs\": null, \"finish_reason\": null}], \"usage\": {\"prompt_tokens\": 48, \"total_tokens\": 49, \"completion_tokens\": 1}}\n\ndata: {\"id\": \"chatcmpl-384eff9930a94a08a35564ff77a93d1d\", \"object\": \"chat.completion.chunk\", \"created\": 1739527763, \"model\": \"meta-llama/Llama-3.3-70B-Instruct\", \"choices\": [{\"index\": 0, \"delta\": {\"content\": \"2\"}, \"logprobs\": null, \"finish_reason\": null}], \"usage\": {\"prompt_tokens\": 48, \"total_tokens\": 50, \"completion_tokens\": 2}}\n\ndata: {\"id\": \"chatcmpl-384eff9930a94a08a35564ff77a93d1d\", \"object\": \"chat.completion.chunk\", \"created\": 1739527763, \"model\": \"meta-llama/Llama-3.3-70B-Instruct\", \"choices\": [{\"index\": 0, \"delta\": {\"content\": \"\"}, \"logprobs\": null, \"finish_reason\": \"stop\", \"stop_reason\": null}], \"usage\": {\"prompt_tokens\": 48, \"total_tokens\": 51, \"completion_tokens\": 3}}\n\ndata: [DONE]\n\n", + "status": 200, + "statusText": "OK", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c432b88366f13-CDG", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "server": "cloudflare", + "transfer-encoding": "chunked" + } + } + }, + "10f86d757e0af0147df39651db831eade03fe35cf6ee2e45215f8c1c669a335f": { + "url": "https://api.hyperbolic.xyz/v1/chat/completions", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"messages\":[{\"role\":\"user\",\"content\":\"Complete this sentence with words, one plus one is equal \"}],\"temperature\":0.1,\"model\":\"meta-llama/Llama-3.2-3B-Instruct\"}" + }, + "response": { + "body": "{\"id\":\"chat-1da8aa70d8a047769b2561108ea3eb3d\",\"object\":\"chat.completion\",\"created\":1739527764,\"model\":\"meta-llama/Llama-3.2-3B-Instruct\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"...two.\"},\"finish_reason\":\"stop\",\"logprobs\":null}],\"usage\":{\"prompt_tokens\":46,\"total_tokens\":50,\"completion_tokens\":4}}", + "status": 200, + "statusText": "OK", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c432b8896702b-CDG", + "connection": "keep-alive", + "content-encoding": "gzip", + "content-type": "application/json", + "server": "cloudflare", + "transfer-encoding": "chunked" + } + } + }, + "63ed3f76e28a4f6d6aece430a994d249b13f883ab2cbcf0ff13acb7005b7625d": { + "url": "https://api.hyperbolic.xyz/v1/chat/completions", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"inputs\":\"Paris is\",\"parameters\":{\"temperature\":0,\"top_p\":0.01,\"max_new_tokens\":10},\"prompt\":\"Paris is\",\"model\":\"meta-llama/Meta-Llama-3.1-405B-Instruct\"}" + }, + "response": { + "body": "{\"detail\":[{\"type\":\"missing\",\"loc\":[\"body\",\"messages\"],\"msg\":\"Field required\",\"input\":{\"inputs\":\"Paris is\",\"parameters\":{\"temperature\":0,\"top_p\":0.01,\"max_new_tokens\":10},\"prompt\":\"Paris is\",\"model\":\"meta-llama/Meta-Llama-3.1-405B-Instruct\"}}]}", + "status": 422, + "statusText": "Unprocessable Entity", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c432b8cd8018e-CDG", + "connection": "keep-alive", + "content-type": "application/json", + "server": "cloudflare" + } + } + }, + "5ffb543765bb5fb2c759321a62828095eda7608939187ce57197ae1a618336ae": { + "url": "https://api.hyperbolic.xyz/v1/chat/completions", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"messages\":[{\"content\":\"Paris is\",\"role\":\"user\"}],\"temperature\":0,\"top_p\":0.01,\"max_new_tokens\":10,\"model\":\"meta-llama/Meta-Llama-3.1-405B-Instruct\"}" + }, + "response": { + "body": "{\"id\":\"chatcmpl-a583deb706944d9796d405f87cb28c8c\",\"object\":\"chat.completion\",\"created\":1739528712,\"model\":\"meta-llama/Meta-Llama-3.1-405B-Instruct\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"...the capital and most populous city of France, known for its stunning architecture, art museums, fashion, and romantic atmosphere. It's often called the \\\"City of Light\\\" (La Ville Lumière) and is famous for its iconic landmarks such as the Eiffel Tower, Notre-Dame Cathedral, and the Louvre Museum.\"},\"finish_reason\":\"stop\",\"logprobs\":null}],\"usage\":{\"prompt_tokens\":37,\"total_tokens\":105,\"completion_tokens\":68}}", + "status": 200, + "statusText": "OK", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c5a4dee0c78fe-CDG", + "connection": "keep-alive", + "content-encoding": "gzip", + "content-type": "application/json", + "server": "cloudflare", + "transfer-encoding": "chunked" + } + } + }, + "949ba2dd449c32f12183e7caf5a79f67db7531a2e77961d2aacc04d4a456d88c": { + "url": "https://api.hyperbolic.xyz/v1/chat/completions", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"messages\":[{\"content\":\"Paris is\",\"role\":\"user\"}],\"max_tokens\":10,\"temperature\":0,\"top_p\":0.01,\"model\":\"meta-llama/Meta-Llama-3.1-405B-Instruct\"}" + }, + "response": { + "body": "{\"id\":\"chatcmpl-02699e2a1ea24037a2f1d6622a849f1f\",\"object\":\"chat.completion\",\"created\":1739528880,\"model\":\"meta-llama/Meta-Llama-3.1-405B-Instruct\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"...the capital and most populous city of France,\"},\"finish_reason\":\"length\",\"logprobs\":null}],\"usage\":{\"prompt_tokens\":37,\"total_tokens\":47,\"completion_tokens\":10}}", + "status": 200, + "statusText": "OK", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c5e690de9d706-CDG", + "connection": "keep-alive", + "content-encoding": "gzip", + "content-type": "application/json", + "server": "cloudflare", + "transfer-encoding": "chunked" + } + } + }, + "340a2a0cae0688dfb5b0cf1d5cac1004fbf9c411ac28e420b7d098a1a1a33437": { + "url": "https://api.hyperbolic.xyz/v1/chat/completions", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"messages\":[{\"content\":\"Paris is\",\"role\":\"user\"}],\"max_tokens\":10,\"temperature\":0,\"top_p\":0.01}" + }, + "response": { + "body": "{\"object\":\"error\",\"message\":\"Only Qwen/Qwen2.5-72B-Instruct && meta-llama/Llama-3.2-3B-Instruct && FLUX.1-dev && mistralai/Pixtral-12B-2409 && StableDiffusion && Qwen/Qwen2-VL-72B-Instruct && meta-llama/Meta-Llama-3-70B-Instruct && meta-llama/Meta-Llama-3.1-70B-Instruct && meta-llama/Meta-Llama-3.1-8B-Instruct && Qwen/Qwen2.5-Coder-32B-Instruct && meta-llama/Meta-Llama-3.1-405B-FP8 && TTS && meta-llama/Meta-Llama-3.1-405B-Instruct && deepseek-ai/DeepSeek-R1-Zero && deepseek-ai/DeepSeek-V3 && Qwen/QwQ-32B-Preview && Qwen/Qwen2-VL-7B-Instruct && meta-llama/Llama-3.3-70B-Instruct && NousResearch/Hermes-3-Llama-3.1-70B && meta-llama/Meta-Llama-3.1-405B && meta-llama/Meta-Llama-3.1-405B-Instruct-Virtuals && deepseek-ai/DeepSeek-R1 allowed now, your model mistralai/Mixtral-8x7B-Instruct-v0.1\",\"type\":\"\",\"param\":null,\"code\":40301}", + "status": 400, + "statusText": "Bad Request", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c837d7d61d60d-CDG", + "connection": "keep-alive", + "content-type": "application/json", + "server": "cloudflare" + } + } + }, + "5940db1cee26d8858daa54a789c34dab857a02dc095d7d8a81dcc07262cc4e4b": { + "url": "https://api.hyperbolic.xyz/v1/images/generations", + "init": { + "headers": { + "Content-Type": "application/json" + }, + "method": "POST", + "body": "{\"height\":128,\"width\":128,\"prompt\":\"award winning high resolution photo of a giant tortoise\",\"model_name\":\"SD2\"}" + }, + "response": { + "body": "{\"images\":[{\"index\":0,\"image\":\"iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAB1/UlEQVR4nJz9ybNkSZbeif1Ur97Z5umN7v58Co85MiMjh6pCoaqAAtCNbkqTQiEFpLQIhUv+O9xxRy7J5oLSzQaaBCCFoVCVWZkZGXP47G+ebL5250m5sGcRHhmRAJoqtnBxNze7dlT16NHvfOc74v/0f/6/hMqKtAornWRlkiRRlESLZbSYp8EyC1ZllJBnIkt1FhIHRHOyFd8MCQ40oY/b91ujZmfYHozag35nNOh3u91eq9tpdTqNjmvZSlNGcTCeLc4vZ2cX6WySLgIKbRq2Y7tCirIywrRM0lpg2Z7T8Fu275quKy2ztKzKcWvHxbIqw8xLneZ5EierZRgFqyTKqrzWeVXnaZXHmnhrYN5/c/jo7e29g35n1DRcT6NijHP0aVa8mGYn8/Rymi8mSTApwuukCqXKpEgNmck6lkZlKe1bdtdxR5bTVVZLGpaQqqx0mpVxUoZxkaY5GiyF79A0rZ7rjnxvaNk9y+vitHBdLAvDQhooiWmgJBToFWI2ra5O20fnqvDauWqmWkWliEWR6HhVJJFSK+qqrMgq0pq01llJDGFJlfD6qCGGGiSJGSVukvlxlsR1WQpp2J7b6RvOdrfd2e3TclA5kdu9QGTxary6XKSzo2SVuaZLo+m5vhCeUWJWhpTC0bYltJKyrkVeibQk16awG1azaXpNS4osjrPxNFgk07iIZnGRlmUc58GqSpauVzRbLeG0h7vGnTutLfoSJ0VPYEye29V8KM+1OE71IoCiIi2JqGJJZBBoMpvSwvSt9nau9m1rm7xVC1lrypIkKYswI8xICoTAMSkthJU3zLxiqTFNfBfPx2vgmBg2NpjggAWVIpfIvF8FMpSpqvx2abUqjKo2qqyqLaeWsS6rOi1IS5KKrKYU5DWYYIDkB0cNKUT1YhGszCBUwdxcLcVqquOxzLdVMWoMGniCJKpXSxElelVU\",\"random_seed\":11489413745290867000}],\"inference_time\":0.8995649814605713}", + "status": 200, + "statusText": "OK", + "headers": { + "cf-cache-status": "DYNAMIC", + "cf-ray": "911c837d8fbb6ee4-CDG", + "connection": "keep-alive", + "content-encoding": "gzip", + "content-type": "application/json", + "server": "cloudflare", + "transfer-encoding": "chunked" + } + } + }, + "d2ca6c5690c9c4dd012d7038606c80dd388ea776f364e7395ee8196d5b1f9849": { + "url": "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAB1/UlEQVR4nJz9ybNkSZbeif1Ur97Z5umN7v58Co85MiMjh6pCoaqAAtCNbkqTQiEFpLQIhUv+O9xxRy7J5oLSzQaaBCCFoVCVWZkZGXP47G+ebL5250m5sGcRHhmRAJoqtnBxNze7dlT16NHvfOc74v/0f/6/hMqKtAornWRlkiRRlESLZbSYp8EyC1ZllJBnIkt1FhIHRHOyFd8MCQ40oY/b91ujZmfYHozag35nNOh3u91eq9tpdTqNjmvZSlNGcTCeLc4vZ2cX6WySLgIKbRq2Y7tCirIywrRM0lpg2Z7T8Fu275quKy2ztKzKcWvHxbIqw8xLneZ5EierZRgFqyTKqrzWeVXnaZXHmnhrYN5/c/jo7e29g35n1DRcT6NijHP0aVa8mGYn8/Rymi8mSTApwuukCqXKpEgNmck6lkZlKe1bdtdxR5bTVVZLGpaQqqx0mpVxUoZxkaY5GiyF79A0rZ7rjnxvaNk9y+vitHBdLAvDQhooiWmgJBToFWI2ra5O20fnqvDauWqmWkWliEWR6HhVJJFSK+qqrMgq0pq01llJDGFJlfD6qCGGGiSJGSVukvlxlsR1WQpp2J7b6RvOdrfd2e3TclA5kdu9QGTxary6XKSzo2SVuaZLo+m5vhCeUWJWhpTC0bYltJKyrkVeibQk16awG1azaXpNS4osjrPxNFgk07iIZnGRlmUc58GqSpauVzRbLeG0h7vGnTutLfoSJ0VPYEye29V8KM+1OE71IoCiIi2JqGJJZBBoMpvSwvSt9nau9m1rm7xVC1lrypIkKYswI8xICoTAMSkthJU3zLxiqTFNfBfPx2vgmBg2NpjggAWVIpfIvF8FMpSpqvx2abUqjKo2qqyqLaeWsS6rOi1IS5KKrKYU5DWYYIDkB0cNKUT1YhGszCBUwdxcLcVqquOxzLdVMWoMGniCJKpXSxElelVU", + "init": {}, + "response": { + "body": "", + "status": 200, + "statusText": "OK", + "headers": { + "content-type": "image/jpeg" + } + } } } \ No newline at end of file