diff --git a/packages/inference/src/lib/makeRequestOptions.ts b/packages/inference/src/lib/makeRequestOptions.ts index 2da705c677..c5f8adcb5b 100644 --- a/packages/inference/src/lib/makeRequestOptions.ts +++ b/packages/inference/src/lib/makeRequestOptions.ts @@ -143,10 +143,11 @@ export function makeRequestOptionsFromResolvedModel( ? endpointUrl + `/v1/chat/completions` : endpointUrl : providerConfig.makeUrl({ + authMethod, baseUrl: authMethod !== "provider-key" ? HF_HUB_INFERENCE_PROXY_TEMPLATE.replace("{{PROVIDER}}", provider) - : providerConfig.baseUrl, + : providerConfig.makeBaseUrl(task), model: resolvedModel, chatCompletion, task, diff --git a/packages/inference/src/providers/black-forest-labs.ts b/packages/inference/src/providers/black-forest-labs.ts index 80e1ada0d6..3fbc3b992f 100644 --- a/packages/inference/src/providers/black-forest-labs.ts +++ b/packages/inference/src/providers/black-forest-labs.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const BLACK_FOREST_LABS_AI_API_BASE_URL = "https://api.us1.bfl.ai"; +const makeBaseUrl = (): string => { + return BLACK_FOREST_LABS_AI_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return params.args; }; @@ -35,7 +39,7 @@ const makeUrl = (params: UrlParams): string => { }; export const BLACK_FOREST_LABS_CONFIG: ProviderConfig = { - baseUrl: BLACK_FOREST_LABS_AI_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/cerebras.ts b/packages/inference/src/providers/cerebras.ts index fbbeae92e7..cf062a4b6b 100644 --- a/packages/inference/src/providers/cerebras.ts +++ b/packages/inference/src/providers/cerebras.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const CEREBRAS_API_BASE_URL = "https://api.cerebras.ai"; +const makeBaseUrl = (): string => { + return CEREBRAS_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -34,7 +38,7 @@ const makeUrl = (params: UrlParams): string => { }; export const CEREBRAS_CONFIG: ProviderConfig = { - baseUrl: CEREBRAS_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/cohere.ts b/packages/inference/src/providers/cohere.ts index 3205d72168..7561f66858 100644 --- a/packages/inference/src/providers/cohere.ts +++ b/packages/inference/src/providers/cohere.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const COHERE_API_BASE_URL = "https://api.cohere.com"; +const makeBaseUrl = (): string => { + return COHERE_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -34,7 +38,7 @@ const makeUrl = (params: UrlParams): string => { }; export const COHERE_CONFIG: ProviderConfig = { - baseUrl: COHERE_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/fal-ai.ts b/packages/inference/src/providers/fal-ai.ts index 980085f0bc..b88f835311 100644 --- a/packages/inference/src/providers/fal-ai.ts +++ b/packages/inference/src/providers/fal-ai.ts @@ -14,9 +14,17 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import { InferenceOutputError } from "../lib/InferenceOutputError"; +import { isUrl } from "../lib/isUrl"; +import type { BodyParams, HeaderParams, InferenceTask, ProviderConfig, UrlParams } from "../types"; +import { delay } from "../utils/delay"; const FAL_AI_API_BASE_URL = "https://fal.run"; +const FAL_AI_API_BASE_URL_QUEUE = "https://queue.fal.run"; + +const makeBaseUrl = (task?: InferenceTask): string => { + return task === "text-to-video" ? FAL_AI_API_BASE_URL_QUEUE : FAL_AI_API_BASE_URL; +}; const makeBody = (params: BodyParams): Record => { return params.args; @@ -29,12 +37,86 @@ const makeHeaders = (params: HeaderParams): Record => { }; const makeUrl = (params: UrlParams): string => { - return `${params.baseUrl}/${params.model}`; + const baseUrl = `${params.baseUrl}/${params.model}`; + if (params.authMethod !== "provider-key" && params.task === "text-to-video") { + return `${baseUrl}?_subdomain=queue`; + } + return baseUrl; }; export const FAL_AI_CONFIG: ProviderConfig = { - baseUrl: FAL_AI_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, }; + +export interface FalAiQueueOutput { + request_id: string; + status: string; + response_url: string; +} + +export async function pollFalResponse( + res: FalAiQueueOutput, + url: string, + headers: Record +): Promise { + const requestId = res.request_id; + if (!requestId) { + throw new InferenceOutputError("No request ID found in the response"); + } + let status = res.status; + + const parsedUrl = new URL(url); + const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}${ + parsedUrl.host === "router.huggingface.co" ? "/fal-ai" : "" + }`; + + // extracting the provider model id for status and result urls + // from the response as it might be different from the mapped model in `url` + const modelId = new URL(res.response_url).pathname; + const queryParams = parsedUrl.search; + + const statusUrl = `${baseUrl}${modelId}/status${queryParams}`; + const resultUrl = `${baseUrl}${modelId}${queryParams}`; + + while (status !== "COMPLETED") { + await delay(500); + const statusResponse = await fetch(statusUrl, { headers }); + + if (!statusResponse.ok) { + throw new InferenceOutputError("Failed to fetch response status from fal-ai API"); + } + try { + status = (await statusResponse.json()).status; + } catch (error) { + throw new InferenceOutputError("Failed to parse status response from fal-ai API"); + } + } + + const resultResponse = await fetch(resultUrl, { headers }); + let result: unknown; + try { + result = await resultResponse.json(); + } catch (error) { + throw new InferenceOutputError("Failed to parse result response from fal-ai API"); + } + if ( + typeof result === "object" && + !!result && + "video" in result && + typeof result.video === "object" && + !!result.video && + "url" in result.video && + typeof result.video.url === "string" && + isUrl(result.video.url) + ) { + const urlResponse = await fetch(result.video.url); + return await urlResponse.blob(); + } else { + throw new InferenceOutputError( + "Expected { video: { url: string } } result format, got instead: " + JSON.stringify(result) + ); + } +} diff --git a/packages/inference/src/providers/fireworks-ai.ts b/packages/inference/src/providers/fireworks-ai.ts index c35d18044d..61c2a4b954 100644 --- a/packages/inference/src/providers/fireworks-ai.ts +++ b/packages/inference/src/providers/fireworks-ai.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const FIREWORKS_AI_API_BASE_URL = "https://api.fireworks.ai"; +const makeBaseUrl = (): string => { + return FIREWORKS_AI_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -37,7 +41,7 @@ const makeUrl = (params: UrlParams): string => { }; export const FIREWORKS_AI_CONFIG: ProviderConfig = { - baseUrl: FIREWORKS_AI_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/hf-inference.ts b/packages/inference/src/providers/hf-inference.ts index 22059a1d09..628751a1f6 100644 --- a/packages/inference/src/providers/hf-inference.ts +++ b/packages/inference/src/providers/hf-inference.ts @@ -11,7 +11,11 @@ * Thanks! */ import { HF_ROUTER_URL } from "../config"; -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; + +const makeBaseUrl = (): string => { + return `${HF_ROUTER_URL}/hf-inference`; +}; const makeBody = (params: BodyParams): Record => { return { @@ -36,7 +40,7 @@ const makeUrl = (params: UrlParams): string => { }; export const HF_INFERENCE_CONFIG: ProviderConfig = { - baseUrl: `${HF_ROUTER_URL}/hf-inference`, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/hyperbolic.ts b/packages/inference/src/providers/hyperbolic.ts index 560e17b71d..94f028a6ef 100644 --- a/packages/inference/src/providers/hyperbolic.ts +++ b/packages/inference/src/providers/hyperbolic.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const HYPERBOLIC_API_BASE_URL = "https://api.hyperbolic.xyz"; +const makeBaseUrl = (): string => { + return HYPERBOLIC_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -37,7 +41,7 @@ const makeUrl = (params: UrlParams): string => { }; export const HYPERBOLIC_CONFIG: ProviderConfig = { - baseUrl: HYPERBOLIC_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/nebius.ts b/packages/inference/src/providers/nebius.ts index 15231f6daa..6c38ddefbc 100644 --- a/packages/inference/src/providers/nebius.ts +++ b/packages/inference/src/providers/nebius.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const NEBIUS_API_BASE_URL = "https://api.studio.nebius.ai"; +const makeBaseUrl = (): string => { + return NEBIUS_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -43,7 +47,7 @@ const makeUrl = (params: UrlParams): string => { }; export const NEBIUS_CONFIG: ProviderConfig = { - baseUrl: NEBIUS_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/novita.ts b/packages/inference/src/providers/novita.ts index dba693796b..1598b04dab 100644 --- a/packages/inference/src/providers/novita.ts +++ b/packages/inference/src/providers/novita.ts @@ -14,10 +14,13 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const NOVITA_API_BASE_URL = "https://api.novita.ai"; +const makeBaseUrl = (): string => { + return NOVITA_API_BASE_URL; +}; const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -41,7 +44,7 @@ const makeUrl = (params: UrlParams): string => { }; export const NOVITA_CONFIG: ProviderConfig = { - baseUrl: NOVITA_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/openai.ts b/packages/inference/src/providers/openai.ts index 4fd5334ac4..34f550440d 100644 --- a/packages/inference/src/providers/openai.ts +++ b/packages/inference/src/providers/openai.ts @@ -1,10 +1,14 @@ /** * Special case: provider configuration for a private models provider (OpenAI in this case). */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const OPENAI_API_BASE_URL = "https://api.openai.com"; +const makeBaseUrl = (): string => { + return OPENAI_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { if (!params.chatCompletion) { throw new Error("OpenAI only supports chat completions."); @@ -27,7 +31,7 @@ const makeUrl = (params: UrlParams): string => { }; export const OPENAI_CONFIG: ProviderConfig = { - baseUrl: OPENAI_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/replicate.ts b/packages/inference/src/providers/replicate.ts index ca298a6eb7..6e2e597fa1 100644 --- a/packages/inference/src/providers/replicate.ts +++ b/packages/inference/src/providers/replicate.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; export const REPLICATE_API_BASE_URL = "https://api.replicate.com"; +const makeBaseUrl = (): string => { + return REPLICATE_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { input: params.args, @@ -39,7 +43,7 @@ const makeUrl = (params: UrlParams): string => { }; export const REPLICATE_CONFIG: ProviderConfig = { - baseUrl: REPLICATE_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/sambanova.ts b/packages/inference/src/providers/sambanova.ts index 7204a28894..1404046a3a 100644 --- a/packages/inference/src/providers/sambanova.ts +++ b/packages/inference/src/providers/sambanova.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const SAMBANOVA_API_BASE_URL = "https://api.sambanova.ai"; +const makeBaseUrl = (): string => { + return SAMBANOVA_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -37,7 +41,7 @@ const makeUrl = (params: UrlParams): string => { }; export const SAMBANOVA_CONFIG: ProviderConfig = { - baseUrl: SAMBANOVA_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/providers/together.ts b/packages/inference/src/providers/together.ts index ca5bd97dff..cf81e3d929 100644 --- a/packages/inference/src/providers/together.ts +++ b/packages/inference/src/providers/together.ts @@ -14,10 +14,14 @@ * * Thanks! */ -import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types"; +import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types"; const TOGETHER_API_BASE_URL = "https://api.together.xyz"; +const makeBaseUrl = (): string => { + return TOGETHER_API_BASE_URL; +}; + const makeBody = (params: BodyParams): Record => { return { ...params.args, @@ -43,7 +47,7 @@ const makeUrl = (params: UrlParams): string => { }; export const TOGETHER_CONFIG: ProviderConfig = { - baseUrl: TOGETHER_API_BASE_URL, + makeBaseUrl, makeBody, makeHeaders, makeUrl, diff --git a/packages/inference/src/tasks/cv/textToVideo.ts b/packages/inference/src/tasks/cv/textToVideo.ts index 7c1065519e..fddea60eb7 100644 --- a/packages/inference/src/tasks/cv/textToVideo.ts +++ b/packages/inference/src/tasks/cv/textToVideo.ts @@ -5,17 +5,13 @@ import { omit } from "../../utils/omit"; import { isUrl } from "../../lib/isUrl"; import { InferenceOutputError } from "../../lib/InferenceOutputError"; import { typedInclude } from "../../utils/typedInclude"; +import { makeRequestOptions } from "../../lib/makeRequestOptions"; +import { pollFalResponse, type FalAiQueueOutput } from "../../providers/fal-ai"; export type TextToVideoArgs = BaseArgs & TextToVideoInput; export type TextToVideoOutput = Blob; -interface FalAiOutput { - video: { - url: string; - }; -} - interface ReplicateOutput { output: string; } @@ -39,25 +35,13 @@ export async function textToVideo(args: TextToVideoArgs, options?: Options): Pro args.provider === "fal-ai" || args.provider === "replicate" || args.provider === "novita" ? { ...omit(args, ["inputs", "parameters"]), ...args.parameters, prompt: args.inputs } : args; - const res = await request(payload, { + const res = await request(payload, { ...options, task: "text-to-video", }); if (args.provider === "fal-ai") { - const isValidOutput = - typeof res === "object" && - !!res && - "video" in res && - typeof res.video === "object" && - !!res.video && - "url" in res.video && - typeof res.video.url === "string" && - isUrl(res.video.url); - if (!isValidOutput) { - throw new InferenceOutputError("Expected { video: { url: string } }"); - } - const urlResponse = await fetch((res as FalAiOutput).video.url); - return await urlResponse.blob(); + const { url, info } = await makeRequestOptions(args, { ...options, task: "text-to-video" }); + return await pollFalResponse(res as FalAiQueueOutput, url, info.headers as Record); } else if (args.provider === "novita") { const isValidOutput = typeof res === "object" && diff --git a/packages/inference/src/types.ts b/packages/inference/src/types.ts index 07f597d93f..3dd64a63b9 100644 --- a/packages/inference/src/types.ts +++ b/packages/inference/src/types.ts @@ -94,19 +94,22 @@ export type RequestArgs = BaseArgs & }; export interface ProviderConfig { - baseUrl: string; + makeBaseUrl: ((task?: InferenceTask) => string) | (() => string); makeBody: (params: BodyParams) => Record; makeHeaders: (params: HeaderParams) => Record; makeUrl: (params: UrlParams) => string; clientSideRoutingOnly?: boolean; } +export type AuthMethod = "none" | "hf-token" | "credentials-include" | "provider-key"; + export interface HeaderParams { accessToken?: string; - authMethod: "none" | "hf-token" | "credentials-include" | "provider-key"; + authMethod: AuthMethod; } export interface UrlParams { + authMethod: AuthMethod; baseUrl: string; model: string; task?: InferenceTask; diff --git a/packages/inference/test/InferenceClient.spec.ts b/packages/inference/test/InferenceClient.spec.ts index 0d16f9d1d8..04446bc6fb 100644 --- a/packages/inference/test/InferenceClient.spec.ts +++ b/packages/inference/test/InferenceClient.spec.ts @@ -11,7 +11,6 @@ import { textToImage, HfInference, } from "../src"; -import { textToVideo } from "../src/tasks/cv/textToVideo"; import { readTestFile } from "./test-files"; import "./vcr"; import { HARDCODED_MODEL_ID_MAPPING } from "../src/providers/consts"; @@ -823,63 +822,6 @@ describe.concurrent("InferenceClient", () => { text: " he has grave doubts whether sir frederick leighton's work is really greek after all and can discover in it but little of rocky ithaca", }); }); - - it("textToVideo - genmo/mochi-1-preview", async () => { - const res = await textToVideo({ - model: "genmo/mochi-1-preview", - inputs: "A running dog", - parameters: { - seed: 176, - }, - provider: "fal-ai", - accessToken: env.HF_FAL_KEY ?? "dummy", - }); - expect(res).toBeInstanceOf(Blob); - }); - - it("textToVideo - HunyuanVideo", async () => { - const res = await textToVideo({ - model: "tencent/HunyuanVideo", - inputs: "A running dog", - parameters: { - seed: 176, - num_inference_steps: 2, - num_frames: 85, - resolution: "480p", - }, - provider: "fal-ai", - accessToken: env.HF_FAL_KEY ?? "dummy", - }); - expect(res).toBeInstanceOf(Blob); - }); - - it("textToVideo - CogVideoX-5b", async () => { - const res = await textToVideo({ - model: "THUDM/CogVideoX-5b", - inputs: "A running dog", - parameters: { - seed: 176, - num_frames: 2, - }, - provider: "fal-ai", - accessToken: env.HF_FAL_KEY ?? "dummy", - }); - expect(res).toBeInstanceOf(Blob); - }); - - it("textToVideo - LTX-Video", async () => { - const res = await textToVideo({ - model: "Lightricks/LTX-Video", - inputs: "A running dog", - parameters: { - seed: 176, - num_inference_steps: 2, - }, - provider: "fal-ai", - accessToken: env.HF_FAL_KEY ?? "dummy", - }); - expect(res).toBeInstanceOf(Blob); - }); }, TIMEOUT ); @@ -981,22 +923,6 @@ describe.concurrent("InferenceClient", () => { expect(res).toBeInstanceOf(Blob); }); - - it("textToVideo Mochi", async () => { - const res = await textToVideo({ - accessToken: env.HF_REPLICATE_KEY ?? "dummy", - model: "genmo/mochi-1-preview", - provider: "replicate", - inputs: "A running dog", - parameters: { - num_inference_steps: 10, - seed: 178, - num_frames: 30, - }, - }); - - expect(res).toBeInstanceOf(Blob); - }); }, TIMEOUT ); diff --git a/packages/inference/test/tapes.json b/packages/inference/test/tapes.json index a9c490c147..c8072ea16c 100644 --- a/packages/inference/test/tapes.json +++ b/packages/inference/test/tapes.json @@ -4351,179 +4351,6 @@ } } }, - "a6b19a8094fe66f4851ebc649a3df322318b25b99637176107f850384618e1c6": { - "url": "https://fal.run/fal-ai/mochi-v1", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"parameters\":{\"seed\":176},\"prompt\":\"A running dog\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://fal.media/files/zebra/hag_CGmcxZTwm4b6RS2Ld_output_1737457748.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"output_1737457748.mp4\",\"file_size\":874855}}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "7419f8d5dd1d1975a75b0e91a6871b8ae894b1a4ea64e1fb247ed0b1791d6e85": { - "url": "https://fal.media/files/zebra/hag_CGmcxZTwm4b6RS2Ld_output_1737457748.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "9056da183f7cf196-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, - "5e581059d2855d93ea50aa8b842dcc34bc0a4844fc54b4716da42dfad1b4b3a0": { - "url": "https://fal.run/fal-ai/mochi-v1", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"prompt\":\"A running dog\",\"seed\":176,\"num_inference_steps\":2,\"num_frames\":85,\"resolution\":\"480p\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://fal.media/files/penguin/otohzMrhAzJqJihM1SZbk_output_1737461997.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"output_1737461997.mp4\",\"file_size\":938434}}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "e556343a30fe1c0cb35c68f38deefc4c0e6e5494418936ed97b89196c52d0069": { - "url": "https://fal.media/files/penguin/otohzMrhAzJqJihM1SZbk_output_1737461997.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "905741eb9d0e0350-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, - "e77a83e0190b4506c10ff4a9ca01d0514f3fa6e9bce63c016209ee122abaf9e7": { - "url": "https://fal.run/fal-ai/mochi-v1", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"prompt\":\"A running dog\",\"seed\":176}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://fal.media/files/kangaroo/03FLlitj0sw_SksFU5Ws1_output_1737462178.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"output_1737462178.mp4\",\"file_size\":1097757}}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "13f836971b1fa11dcb7ba358e46ea0bfd874762dadaff826bab503faa8b81f6b": { - "url": "https://fal.media/files/kangaroo/03FLlitj0sw_SksFU5Ws1_output_1737462178.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "905746692bf3d652-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, - "91172a3ea2588a3cb7d0888bcd5fe19e9461d273b05baf98fc7b98468227662d": { - "url": "https://api.replicate.com/v1/predictions", - "init": { - "headers": { - "Content-Type": "application/json", - "Prefer": "wait" - }, - "method": "POST", - "body": "{\"input\":{\"num_inference_steps\":10,\"seed\":178,\"num_frames\":30,\"prompt\":\"A running dog\"},\"version\":\"1944af04d098ef69bed7f9d335d102e652203f268ec4aaa2d836f6217217e460\"}" - }, - "response": { - "body": "{\"id\":\"v48356wb8srme0cmjfdrd0kmzm\",\"model\":\"genmoai/mochi-1\",\"version\":\"1944af04d098ef69bed7f9d335d102e652203f268ec4aaa2d836f6217217e460\",\"input\":{\"num_frames\":30,\"num_inference_steps\":10,\"prompt\":\"A running dog\",\"seed\":178},\"logs\":\"\",\"output\":\"https://replicate.delivery/xezq/kbgNy0QZ6bIFMJB84rMEuoD28JrnjyPfw5ZxUyaiMSkuuAEKA/output.mp4\",\"data_removed\":false,\"error\":null,\"status\":\"processing\",\"created_at\":\"2025-01-23T15:50:26.374Z\",\"urls\":{\"cancel\":\"https://api.replicate.com/v1/predictions/v48356wb8srme0cmjfdrd0kmzm/cancel\",\"get\":\"https://api.replicate.com/v1/predictions/v48356wb8srme0cmjfdrd0kmzm\",\"stream\":\"https://stream.replicate.com/v1/files/bcwr-fph2og2nch62esxtzv6ue3ohvbyai74fgqx5ylj7kvaja7fssxka\"}}", - "status": 201, - "statusText": "Created", - "headers": { - "alt-svc": "h3=\":443\"; ma=86400", - "cf-cache-status": "DYNAMIC", - "cf-ray": "9068f07e6cd82a5f-CDG", - "connection": "keep-alive", - "content-type": "application/json; charset=UTF-8", - "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}", - "preference-applied": "wait=60", - "ratelimit-remaining": "599", - "ratelimit-reset": "1", - "report-to": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=V5tXh9%2BYCF7rlqoc%2Bf%2F5Gsgmy7tRtT2Fusf%2FkQSuv7FPObfndoAZud92KeTq9ihNhh9DvY3rMpwgJo7vo30ccxVIdfXGg8WDkz9qftjILvOSceHuUk8KE4gWUgyzrEmMa2e8\"}],\"group\":\"cf-nel\",\"max_age\":604800}", - "server": "cloudflare", - "server-timing": "cfL4;desc=\"?proto=TCP&rtt=3956&min_rtt=3730&rtt_var=1560&sent=4&recv=5&lost=0&retrans=0&sent_bytes=2849&recv_bytes=979&delivery_rate=776407&cwnd=227&unsent_bytes=0&cid=148a4e2ec5c1cb4b&ts=27590&x=0\"", - "strict-transport-security": "max-age=15552000", - "vary": "Accept-Encoding" - } - } - }, - "3c111adf9405a2d0cd8396d0cbf053e7718f56128de0d1c6f06448825ba6a150": { - "url": "https://replicate.delivery/xezq/l8ZjGvxNM0ofNCs7g3on55wS1PsYp8lGlCcHNOyFfXJQmUHUA/output.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "accept-ranges": "bytes", - "access-control-allow-origin": "*", - "alt-svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000", - "cache-control": "public,max-age=3600", - "cache-id": "PAR-8ec5b013", - "cache-status": "miss", - "content-type": "video/mp4", - "etag": "\"4f3e69b2139f01c08a1f7a301223e967\"", - "last-modified": "Tue, 21 Jan 2025 12:48:16 GMT", - "server": "UploadServer" - } - } - }, "2422845812e6f1c0ddc454c0a917a3694049edaaa12d602212a7d3dea82350e8": { "url": "https://fal.run/fal-ai/flux/schnell", "init": { @@ -4564,46 +4391,6 @@ } } }, - "e026782aca942c2ad149dce0163299aac5af863924cae3e0b5a1c464ea591506": { - "url": "https://fal.run/fal-ai/mochi-v1", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"seed\":176,\"num_inference_steps\":2,\"num_frames\":85,\"resolution\":\"480p\",\"prompt\":\"A running dog\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://fal.media/files/monkey/LE5tfnsuui-CHRI53J2_G_output_1737464726.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"output_1737464726.mp4\",\"file_size\":570756}}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "7fe6560d50ca91805967420d558fd497b43eda54500c657e039b37ccb785146b": { - "url": "https://fal.media/files/monkey/LE5tfnsuui-CHRI53J2_G_output_1737464726.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "905784a69c3803ff-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, "958644a11be1d89cce04fc41ea39ae1f3602c7785baed34cfc1a4bdfde42f251": { "url": "https://api.together.xyz/v1/images/generations", "init": { @@ -4645,46 +4432,6 @@ } } }, - "c5044b473b3f8833f20875e9efcd93b965f04dcd4b0a04a460464f7abda64cac": { - "url": "https://fal.run/fal-ai/mochi-v1", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"seed\":176,\"prompt\":\"A running dog\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://fal.media/files/rabbit/dukHPBkQTdV2ZFuylnDwY_output_1737465066.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"output_1737465066.mp4\",\"file_size\":1041071}}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "318d866b234e6bec7665ed63395f2ccba1342d71df214a74125a9b551abf57b8": { - "url": "https://fal.media/files/rabbit/dukHPBkQTdV2ZFuylnDwY_output_1737465066.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "90578cdf0e34d400-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, "d7b816735bc3b62587df482bda3c3cb8c23d32b5aa971ff9a34262af0f48dc10": { "url": "https://fal.run/fal-ai/flux/schnell", "init": { @@ -5587,129 +5334,6 @@ } } }, - "8e5cd052a79581ad4c5002962c93746ffb9587cff4c55ae8b33f85e0bb6a2fdd": { - "url": "https://fal.run/fal-ai/ltx-video", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"seed\":176,\"num_inference_steps\":2,\"prompt\":\"A running dog\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://v3.fal.media/files/kangaroo/IZn0hEJxd5OoapfNX6rSq_tmpfperp_j6.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"tmpfperp_j6.mp4\",\"file_size\":9669497},\"seed\":176}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "4788fdd7d1d4311ec83fa1208de829b16e6b044607ecb4a7838eebc72114a921": { - "url": "https://v3.fal.media/files/kangaroo/IZn0hEJxd5OoapfNX6rSq_tmpfperp_j6.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "accept-ranges": "bytes", - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "908ff376b8aff120-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, - "e4c01272acc7b4b098731e451e96b8d0b087d4c72543f1a8b97cdf1834aabe27": { - "url": "https://fal.run/fal-ai/cogvideox-5b", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"seed\":176,\"num_frames\":2,\"prompt\":\"A running dog\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://v3.fal.media/files/penguin/YvilKeP7JL45cNmlJW8hP_tmp.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"tmp.mp4\",\"file_size\":4156439},\"timings\":{\"inference\":58.29187552398071},\"seed\":176,\"prompt\":\"A running dog\"}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "df62590fb03c7398302c98c0b5d5d1a7d75f77941a9b92be1682b94111e7344a": { - "url": "https://v3.fal.media/files/penguin/YvilKeP7JL45cNmlJW8hP_tmp.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "accept-ranges": "bytes", - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "908ff4b64b0cd156-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, - "0abfddc21aaed8b0b716c10a867e23fd10a779863512f2bcf10d2d97b47e8c31": { - "url": "https://fal.run/fal-ai/hunyuan-video", - "init": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{\"seed\":176,\"num_inference_steps\":2,\"num_frames\":85,\"resolution\":\"480p\",\"prompt\":\"A running dog\"}" - }, - "response": { - "body": "{\"video\":{\"url\":\"https://v3.fal.media/files/rabbit/L6wJQvUds5HsTUGLZe9Bp_video-1738056610.mp4\",\"content_type\":\"application/octet-stream\",\"file_name\":\"video-1738056610.mp4\",\"file_size\":216048},\"seed\":176}", - "status": 200, - "statusText": "OK", - "headers": { - "connection": "keep-alive", - "content-type": "application/json", - "strict-transport-security": "max-age=31536000; includeSubDomains" - } - } - }, - "b1b02865c69c8ae30637b72442f9c8f21d15f6d2af0081e5de5d59fbfd3d2d41": { - "url": "https://v3.fal.media/files/rabbit/L6wJQvUds5HsTUGLZe9Bp_video-1738056610.mp4", - "init": {}, - "response": { - "body": "", - "status": 200, - "statusText": "OK", - "headers": { - "accept-ranges": "bytes", - "access-control-allow-headers": "*", - "access-control-allow-methods": "*", - "access-control-allow-origin": "*", - "access-control-max-age": "86400", - "cf-ray": "908ff665ca2d2a03-CDG", - "connection": "keep-alive", - "content-type": "application/octet-stream", - "server": "cloudflare", - "vary": "Accept-Encoding" - } - } - }, "e9ce30eb3ef182e09ee9344b43950114e79e003713c94f4556ee0d9085b884e8": { "url": "https://huggingface.co/api/inference-proxy/hf-inference/models/lllyasviel/sd-controlnet-canny", "init": {