-
Notifications
You must be signed in to change notification settings - Fork 529
[inference provider] Add wavespeed.ai as an inference provider #1424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 42 commits
a4d8504
686931e
0e71b88
4461225
e0bf580
07af35f
fa3afa4
214ff99
47c64c6
7270c5c
ba35791
ca35eab
80d4640
77be0c6
0c77b3b
3ab254e
a8fe74c
f706e02
47f41f0
0cfefe8
f162e89
b23a000
6cabc5a
71e4939
6341233
bf5ccb4
554bd19
8507385
054ecb9
1a1f672
1b407f3
4a71a4b
839e940
64a991d
fd20f75
98465e2
4e4ca9c
76344db
f145274
dc66fd4
da95bc3
781d302
8ae96f2
8e35b64
5efd3dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
import type { TextToImageArgs } from "../tasks/cv/textToImage.js"; | ||
import type { ImageToImageArgs } from "../tasks/cv/imageToImage.js"; | ||
import type { TextToVideoArgs } from "../tasks/cv/textToVideo.js"; | ||
import type { BodyParams, RequestArgs, UrlParams } from "../types.js"; | ||
import { delay } from "../utils/delay.js"; | ||
import { omit } from "../utils/omit.js"; | ||
import { base64FromBytes } from "../utils/base64FromBytes.js"; | ||
import type { TextToImageTaskHelper, TextToVideoTaskHelper, ImageToImageTaskHelper } from "./providerHelper.js"; | ||
import { TaskProviderHelper } from "./providerHelper.js"; | ||
import { | ||
InferenceClientInputError, | ||
InferenceClientProviderApiError, | ||
InferenceClientProviderOutputError, | ||
} from "../errors.js"; | ||
|
||
const WAVESPEEDAI_API_BASE_URL = "https://api.wavespeed.ai"; | ||
|
||
/** | ||
* Response structure for task status and results | ||
*/ | ||
interface WaveSpeedAITaskResponse { | ||
id: string; | ||
model: string; | ||
outputs: string[]; | ||
urls: { | ||
get: string; | ||
}; | ||
has_nsfw_contents: boolean[]; | ||
status: "created" | "processing" | "completed" | "failed"; | ||
created_at: string; | ||
error: string; | ||
executionTime: number; | ||
timings: { | ||
inference: number; | ||
}; | ||
} | ||
|
||
/** | ||
* Response structure for initial task submission | ||
*/ | ||
interface WaveSpeedAISubmitResponse { | ||
id: string; | ||
urls: { | ||
get: string; | ||
}; | ||
} | ||
|
||
/** | ||
* Response structure for WaveSpeed AI API | ||
*/ | ||
interface WaveSpeedAIResponse { | ||
code: number; | ||
message: string; | ||
data: WaveSpeedAITaskResponse; | ||
} | ||
|
||
/** | ||
* Response structure for WaveSpeed AI API with submit response data | ||
*/ | ||
interface WaveSpeedAISubmitTaskResponse { | ||
code: number; | ||
message: string; | ||
data: WaveSpeedAISubmitResponse; | ||
} | ||
|
||
abstract class WavespeedAITask extends TaskProviderHelper { | ||
constructor(url?: string) { | ||
super("wavespeed-ai", url || WAVESPEEDAI_API_BASE_URL); | ||
} | ||
|
||
makeRoute(params: UrlParams): string { | ||
return `/api/v3/${params.model}`; | ||
} | ||
|
||
preparePayload(params: BodyParams<ImageToImageArgs | TextToImageArgs | TextToVideoArgs>): Record<string, unknown> { | ||
const payload: Record<string, unknown> = { | ||
...omit(params.args, ["inputs", "parameters"]), | ||
...params.args.parameters, | ||
prompt: params.args.inputs, | ||
}; | ||
// Add LoRA support if adapter is specified in the mapping | ||
if (params.mapping?.adapter === "lora") { | ||
payload.loras = [ | ||
{ | ||
path: params.mapping.hfModelId, | ||
scale: 1, // Default scale value | ||
}, | ||
]; | ||
} | ||
return payload; | ||
} | ||
|
||
override async getResponse( | ||
response: WaveSpeedAISubmitTaskResponse, | ||
url?: string, | ||
headers?: Record<string, string> | ||
): Promise<Blob> { | ||
if (!headers) { | ||
throw new InferenceClientInputError("Headers are required for WaveSpeed AI API calls"); | ||
} | ||
|
||
const resultUrl = response.data.urls.get; | ||
|
||
// Poll for results until completion | ||
while (true) { | ||
const resultResponse = await fetch(resultUrl, { headers }); | ||
|
||
if (!resultResponse.ok) { | ||
throw new InferenceClientProviderApiError( | ||
"Failed to fetch response status from WaveSpeed AI API", | ||
{ url: resultUrl, method: "GET" }, | ||
{ | ||
requestId: resultResponse.headers.get("x-request-id") ?? "", | ||
status: resultResponse.status, | ||
body: await resultResponse.text(), | ||
} | ||
); | ||
} | ||
|
||
const result: WaveSpeedAIResponse = await resultResponse.json(); | ||
const taskResult = result.data; | ||
|
||
switch (taskResult.status) { | ||
case "completed": { | ||
// Get the media data from the first output URL | ||
if (!taskResult.outputs?.[0]) { | ||
throw new InferenceClientProviderOutputError( | ||
"Received malformed response from WaveSpeed AI API: No output URL in completed response" | ||
); | ||
} | ||
const mediaResponse = await fetch(taskResult.outputs[0]); | ||
if (!mediaResponse.ok) { | ||
throw new InferenceClientProviderApiError( | ||
"Failed to fetch generation output from WaveSpeed AI API", | ||
{ url: taskResult.outputs[0], method: "GET" }, | ||
{ | ||
requestId: mediaResponse.headers.get("x-request-id") ?? "", | ||
status: mediaResponse.status, | ||
body: await mediaResponse.text(), | ||
} | ||
); | ||
} | ||
return await mediaResponse.blob(); | ||
} | ||
case "failed": { | ||
throw new InferenceClientProviderOutputError(taskResult.error || "Task failed"); | ||
} | ||
|
||
default: { | ||
// Wait before polling again | ||
await delay(500); | ||
continue; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
export class WavespeedAITextToImageTask extends WavespeedAITask implements TextToImageTaskHelper { | ||
constructor() { | ||
super(WAVESPEEDAI_API_BASE_URL); | ||
} | ||
} | ||
|
||
export class WavespeedAITextToVideoTask extends WavespeedAITask implements TextToVideoTaskHelper { | ||
constructor() { | ||
super(WAVESPEEDAI_API_BASE_URL); | ||
} | ||
} | ||
|
||
export class WavespeedAIImageToImageTask extends WavespeedAITask implements ImageToImageTaskHelper { | ||
constructor() { | ||
super(WAVESPEEDAI_API_BASE_URL); | ||
} | ||
|
||
hanouticelina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
async preparePayloadAsync(args: ImageToImageArgs): Promise<RequestArgs> { | ||
return { | ||
...args, | ||
inputs: args.parameters?.prompt, | ||
hanouticelina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
image: base64FromBytes( | ||
new Uint8Array(args.inputs instanceof ArrayBuffer ? args.inputs : await (args.inputs as Blob).arrayBuffer()) | ||
), | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,7 @@ export const INFERENCE_PROVIDERS = [ | |
"sambanova", | ||
"scaleway", | ||
"together", | ||
"wavespeed-ai", | ||
|
||
"zai-org", | ||
] as const; | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2291,6 +2291,119 @@ describe.skip("InferenceClient", () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TIMEOUT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
describe.concurrent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Wavespeed AI", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const client = new InferenceClient(env.HF_WAVESPEED_KEY ?? "dummy"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
HARDCODED_MODEL_INFERENCE_MAPPING["wavespeed-ai"] = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"black-forest-labs/FLUX.1-schnell": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hfModelId: "wavespeed-ai/flux-schnell", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
arabot777 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
providerId: "wavespeed-ai/flux-schnell", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: "live", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
task: "text-to-image", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Wan-AI/Wan2.1-T2V-14B": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hfModelId: "wavespeed-ai/wan-2.1/t2v-480p", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
providerId: "wavespeed-ai/wan-2.1/t2v-480p", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: "live", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
task: "text-to-video", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"HiDream-ai/HiDream-E1-Full": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hfModelId: "wavespeed-ai/hidream-e1-full", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
providerId: "wavespeed-ai/hidream-e1-full", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: "live", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
task: "image-to-image", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"openfree/flux-chatgpt-ghibli-lora": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hfModelId: "openfree/flux-chatgpt-ghibli-lora", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
providerId: "wavespeed-ai/flux-dev-lora", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: "live", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
task: "text-to-image", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
adapter: "lora", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
adapterWeightsPath: "openfree/flux-chatgpt-ghibli-lora", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"linoyts/yarn_art_Flux_LoRA": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hfModelId: "linoyts/yarn_art_Flux_LoRA", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
providerId: "wavespeed-ai/flux-dev-lora-ultra-fast", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
status: "live", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
task: "text-to-image", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
adapter: "lora", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
adapterWeightsPath: "linoyts/yarn_art_Flux_LoRA", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
2321
to
2338
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The value for
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it(`textToImage - black-forest-labs/FLUX.1-schnell`, async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const res = await client.textToImage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model: "black-forest-labs/FLUX.1-schnell", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
inputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Cute boy with a hat, exploring nature, holding a telescope, backpack, surrounded by flowers, cartoon style, vibrant colors.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(res).toBeInstanceOf(Blob); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it(`textToImage - openfree/flux-chatgpt-ghibli-lora`, async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const res = await client.textToImage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model: "openfree/flux-chatgpt-ghibli-lora", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
inputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Cute boy with a hat, exploring nature, holding a telescope, backpack, surrounded by flowers, cartoon style, vibrant colors.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(res).toBeInstanceOf(Blob); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it(`textToImage - linoyts/yarn_art_Flux_LoRA`, async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const res = await client.textToImage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model: "linoyts/yarn_art_Flux_LoRA", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
inputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Cute boy with a hat, exploring nature, holding a telescope, backpack, surrounded by flowers, cartoon style, vibrant colors.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(res).toBeInstanceOf(Blob); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it(`textToVideo - Wan-AI/Wan2.1-T2V-14B`, async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const res = await client.textToVideo({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model: "Wan-AI/Wan2.1-T2V-14B", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
inputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"A cool street dancer, wearing a baggy hoodie and hip-hop pants, dancing in front of a graffiti wall, night neon background, quick camera cuts, urban trends.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
parameters: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
guidance_scale: 5, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
num_inference_steps: 30, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
seed: -1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
duration: 5, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enable_safety_checker: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
flow_shift: 2.9, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size: "480*832", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(res).toBeInstanceOf(Blob); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it(`imageToImage - HiDream-ai/HiDream-E1-Full`, async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const res = await client.imageToImage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model: "HiDream-ai/HiDream-E1-Full", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provider: "wavespeed-ai", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
inputs: new Blob([readTestFile("cheetah.png")], { type: "image / png" }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
arabot777 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
parameters: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prompt: "The leopard chases its prey", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
guidance_scale: 5, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
num_inference_steps: 30, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
seed: -1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(res).toBeInstanceOf(Blob); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
60000 * 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
arabot777 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
describe.concurrent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"PublicAI", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.