完善生图5.0的功能
This commit is contained in:
1 parent
88a4268d40
commit
678d213f40
31 files changed
+3281
-107
No files matched your search
@@ -1,12 +1,14 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { assetPreviewUrl, materialPreviewUrl, storedAssetPreviewUrl } from "@/lib/client/asset-urls";
|
||||
import { assetContentUrl, assetPreviewUrl, materialContentUrl, materialPreviewUrl, storedAssetPreviewUrl } from "@/lib/client/asset-urls";
|
||||
|
||||
describe("private asset browser URLs", () => {
|
||||
it("uses the authenticated inline endpoint for stored assets", () => {
|
||||
expect(assetPreviewUrl({ id: "asset/a b" })).toBe("/api/assets/asset%2Fa%20b/download?inline=1");
|
||||
expect(assetContentUrl({ id: "asset/a b" })).toBe("/api/assets/asset%2Fa%20b/download");
|
||||
expect(materialPreviewUrl({ id: "asset-1", url: "https://private.test/raw.png" })).toBe("/api/assets/asset-1/download?inline=1");
|
||||
expect(materialContentUrl({ id: "asset-1", url: "https://private.test/raw.png" })).toBe("/api/assets/asset-1/download");
|
||||
expect(materialPreviewUrl({ url: "https://external.test/reference.png" })).toBe("https://external.test/reference.png");
|
||||
expect(storedAssetPreviewUrl("https://private.test/legacy.png", [{ id: "asset-legacy", url: "https://private.test/legacy.png" }])).toBe("/api/assets/asset-legacy/download?inline=1");
|
||||
expect(storedAssetPreviewUrl("https://external.test/template.png", [])).toBe("https://external.test/template.png");
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
buildSeedreamInteractivePrompt,
|
||||
buildSeedreamLayerPrompt,
|
||||
missingSeedreamAnnotationTokens,
|
||||
seedreamAnnotationReferences,
|
||||
type SeedreamAnnotation
|
||||
} from "@/lib/seedream/creation";
|
||||
|
||||
const annotations: SeedreamAnnotation[] = [
|
||||
{ id: "box", index: 1, kind: "box", box: { left: 100, top: 200, right: 700, bottom: 800 } },
|
||||
{ id: "point", index: 3, kind: "point", point: { x: 456, y: 321 } }
|
||||
];
|
||||
|
||||
describe("Seedream interactive prompt", () => {
|
||||
it("offers existing canvas annotations as @ input references", () => {
|
||||
expect(seedreamAnnotationReferences([
|
||||
...annotations,
|
||||
{ id: "mark", index: 4, kind: "stroke", points: [{ x: 1, y: 1 }, { x: 2, y: 2 }] }
|
||||
], "标")).toEqual([
|
||||
{ token: "@标注1", label: "框选区域 1", caption: "画布标注" },
|
||||
{ token: "@标注3", label: "点选位置 3", caption: "画布标注" },
|
||||
{ token: "@标记4", label: "蓝色标记 4", caption: "画布标注" }
|
||||
]);
|
||||
});
|
||||
|
||||
it("replaces visible annotation tokens with normalized provider tags", () => {
|
||||
expect(buildSeedreamInteractivePrompt("把 @标注1 改成蓝色", annotations)).toBe(
|
||||
"把 图1<bbox>100 200 700 800</bbox> 改成蓝色\n编辑位置:标注3 图1<point>456 321</point>。"
|
||||
);
|
||||
});
|
||||
|
||||
it("supports cross-image coordinates and visible mark references", () => {
|
||||
const crossImageAnnotations: SeedreamAnnotation[] = [
|
||||
{ id: "subject", index: 1, kind: "box", sourceKey: "image-a", box: { left: 50, top: 60, right: 400, bottom: 500 } },
|
||||
{ id: "target", index: 2, kind: "point", sourceKey: "image-b", point: { x: 720, y: 310 } },
|
||||
{ id: "mark", index: 4, kind: "stroke", sourceKey: "image-b", points: [{ x: 500, y: 500 }, { x: 650, y: 610 }] }
|
||||
];
|
||||
expect(buildSeedreamInteractivePrompt("把 @标注1 移到 @标注2,并清除 @标记4", crossImageAnnotations, ["image-a", "image-b"])).toBe(
|
||||
"把 图1<bbox>50 60 400 500</bbox> 移到 图2<point>720 310</point>,并清除 图2中的蓝色标记区域"
|
||||
);
|
||||
});
|
||||
|
||||
it("detects references to annotations that were removed", () => {
|
||||
expect(missingSeedreamAnnotationTokens("修改 @标注3 和 @标注2", annotations)).toEqual(["@标注2"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Seedream layer prompt", () => {
|
||||
it("supports optional region instructions for layer decomposition", () => {
|
||||
expect(buildSeedreamLayerPrompt("拆出 @标注1 内的标题", annotations)).toBe(
|
||||
"拆出 <bbox>100 200 700 800</bbox> 内的标题\n需拆分区域:<point>456 321</point>。"
|
||||
);
|
||||
});
|
||||
|
||||
it("can describe a blue mark when the prompt is left empty", () => {
|
||||
const marks: SeedreamAnnotation[] = [
|
||||
{ id: "mark", index: 1, kind: "stroke", points: [{ x: 100, y: 100 }, { x: 200, y: 250 }] }
|
||||
];
|
||||
expect(buildSeedreamLayerPrompt("", marks)).toBe("需拆分区域:图片中的蓝色标记区域。");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { downloadSeedreamLayerComposition } from "@/lib/client/seedream-layer-compose";
|
||||
|
||||
describe("Seedream layer composition download", () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("streams private assets through the same-origin download route instead of following the signed preview redirect", async () => {
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
||||
const url = String(input);
|
||||
if (url.includes("inline=1")) throw new TypeError("Failed to fetch");
|
||||
return new Response(new Blob(["image"]), { status: 200 });
|
||||
});
|
||||
const close = vi.fn();
|
||||
const drawImage = vi.fn();
|
||||
const click = vi.fn();
|
||||
const anchor = { href: "", download: "", click, remove: vi.fn() };
|
||||
const canvas = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
getContext: () => ({ clearRect: vi.fn(), drawImage }),
|
||||
toBlob: (callback: BlobCallback) => callback(new Blob(["png"], { type: "image/png" }))
|
||||
};
|
||||
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
vi.stubGlobal("createImageBitmap", vi.fn(async () => ({ width: 100, height: 100, close })));
|
||||
vi.stubGlobal("document", {
|
||||
createElement: (tag: string) => tag === "canvas" ? canvas : anchor,
|
||||
body: { appendChild: vi.fn() }
|
||||
});
|
||||
vi.stubGlobal("window", { setTimeout: (callback: () => void) => { callback(); return 1; } });
|
||||
vi.stubGlobal("URL", { createObjectURL: () => "blob:composition", revokeObjectURL: vi.fn() });
|
||||
|
||||
await expect(downloadSeedreamLayerComposition({
|
||||
items: [{ url: "/api/assets/private-layer/download?inline=1", visible: true, box: [0, 0, 1000, 1000] }],
|
||||
width: 100,
|
||||
height: 100,
|
||||
fileName: "composition.png"
|
||||
})).resolves.toBeUndefined();
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith("/api/assets/private-layer/download", { credentials: "same-origin" });
|
||||
expect(drawImage).toHaveBeenCalledOnce();
|
||||
expect(click).toHaveBeenCalledOnce();
|
||||
expect(close).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user