扩图结果直接归档到七牛存储
This commit is contained in:
parent
6caf1b5cce
commit
d32258e13b
@ -12,6 +12,8 @@ import { expandWithVip98kOutpaint, VIP98K_OUTPAINT_MODEL } from "@/lib/ai/extend
|
||||
import { db } from "@/lib/db";
|
||||
import { generatedImage } from "@/lib/db/schema";
|
||||
import { uploadFile } from "@/lib/storage/service";
|
||||
import { archiveTemporaryImage } from "@/lib/storage/image-archive";
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
type ExtendConfig = {
|
||||
provider?: ExtendProvider;
|
||||
@ -434,7 +436,10 @@ export async function executeExtendJob(
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
let buffer: Buffer;
|
||||
let buffer!: Buffer;
|
||||
let uploadResult: { thumbnail: string; original: string } | undefined;
|
||||
let archivedBytes: number | undefined;
|
||||
let downloadAsset: Awaited<ReturnType<typeof archiveTemporaryImage>>["downloadAsset"];
|
||||
let modelId: string;
|
||||
if (config.provider === "fal") {
|
||||
buffer = await expandWithFalOutpaint({ imageUrl: inputImageUrl, apiKey: config.apiKey!, xScale, yScale });
|
||||
@ -450,21 +455,28 @@ export async function executeExtendJob(
|
||||
} else {
|
||||
const prepared = config.provider === "vip98k" ? inputImageUrl : await normalizeDashscopeExpansionInput(inputImageUrl);
|
||||
const url = await extendImage(prepared, config, xScale, yScale, requestId);
|
||||
const imageResponse = await fetch(url);
|
||||
if (!imageResponse.ok) {
|
||||
throw new ExtendServiceError("下载拓展图片失败", 500, `${imageResponse.status} ${imageResponse.statusText}`);
|
||||
if (config.provider === "vip98k" && !includeBase64) {
|
||||
const archived = await archiveTemporaryImage(url, requestId || randomUUID());
|
||||
uploadResult = { original: archived.url, thumbnail: archived.thumbnailUrl };
|
||||
archivedBytes = archived.bytes;
|
||||
downloadAsset = archived.downloadAsset;
|
||||
} else {
|
||||
const imageResponse = await fetch(url);
|
||||
if (!imageResponse.ok) {
|
||||
throw new ExtendServiceError("下载拓展图片失败", 500, `${imageResponse.status} ${imageResponse.statusText}`);
|
||||
}
|
||||
buffer = Buffer.from(await imageResponse.arrayBuffer());
|
||||
}
|
||||
buffer = Buffer.from(await imageResponse.arrayBuffer());
|
||||
modelId = config.provider === "vip98k" ? "image-expansion" : "extend-1.0";
|
||||
}
|
||||
const imageBase64Result = includeBase64 ? buffer.toString("base64") : undefined;
|
||||
const uploadResult = await uploadBufferPairToS3(buffer, config.provider === "fal" || config.provider === "vip98k" ? "png" : "jpg");
|
||||
uploadResult ??= await uploadBufferPairToS3(buffer, config.provider === "fal" || config.provider === "vip98k" ? "png" : "jpg");
|
||||
console.log("[Extend Service] Result uploaded:", {
|
||||
requestId,
|
||||
includeBase64,
|
||||
inputImageUrl: inputImageUrl.slice(0, 120),
|
||||
modelId,
|
||||
outputBytes: buffer.length,
|
||||
outputBytes: archivedBytes ?? buffer.length,
|
||||
});
|
||||
let mediaAssetId: string | null = null;
|
||||
let generatedImageId: string | null = null;
|
||||
@ -513,6 +525,7 @@ export async function executeExtendJob(
|
||||
xScale,
|
||||
yScale,
|
||||
imageSize: "2K",
|
||||
...(downloadAsset ? { downloadAsset } : {}),
|
||||
},
|
||||
});
|
||||
mediaAssetId = media?.id || null;
|
||||
|
||||
@ -13,6 +13,7 @@ test("native expansion sends the original image and never switches models after
|
||||
"@/lib/db": {},
|
||||
"@/lib/db/schema": {},
|
||||
"@/lib/storage/service": {},
|
||||
"@/lib/storage/image-archive": {},
|
||||
"@/lib/ai/vip98k-runtime": {
|
||||
executeConfiguredVip98kTask: async (params: unknown) => { calls.push(params); throw new Error(message); },
|
||||
},
|
||||
@ -22,6 +23,41 @@ test("native expansion sends the original image and never switches models after
|
||||
}
|
||||
});
|
||||
|
||||
test("native expansion archives the completed image without transferring its bytes through the app", async () => {
|
||||
const calls: string[] = [];
|
||||
const service = serverLoader({
|
||||
"@/lib/db/queries": { getSystemSetting: async () => ({ value: { provider: "vip98k", modelId: "image-expansion" } }) },
|
||||
"@/lib/db": {},
|
||||
"@/lib/db/schema": {},
|
||||
"@/lib/storage/service": {},
|
||||
"@/lib/ai/vip98k-runtime": { executeConfiguredVip98kTask: async () => ({ outputUrls: ["https://relay.test/result.png"] }) },
|
||||
"@/lib/storage/image-archive": { archiveTemporaryImage: async (url: string, id: string) => {
|
||||
calls.push(url, id);
|
||||
return { url: "https://cdn.test/native.png", thumbnailUrl: "https://cdn.test/native.png", bytes: 12375212 };
|
||||
} },
|
||||
})("lib/ai/extend/service.ts");
|
||||
const result = await service.executeExtendJob({ userId: "test", imageUrl: "https://source.test/original.jpg", requestId: "request-1", skipGallerySave: true });
|
||||
expect(calls).toEqual(["https://relay.test/result.png", "request-1"]);
|
||||
expect(result.original_url).toBe("https://cdn.test/native.png");
|
||||
expect(result.image_base64).toBeUndefined();
|
||||
});
|
||||
|
||||
test("native expansion still returns image bytes to callers requesting base64", async () => {
|
||||
const image = await sharp({ create: { width: 12, height: 8, channels: 3, background: "red" } }).png().toBuffer();
|
||||
const service = serverLoader({
|
||||
"@/lib/db/queries": { getSystemSetting: async () => ({ value: { provider: "vip98k", modelId: "image-expansion" } }) },
|
||||
"@/lib/db": {},
|
||||
"@/lib/db/schema": {},
|
||||
"@/lib/storage/service": { uploadFile: async (name: string) => ({ url: `https://cdn.test/${name}` }) },
|
||||
"@/lib/storage/image-archive": { archiveTemporaryImage: () => { throw new Error("Base64 callers need the image bytes"); } },
|
||||
"@/lib/ai/vip98k-runtime": { executeConfiguredVip98kTask: async () => ({ outputUrls: ["https://relay.test/result.png"] }) },
|
||||
fetch: async () => new Response(new Uint8Array(image)),
|
||||
})("lib/ai/extend/service.ts");
|
||||
const result = await service.executeExtendJob({ userId: "test", imageUrl: "https://source.test/original.jpg", includeBase64: true, skipGallerySave: true });
|
||||
expect(result.image_base64).toBe(image.toString("base64"));
|
||||
expect(result.original_url).toMatch(/\.png$/);
|
||||
});
|
||||
|
||||
test.describe("image extension provider configuration", () => {
|
||||
test("uses the most recently updated Alibaba image provider key", () => {
|
||||
expect(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user