79 lines
3.5 KiB
TypeScript
79 lines
3.5 KiB
TypeScript
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
bailianResultUrls,
|
|
bailianStatus,
|
|
buildBailianImagePayload,
|
|
buildBailianVideoPayload,
|
|
deriveBailianNativeBaseUrl,
|
|
shouldMockBailian
|
|
} from "@/lib/bailian/client";
|
|
|
|
afterEach(() => {
|
|
delete process.env.BAILIAN_IMAGE_MODEL;
|
|
delete process.env.BAILIAN_VIDEO_MODEL;
|
|
delete process.env.BAILIAN_API_KEY;
|
|
delete process.env.DASHSCOPE_API_KEY;
|
|
delete process.env.BAILIAN_MOCK;
|
|
});
|
|
|
|
describe("Bailian client", () => {
|
|
it("derives native API base from compatible-mode URL", () => {
|
|
expect(deriveBailianNativeBaseUrl("https://workspace.cn-beijing.maas.aliyuncs.com/compatible-mode/v1"))
|
|
.toBe("https://workspace.cn-beijing.maas.aliyuncs.com");
|
|
});
|
|
|
|
it("does not silently mock when the API key is missing", () => {
|
|
expect(shouldMockBailian()).toBe(false);
|
|
process.env.BAILIAN_MOCK = "true";
|
|
expect(shouldMockBailian()).toBe(true);
|
|
});
|
|
|
|
it("builds Wan 2.7 text-to-image and reference-image payloads", () => {
|
|
const text = buildBailianImagePayload("image.generate", { prompt: "海边酒店", width: 2048, height: 2048 });
|
|
expect(text).toMatchObject({ model: "wan2.7-image-pro", parameters: { size: "2048*2048", thinking_mode: true, watermark: false } });
|
|
const edit = buildBailianImagePayload("image.generate", { prompt: "保持人物一致", imageUrls: ["https://example.com/a.png"], width: 2048, height: 2048 });
|
|
expect((edit.input.messages[0].content as Array<Record<string, string>>)[0]).toEqual({ image: "https://example.com/a.png" });
|
|
expect(edit.parameters).not.toHaveProperty("thinking_mode");
|
|
});
|
|
|
|
it("preserves a user-selected 9:16 output size for reference images", () => {
|
|
const payload = buildBailianImagePayload("image.generate", {
|
|
prompt: "x",
|
|
imageUrls: ["https://example.com/a.png"],
|
|
width: 1440,
|
|
height: 2560
|
|
});
|
|
expect(payload.parameters.size).toBe("1440*2560");
|
|
});
|
|
|
|
it("rejects reference-image output only when total pixels exceed the 2K budget", () => {
|
|
expect(() => buildBailianImagePayload("image.generate", { prompt: "x", imageUrls: ["https://example.com/a.png"], width: 2048, height: 2560 }))
|
|
.toThrow("总像素");
|
|
});
|
|
|
|
it("maps one or two video images to first and last frames", () => {
|
|
const payload = buildBailianVideoPayload({
|
|
prompt: "镜头推进",
|
|
origin: "https://app.example.com",
|
|
materials: [{ type: "image", url: "/first.png" }, { type: "image", url: "/last.png" }],
|
|
settings: { duration: 10, resolution: "1080P" }
|
|
});
|
|
expect(payload.input.media).toEqual([
|
|
{ type: "first_frame", url: "https://app.example.com/first.png" },
|
|
{ type: "last_frame", url: "https://app.example.com/last.png" }
|
|
]);
|
|
expect(payload.parameters).toMatchObject({ duration: 10, resolution: "1080P", prompt_extend: true, watermark: false });
|
|
});
|
|
|
|
it("normalizes task state and result URLs", () => {
|
|
const response = { output: { task_status: "SUCCEEDED", results: [{ url: "https://example.com/result.png" }] } };
|
|
expect(bailianStatus(response)).toBe("succeeded");
|
|
expect(bailianResultUrls(response, "image")).toEqual(["https://example.com/result.png"]);
|
|
});
|
|
|
|
it("extracts Wan 2.7 image URLs from choices content", () => {
|
|
const response = { output: { task_status: "SUCCEEDED", choices: [{ message: { content: [{ type: "image", image: "https://example.com/choice.png" }] } }] } };
|
|
expect(bailianResultUrls(response, "image")).toEqual(["https://example.com/choice.png"]);
|
|
});
|
|
});
|