diff --git a/packages/inference/src/providers/wavespeed.ts b/packages/inference/src/providers/wavespeed.ts index c9d30c0ac5..558c521317 100644 --- a/packages/inference/src/providers/wavespeed.ts +++ b/packages/inference/src/providers/wavespeed.ts @@ -69,6 +69,20 @@ interface WaveSpeedAISubmitTaskResponse { data: WaveSpeedAISubmitResponse; } +async function buildImagesField( + inputs: Blob | ArrayBuffer, + hasImages: unknown +): Promise<{ base: string; images: string[] }> { + const base = base64FromBytes( + new Uint8Array(inputs instanceof ArrayBuffer ? inputs : await (inputs as Blob).arrayBuffer()) + ); + const images = + Array.isArray(hasImages) && hasImages.every((value): value is string => typeof value === "string") + ? hasImages + : [base]; + return { base, images }; +} + abstract class WavespeedAITask extends TaskProviderHelper { constructor(url?: string) { super("wavespeed", url || WAVESPEEDAI_API_BASE_URL); @@ -83,7 +97,7 @@ abstract class WavespeedAITask extends TaskProviderHelper { ): Record { const payload: Record = { ...omit(params.args, ["inputs", "parameters"]), - ...params.args.parameters, + ...(params.args.parameters ? omit(params.args.parameters as Record, ["images"]) : undefined), prompt: params.args.inputs, }; // Add LoRA support if adapter is specified in the mapping @@ -188,13 +202,10 @@ export class WavespeedAIImageToImageTask extends WavespeedAITask implements Imag } async preparePayloadAsync(args: ImageToImageArgs): Promise { - return { - ...args, - inputs: args.parameters?.prompt, - image: base64FromBytes( - new Uint8Array(args.inputs instanceof ArrayBuffer ? args.inputs : await (args.inputs as Blob).arrayBuffer()) - ), - }; + const hasImages = + (args as { images?: unknown }).images ?? (args.parameters as Record | undefined)?.images; + const { base, images } = await buildImagesField(args.inputs as Blob | ArrayBuffer, hasImages); + return { ...args, inputs: args.parameters?.prompt, image: base, images }; } } @@ -204,12 +215,9 @@ export class WavespeedAIImageToVideoTask extends WavespeedAITask implements Imag } async preparePayloadAsync(args: ImageToVideoArgs): Promise { - return { - ...args, - inputs: args.parameters?.prompt, - image: base64FromBytes( - new Uint8Array(args.inputs instanceof ArrayBuffer ? args.inputs : await (args.inputs as Blob).arrayBuffer()) - ), - }; + const hasImages = + (args as { images?: unknown }).images ?? (args.parameters as Record | undefined)?.images; + const { base, images } = await buildImagesField(args.inputs as Blob | ArrayBuffer, hasImages); + return { ...args, inputs: args.parameters?.prompt, image: base, images }; } } diff --git a/packages/inference/test/InferenceClient.spec.ts b/packages/inference/test/InferenceClient.spec.ts index 7e9d8388d5..00f9d9953f 100644 --- a/packages/inference/test/InferenceClient.spec.ts +++ b/packages/inference/test/InferenceClient.spec.ts @@ -2297,6 +2297,22 @@ describe.skip("InferenceClient", () => { const client = new InferenceClient(env.HF_WAVESPEED_KEY ?? "dummy"); HARDCODED_MODEL_INFERENCE_MAPPING["wavespeed"] = { + "Qwen/Qwen-Image-Edit-2509": { + provider: "wavespeed", + hfModelId: "Qwen/Qwen-Image-Edit-2509", + providerId: "wavespeed-ai/qwen-image/edit-plus-lora", + status: "live", + task: "image-to-image", + }, + "dx8152/Qwen-Edit-2509-Multiple-angles": { + provider: "wavespeed", + hfModelId: "dx8152/Qwen-Edit-2509-Multiple-angles", + providerId: "wavespeed-ai/qwen-image/edit-plus-lora", + status: "live", + task: "image-to-image", + adapter: "lora", + adapterWeightsPath: "镜头转换.safetensors", + }, "black-forest-labs/FLUX.1-schnell": { provider: "wavespeed", hfModelId: "black-forest-labs/FLUX.1-schnell", @@ -2421,6 +2437,32 @@ describe.skip("InferenceClient", () => { }); expect(res).toBeInstanceOf(Blob); }); + it(`imageToImage - Qwen/Qwen-Image-Edit-2509`, async () => { + const res = await client.imageToImage({ + model: "Qwen/Qwen-Image-Edit-2509", + provider: "wavespeed", + inputs: new Blob([readTestFile("cheetah.png")], { type: "image/png" }), + parameters: { + prompt: "Turn the animal's head left", + }, + }); + expect(res).toBeInstanceOf(Blob); + }); + it(`imageToImage - dx8152/Qwen-Edit-2509-Multiple-angles`, async () => { + const res = await client.imageToImage({ + model: "dx8152/Qwen-Edit-2509-Multiple-angles", + provider: "wavespeed", + inputs: new Blob([readTestFile("cheetah.png")], { type: "image/png" }), + parameters: { + prompt: "Turn the animal's head left", + images: [ + new Blob([readTestFile("cheetah.png")], { type: "image/png" }), + new Blob([readTestFile("bird_canny.png")], { type: "image/png" }), + ], + }, + }); + expect(res).toBeInstanceOf(Blob); + }); }, TIMEOUT );