ai-chatbot/tests/routes/video-canvas-aliyun-analysis.test.ts

100 lines
5.6 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { analyzeAliyunVideo, isAliyunVideoModel, supportsVideoSound } from "@/lib/video-canvas/aliyun-video-analysis";
test("only official Alibaba video-understanding models use direct video input", () => {
expect(isAliyunVideoModel("qwen3.8-max", "alibaba")).toBe(true);
expect(isAliyunVideoModel("qwen3.8-omni-flash", "alibaba")).toBe(true);
expect(isAliyunVideoModel("qwen3-vl-plus", "alibaba")).toBe(false);
expect(isAliyunVideoModel("qwen3.8-max", "custom")).toBe(false);
expect(supportsVideoSound("qwen3.8-max")).toBe(false);
expect(supportsVideoSound("qwen3.8-omni-flash")).toBe(true);
});
test("direct visual analysis sends the full video to the official endpoint", async () => {
const original = globalThis.fetch;
let body: any;
globalThis.fetch = async (input, init) => {
expect(String(input)).toBe("https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions");
body = JSON.parse(String(init?.body));
return Response.json({ choices: [{ message: { content: '{"summary":"已解析真实画面"}' } }] });
};
try {
const result = await analyzeAliyunVideo({ apiKey: "test-key", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", modelId: "qwen3.8-max", prompt: "按时间分析", videoUrl: "https://example.com/test.mp4" });
expect(result).toContain("已解析真实画面");
expect(body.messages[0].content[0]).toMatchObject({ type: "video_url", video_url: { url: "https://example.com/test.mp4" } });
expect(body.stream).toBe(false);
} finally { globalThis.fetch = original; }
});
test("Omni parses streaming video and sound response", async () => {
const original = globalThis.fetch;
globalThis.fetch = async (_input, init) => {
const body = JSON.parse(String(init?.body));
expect(body.model).toBe("qwen3.8-omni-flash");
expect(body.stream).toBe(true);
expect(body.modalities).toEqual(["text"]);
return new Response('data: {"choices":[{"delta":{"content":"有人声"}}]}\n\ndata: [DONE]\n', { status: 200 });
};
try {
expect(await analyzeAliyunVideo({ apiKey: "test-key", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", modelId: "qwen3.8-omni-flash", prompt: "听声音", videoUrl: "https://example.com/test.mp4" })).toBe("有人声");
} finally { globalThis.fetch = original; }
});
test("native highlight analysis uses temporal video input with adjacent shot context", async () => {
const original = globalThis.fetch;
globalThis.fetch = async (_input, init) => {
const body = JSON.parse(String(init?.body));
expect(body.messages[0].content).toEqual([
{ type: "video_url", video_url: { url: "https://example.com/shot.mp4" }, fps: 2 },
{ type: "image_url", image_url: { url: "data:image/jpeg;base64,bmVpZ2hib3I=" } },
{ type: "text", text: "挑选动作高光,并检查衔接" },
]);
return Response.json({ choices: [{ message: { content: '{"startSeconds":2,"matchScore":90}' } }] });
};
try {
expect(await analyzeAliyunVideo({ apiKey: "test-key", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
modelId: "qwen3.8-max", prompt: "挑选动作高光,并检查衔接", videoUrl: "https://example.com/shot.mp4",
contextImages: ["data:image/jpeg;base64,bmVpZ2hib3I="], fps: 2 })).toContain("startSeconds");
} finally { globalThis.fetch = original; }
});
test("rejects private video URLs and unofficial provider endpoints", async () => {
await expect(analyzeAliyunVideo({ apiKey: "test-key", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", modelId: "qwen3.8-max", prompt: "分析", videoUrl: "http://127.0.0.1/test.mp4" })).rejects.toThrow("公网访问");
await expect(analyzeAliyunVideo({ apiKey: "test-key", baseUrl: "https://example.com/v1", modelId: "qwen3.8-max", prompt: "分析", videoUrl: "https://example.com/test.mp4" })).rejects.toThrow("官方地址");
});
test("highlight requests enforce provider JSON output without changing free-text analysis", async () => {
const original = globalThis.fetch;
const bodies: any[] = [];
globalThis.fetch = async (_input, init) => {
bodies.push(JSON.parse(String(init?.body)));
return Response.json({ choices: [{ finish_reason: "stop", message: { content: '{"startSeconds":0}' } }] });
};
const input = { apiKey: "test-key", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
modelId: "qwen3.8-max" as const, prompt: "返回 JSON", videoUrl: "https://example.com/shot.mp4" };
try {
await analyzeAliyunVideo({ ...input, jsonOutput: true });
await analyzeAliyunVideo(input);
expect(bodies[0].response_format).toEqual({ type: "json_object" });
expect(bodies[1].response_format).toBeUndefined();
} finally { globalThis.fetch = original; }
});
for (const modelId of ["qwen3.8-max", "qwen3.8-omni-flash"] as const) {
test(`${modelId} rejects truncated analysis even when the partial text is valid JSON`, async () => {
const original = globalThis.fetch;
let calls = 0;
globalThis.fetch = async () => {
calls++;
return modelId === "qwen3.8-max"
? Response.json({ choices: [{ finish_reason: "length", message: { content: '{"matchScore":99}' } }] })
: new Response('data: {"choices":[{"delta":{"content":"{\"matchScore\":99}"}}]}\n\ndata: {"choices":[{"delta":{},"finish_reason":"length"}]}\n\ndata: [DONE]\n');
};
try {
await expect(analyzeAliyunVideo({ apiKey: "test-key", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
modelId, prompt: "返回 JSON", videoUrl: "https://example.com/shot.mp4", jsonOutput: true })).rejects.toThrow("被截断");
expect(calls).toBe(1);
} finally { globalThis.fetch = original; }
});
}