修复bug

This commit is contained in:
zhishi 2026-03-08 18:23:34 +08:00
parent f3928b8a4c
commit 1c65d00881
28 changed files with 1627 additions and 1292 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "toonflow-app", "name": "toonflow-app",
"version": "1.0.7", "version": "1.0.7-patch2",
"description": "Toonflow 是一款 AI 短剧漫剧工具,能够利用 AI 技术将小说自动转化为剧本,并结合 AI 生成的图片和视频,实现高效的短剧创作。", "description": "Toonflow 是一款 AI 短剧漫剧工具,能够利用 AI 技术将小说自动转化为剧本,并结合 AI 生成的图片和视频,实现高效的短剧创作。",
"author": "HBAI-Ltd <ltlctools@outlook.com>", "author": "HBAI-Ltd <ltlctools@outlook.com>",
"homepage": "https://github.com/HBAI-Ltd/Toonflow-app#readme", "homepage": "https://github.com/HBAI-Ltd/Toonflow-app#readme",
@ -37,7 +37,7 @@
"@ai-sdk/anthropic": "^3.0.35", "@ai-sdk/anthropic": "^3.0.35",
"@ai-sdk/deepseek": "^2.0.17", "@ai-sdk/deepseek": "^2.0.17",
"@ai-sdk/devtools": "^0.0.11", "@ai-sdk/devtools": "^0.0.11",
"@ai-sdk/google": "^3.0.20", "@ai-sdk/google": "^3.0.43",
"@ai-sdk/openai": "^3.0.25", "@ai-sdk/openai": "^3.0.25",
"@ai-sdk/openai-compatible": "^2.0.27", "@ai-sdk/openai-compatible": "^2.0.27",
"@ai-sdk/xai": "^3.0.47", "@ai-sdk/xai": "^3.0.47",

File diff suppressed because one or more lines are too long

View File

@ -175,14 +175,25 @@ async function processImages(images: ImageInfo[]): Promise<Buffer[]> {
let processedBuffers: Buffer[]; let processedBuffers: Buffer[];
if (images.length <= maxImages) { if (images.length <= maxImages) {
console.log("%c Line:178 🥤 images", "background:#ffdd4d", images);
console.log("%c Line:179 🍑", "background:#ed9ec7");
const buffers = await Promise.all(images.map((img) => u.oss.getFile(img.filePath))); const buffers = await Promise.all(images.map((img) => u.oss.getFile(img.filePath)));
console.log("%c Line:179 🧀 buffers", "background:#ffdd4d", buffers);
processedBuffers = await Promise.all(buffers.map((buffer) => compressImage(buffer))); processedBuffers = await Promise.all(buffers.map((buffer) => compressImage(buffer)));
console.log("%c Line:181 🍇 processedBuffers", "background:#e41a6a", processedBuffers);
} else { } else {
const mergeStartIndex = maxImages - 1; const mergeStartIndex = maxImages - 1;
console.log("%c Line:183 🍖", "background:#6ec1c2");
const firstBuffers = await Promise.all(images.slice(0, mergeStartIndex).map((img) => u.oss.getFile(img.filePath))); const firstBuffers = await Promise.all(images.slice(0, mergeStartIndex).map((img) => u.oss.getFile(img.filePath)));
console.log("%c Line:183 🍉 firstBuffers", "background:#42b983", firstBuffers);
const compressedFirstImages = await Promise.all(firstBuffers.map((buffer) => compressImage(buffer))); const compressedFirstImages = await Promise.all(firstBuffers.map((buffer) => compressImage(buffer)));
console.log("%c Line:185 🍺 compressedFirstImages", "background:#42b983", compressedFirstImages);
const imagesToMergeList = images.slice(mergeStartIndex).map((img) => img.filePath); const imagesToMergeList = images.slice(mergeStartIndex).map((img) => img.filePath);
console.log("%c Line:187 🍿 imagesToMergeList", "background:#b03734", imagesToMergeList);
const mergedImage = await mergeImages(imagesToMergeList); const mergedImage = await mergeImages(imagesToMergeList);
console.log("%c Line:189 🍉 mergedImage", "background:#ed9ec7", mergedImage);
processedBuffers = [...compressedFirstImages, mergedImage]; processedBuffers = [...compressedFirstImages, mergedImage];
} }
@ -288,6 +299,7 @@ export default async (cells: { prompt: string }[], scriptId: number, projectId:
// 使用 AI 过滤相关资产 // 使用 AI 过滤相关资产
const filteredImages = await filterRelevantAssets(cellPrompts, resources, allImages); const filteredImages = await filterRelevantAssets(cellPrompts, resources, allImages);
console.log("%c Line:291 🍇 filteredImages", "background:#4fff4B", filteredImages);
const resourcesMapPrompts = buildResourcesMapPrompts(filteredImages); const resourcesMapPrompts = buildResourcesMapPrompts(filteredImages);
console.log("====润色前:", cellPrompts); console.log("====润色前:", cellPrompts);
@ -324,6 +336,7 @@ export default async (cells: { prompt: string }[], scriptId: number, projectId:
}, },
apiConfig, apiConfig,
); );
console.log("%c Line:315 🍊 contentStr", "background:#ffdd4d", contentStr);
const match = contentStr.match(/base64,([A-Za-z0-9+/=]+)/); const match = contentStr.match(/base64,([A-Za-z0-9+/=]+)/);
const base64Str = match?.[1] ?? contentStr; const base64Str = match?.[1] ?? contentStr;

View File

@ -98,7 +98,6 @@ export default class Storyboard {
private log(action: string, detail?: string) { private log(action: string, detail?: string) {
const msg = detail ? `${action}: ${detail}` : action; const msg = detail ? `${action}: ${detail}` : action;
console.log(`\n[${new Date().toLocaleTimeString()}] ${msg}\n`);
} }
// ==================== 剧本相关操作 ==================== // ==================== 剧本相关操作 ====================
@ -242,7 +241,6 @@ ${sections.join("\n\n")}
const skipped: number[] = []; const skipped: number[] = [];
for (const item of shots) { for (const item of shots) {
const exists = this.shots.some((f) => f.segmentId === item.segmentIndex); const exists = this.shots.some((f) => f.segmentId === item.segmentIndex);
if (exists) { if (exists) {
skipped.push(item.segmentIndex); skipped.push(item.segmentIndex);
@ -445,6 +443,7 @@ ${sections.join("\n\n")}
this.scriptId, this.scriptId,
this.projectId, this.projectId,
); );
// 通知前端正在分割图片 // 通知前端正在分割图片
this.emit("shotImageGenerateProgress", { shotId, status: "splitting", message: "正在分割宫格图片为单张镜头图" }); this.emit("shotImageGenerateProgress", { shotId, status: "splitting", message: "正在分割宫格图片为单张镜头图" });
@ -460,8 +459,10 @@ ${sections.join("\n\n")}
for (let i = 0; i < imageBuffers.length; i++) { for (let i = 0; i < imageBuffers.length; i++) {
const fileName = `${this.projectId}/chat/${this.scriptId}/storyboard/shot_${shotId}_take_${i}_${timestamp}.png`; const fileName = `${this.projectId}/chat/${this.scriptId}/storyboard/shot_${shotId}_take_${i}_${timestamp}.png`;
await u.oss.writeFile(fileName, imageBuffers[i]); await u.oss.writeFile(fileName, imageBuffers[i]);
const imageUrl = await u.oss.getFileUrl(fileName); const imageUrl = await u.oss.getFileUrl(fileName);
imagePaths.push(imageUrl); imagePaths.push(imageUrl);
// 每保存一张镜头图片通知进度 // 每保存一张镜头图片通知进度

View File

@ -97,7 +97,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
name: "t_project", name: "t_project",
builder: (table) => { builder: (table) => {
table.integer("id"); table.integer("id");
table.string("projectType"); // table.string("projectType");
table.text("name"); table.text("name");
table.text("intro"); table.text("intro");
table.text("type"); table.text("type");
@ -195,23 +195,23 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
}, },
initData: async (knex) => {}, initData: async (knex) => {},
}, },
{ // {
name: "t_myTasks", // name: "t_myTasks",
builder: (table) => { // builder: (table) => {
table.integer("id").notNullable(); // table.integer("id").notNullable();
table.integer("projectId"); // table.integer("projectId");
table.string("taskClass"); // table.string("taskClass");
table.string("relatedObjects"); // table.string("relatedObjects");
table.string("model"); // table.string("model");
table.text("describe"); // table.text("describe");
table.string("state"); // table.string("state");
table.integer("startTime"); // table.integer("startTime");
table.text("reason"); // table.text("reason");
table.primary(["id"]); // table.primary(["id"]);
table.unique(["id"]); // table.unique(["id"]);
}, // },
initData: async (knex) => {}, // initData: async (knex) => {},
}, // },
{ {
name: "t_artStyle", name: "t_artStyle",
builder: (table) => { builder: (table) => {
@ -668,6 +668,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
{ manufacturer: "grsai", model: "nano-banana-pro", grid: 1, type: "ti2i" }, { manufacturer: "grsai", model: "nano-banana-pro", grid: 1, type: "ti2i" },
{ manufacturer: "grsai", model: "nano-banana", grid: 1, type: "ti2i" }, { manufacturer: "grsai", model: "nano-banana", grid: 1, type: "ti2i" },
{ manufacturer: "grsai", model: "nano-banana-2", grid: 1, type: "ti2i" }, { manufacturer: "grsai", model: "nano-banana-2", grid: 1, type: "ti2i" },
{ manufacturer: "formal", model: "Qwen-Image", grid: 1, type: "ti2i" },
]); ]);
}, },
}, },
@ -686,7 +687,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
initData: async (knex) => { initData: async (knex) => {
await knex("t_videoModel").insert([ await knex("t_videoModel").insert([
{ {
id: 1,
manufacturer: "volcengine", manufacturer: "volcengine",
model: "doubao-seedance-1-5-pro-251215", model: "doubao-seedance-1-5-pro-251215",
durationResolutionMap: JSON.stringify([{ duration: [4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
@ -695,7 +695,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "endFrameOptional"]), type: JSON.stringify(["text", "endFrameOptional"]),
}, },
{ {
id: 2,
manufacturer: "volcengine", manufacturer: "volcengine",
model: "doubao-seedance-1-0-pro-250528", model: "doubao-seedance-1-0-pro-250528",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
@ -704,7 +703,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "endFrameOptional"]), type: JSON.stringify(["text", "endFrameOptional"]),
}, },
{ {
id: 3,
manufacturer: "volcengine", manufacturer: "volcengine",
model: "doubao-seedance-1-0-pro-fast-251015", model: "doubao-seedance-1-0-pro-fast-251015",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
@ -713,7 +711,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "singleImage"]), type: JSON.stringify(["text", "singleImage"]),
}, },
{ {
id: 4,
manufacturer: "volcengine", manufacturer: "volcengine",
model: "doubao-seedance-1-0-lite-i2v-250428", model: "doubao-seedance-1-0-lite-i2v-250428",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
@ -722,7 +719,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["endFrameOptional", "reference"]), type: JSON.stringify(["endFrameOptional", "reference"]),
}, },
{ {
id: 5,
manufacturer: "volcengine", manufacturer: "volcengine",
model: "doubao-seedance-1-0-lite-t2v-250428", model: "doubao-seedance-1-0-lite-t2v-250428",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
@ -731,97 +727,46 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text"]), type: JSON.stringify(["text"]),
}, },
{ {
id: 6,
manufacturer: "kling", manufacturer: "kling",
model: "kling-v1(STD)", model: "kling-v1(STD)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["720p"] }]),
aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["text"]), type: JSON.stringify(["text", "startEndRequired"]),
}, },
{ {
id: 7,
manufacturer: "kling",
model: "kling-v1(STD)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["720p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["startEndRequired"]),
},
{
id: 8,
manufacturer: "kling", manufacturer: "kling",
model: "kling-v1(PRO)", model: "kling-v1(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["text"]), type: JSON.stringify(["text", "startEndRequired"]),
}, },
{ {
id: 9,
manufacturer: "kling",
model: "kling-v1(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["startEndRequired"]),
},
{
id: 10,
manufacturer: "kling", manufacturer: "kling",
model: "kling-v1-6(PRO)", model: "kling-v1-6(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["text"]), type: JSON.stringify(["text", "startEndRequired"]),
}, },
{ {
id: 11,
manufacturer: "kling",
model: "kling-v1-6(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["startEndRequired"]),
},
{
id: 12,
manufacturer: "kling", manufacturer: "kling",
model: "kling-v2-5-turbo(PRO)", model: "kling-v2-5-turbo(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["text"]), type: JSON.stringify(["text", "startEndRequired"]),
}, },
{ {
id: 13,
manufacturer: "kling",
model: "kling-v2-5-turbo(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["startEndRequired"]),
},
{
id: 14,
manufacturer: "kling", manufacturer: "kling",
model: "kling-v2-6(PRO)", model: "kling-v2-6(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]), aspectRatio: JSON.stringify(["16:9", "1:1", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["text"]), type: JSON.stringify(["text", "startEndRequired"]),
}, },
{ {
id: 15,
manufacturer: "kling",
model: "kling-v2-6(PRO)",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["startEndRequired"]),
},
{
id: 16,
manufacturer: "vidu", manufacturer: "vidu",
model: "viduq3-pro", model: "viduq3-pro",
durationResolutionMap: JSON.stringify([ durationResolutionMap: JSON.stringify([
@ -829,21 +774,9 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
]), ]),
aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]), aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]),
audio: 1, audio: 1,
type: JSON.stringify(["text"]), type: JSON.stringify(["text", "singleImage"]),
}, },
{ {
id: 17,
manufacturer: "vidu",
model: "viduq3-pro",
durationResolutionMap: JSON.stringify([
{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], resolution: ["540p", "720p", "1080p"] },
]),
aspectRatio: JSON.stringify([]),
audio: 1,
type: JSON.stringify(["singleImage"]),
},
{
id: 18,
manufacturer: "vidu", manufacturer: "vidu",
model: "viduq2-pro-fast", model: "viduq2-pro-fast",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["720p", "1080p"] }]),
@ -852,61 +785,30 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage", "startEndRequired"]), type: JSON.stringify(["singleImage", "startEndRequired"]),
}, },
{ {
id: 19,
manufacturer: "vidu",
model: "viduq2-pro",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]),
audio: 0,
type: JSON.stringify(["text"]),
},
{
id: 20,
manufacturer: "vidu", manufacturer: "vidu",
model: "viduq2-pro", model: "viduq2-pro",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify([]), aspectRatio: JSON.stringify([]),
audio: 0, audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
}, },
{ {
id: 21,
manufacturer: "vidu",
model: "viduq2-turbo",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]),
audio: 0,
type: JSON.stringify(["text"]),
},
{
id: 22,
manufacturer: "vidu", manufacturer: "vidu",
model: "viduq2-turbo", model: "viduq2-turbo",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify([]), aspectRatio: JSON.stringify([]),
audio: 0, audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
}, },
{ {
id: 23,
manufacturer: "vidu",
model: "viduq1",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16", "1:1"]),
audio: 0,
type: JSON.stringify(["text"]),
},
{
id: 24,
manufacturer: "vidu", manufacturer: "vidu",
model: "viduq1", model: "viduq1",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]), aspectRatio: JSON.stringify([]),
audio: 0, audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
}, },
{ {
id: 25,
manufacturer: "vidu", manufacturer: "vidu",
model: "viduq1-classic", model: "viduq1-classic",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
@ -915,7 +817,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage", "startEndRequired"]), type: JSON.stringify(["singleImage", "startEndRequired"]),
}, },
{ {
id: 26,
manufacturer: "vidu", manufacturer: "vidu",
model: "vidu2.0", model: "vidu2.0",
durationResolutionMap: JSON.stringify([ durationResolutionMap: JSON.stringify([
@ -927,7 +828,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage", "reference", "startEndRequired"]), type: JSON.stringify(["singleImage", "reference", "startEndRequired"]),
}, },
{ {
id: 27,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.6-t2v", model: "wan2.6-t2v",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]),
@ -936,7 +836,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text"]), type: JSON.stringify(["text"]),
}, },
{ {
id: 28,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.5-t2v-preview", model: "wan2.5-t2v-preview",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["480p", "720p", "1080p"] }]),
@ -945,7 +844,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text"]), type: JSON.stringify(["text"]),
}, },
{ {
id: 29,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.2-t2v-plus", model: "wan2.2-t2v-plus",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "1080p"] }]),
@ -954,7 +852,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text"]), type: JSON.stringify(["text"]),
}, },
{ {
id: 30,
manufacturer: "wan", manufacturer: "wan",
model: "wanx2.1-t2v-turbo", model: "wanx2.1-t2v-turbo",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p"] }]),
@ -963,7 +860,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text"]), type: JSON.stringify(["text"]),
}, },
{ {
id: 31,
manufacturer: "wan", manufacturer: "wan",
model: "wanx2.1-t2v-plus", model: "wanx2.1-t2v-plus",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]),
@ -972,7 +868,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text"]), type: JSON.stringify(["text"]),
}, },
{ {
id: 32,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.6-i2v-flash", model: "wan2.6-i2v-flash",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]),
@ -981,7 +876,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 33,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.6-i2v", model: "wan2.6-i2v",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p", "1080p"] }]),
@ -990,7 +884,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 34,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.5-i2v-preview", model: "wan2.5-i2v-preview",
durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 10], resolution: ["480p", "720p", "1080p"] }]),
@ -999,7 +892,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 35,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.2-i2v-flash", model: "wan2.2-i2v-flash",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p", "1080p"] }]),
@ -1008,7 +900,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 36,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.2-i2v-plus", model: "wan2.2-i2v-plus",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "1080p"] }]),
@ -1017,7 +908,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 37,
manufacturer: "wan", manufacturer: "wan",
model: "wanx2.1-i2v-plus", model: "wanx2.1-i2v-plus",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]),
@ -1026,7 +916,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 38,
manufacturer: "wan", manufacturer: "wan",
model: "wanx2.1-i2v-turbo", model: "wanx2.1-i2v-turbo",
durationResolutionMap: JSON.stringify([{ duration: [3, 4, 5], resolution: ["480p", "720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [3, 4, 5], resolution: ["480p", "720p"] }]),
@ -1035,7 +924,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["singleImage"]), type: JSON.stringify(["singleImage"]),
}, },
{ {
id: 39,
manufacturer: "wan", manufacturer: "wan",
model: "wan2.2-kf2v-flash", model: "wan2.2-kf2v-flash",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p", "1080p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["480p", "720p", "1080p"] }]),
@ -1044,7 +932,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["startEndRequired"]), type: JSON.stringify(["startEndRequired"]),
}, },
{ {
id: 40,
manufacturer: "wan", manufacturer: "wan",
model: "wanx2.1-kf2v-plus", model: "wanx2.1-kf2v-plus",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]),
@ -1053,7 +940,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["startEndRequired"]), type: JSON.stringify(["startEndRequired"]),
}, },
{ {
id: 41,
manufacturer: "gemini", manufacturer: "gemini",
model: "veo-3.1-generate-preview", model: "veo-3.1-generate-preview",
durationResolutionMap: JSON.stringify([ durationResolutionMap: JSON.stringify([
@ -1065,7 +951,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "singleImage", "startEndRequired", "endFrameOptional", "reference"]), type: JSON.stringify(["text", "singleImage", "startEndRequired", "endFrameOptional", "reference"]),
}, },
{ {
id: 42,
manufacturer: "gemini", manufacturer: "gemini",
model: "veo-3.1-fast-generate-preview", model: "veo-3.1-fast-generate-preview",
durationResolutionMap: JSON.stringify([ durationResolutionMap: JSON.stringify([
@ -1077,7 +962,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "singleImage", "startEndRequired", "endFrameOptional", "reference"]), type: JSON.stringify(["text", "singleImage", "startEndRequired", "endFrameOptional", "reference"]),
}, },
{ {
id: 43,
manufacturer: "gemini", manufacturer: "gemini",
model: "veo-3.0-generate-preview", model: "veo-3.0-generate-preview",
durationResolutionMap: JSON.stringify([ durationResolutionMap: JSON.stringify([
@ -1089,7 +973,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "singleImage"]), type: JSON.stringify(["text", "singleImage"]),
}, },
{ {
id: 44,
manufacturer: "gemini", manufacturer: "gemini",
model: "veo-3.0-fast-generate-preview", model: "veo-3.0-fast-generate-preview",
durationResolutionMap: JSON.stringify([ durationResolutionMap: JSON.stringify([
@ -1101,7 +984,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "singleImage"]), type: JSON.stringify(["text", "singleImage"]),
}, },
{ {
id: 45,
manufacturer: "gemini", manufacturer: "gemini",
model: "veo-2.0-generate-001", model: "veo-2.0-generate-001",
durationResolutionMap: JSON.stringify([{ duration: [5, 6, 7, 8], resolution: ["720p"] }]), durationResolutionMap: JSON.stringify([{ duration: [5, 6, 7, 8], resolution: ["720p"] }]),
@ -1110,34 +992,30 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["text", "singleImage"]), type: JSON.stringify(["text", "singleImage"]),
}, },
{ {
id: 46,
manufacturer: "runninghub", manufacturer: "runninghub",
model: "sora-2", model: "sora-2",
durationResolutionMap: JSON.stringify([{ duration: [10, 15], resolution: [] }]), durationResolutionMap: JSON.stringify([{ duration: [10, 15], resolution: [] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]), aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["singleImage", "text"]), type: JSON.stringify(["singleImage", "text", "multiImage"]),
}, },
{ {
id: 47,
manufacturer: "runninghub", manufacturer: "runninghub",
model: "sora-2-pro", model: "sora-2-pro",
durationResolutionMap: JSON.stringify([{ duration: [15, 25], resolution: [] }]), durationResolutionMap: JSON.stringify([{ duration: [15, 25], resolution: [] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]), aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["singleImage", "text"]), type: JSON.stringify(["singleImage", "text", "multiImage"]),
}, },
{ {
id: 48,
manufacturer: "grsai", manufacturer: "grsai",
model: "sora-2", model: "sora-2",
durationResolutionMap: JSON.stringify([{ duration: [10, 15], resolution: [] }]), durationResolutionMap: JSON.stringify([{ duration: [10, 15], resolution: [] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]), aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0, audio: 0,
type: JSON.stringify(["singleImage", "text"]), type: JSON.stringify(["singleImage", "text", "multiImage"]),
}, },
{ {
id: 49,
manufacturer: "grsai", manufacturer: "grsai",
model: "veo3.1-pro", model: "veo3.1-pro",
durationResolutionMap: JSON.stringify([]), durationResolutionMap: JSON.stringify([]),
@ -1147,7 +1025,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
}, },
{ {
id: 50,
manufacturer: "grsai", manufacturer: "grsai",
model: "veo3.1-pro-1080p", model: "veo3.1-pro-1080p",
durationResolutionMap: JSON.stringify([]), durationResolutionMap: JSON.stringify([]),
@ -1156,7 +1033,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["startEndRequired", "text"]), type: JSON.stringify(["startEndRequired", "text"]),
}, },
{ {
id: 51,
manufacturer: "grsai", manufacturer: "grsai",
model: "veo3.1-pro-4k", model: "veo3.1-pro-4k",
durationResolutionMap: JSON.stringify([]), durationResolutionMap: JSON.stringify([]),
@ -1165,7 +1041,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["startEndRequired", "text"]), type: JSON.stringify(["startEndRequired", "text"]),
}, },
{ {
id: 52,
manufacturer: "grsai", manufacturer: "grsai",
model: "veo3.1-fast", model: "veo3.1-fast",
durationResolutionMap: JSON.stringify([]), durationResolutionMap: JSON.stringify([]),
@ -1174,7 +1049,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["startEndRequired", "text"]), type: JSON.stringify(["startEndRequired", "text"]),
}, },
{ {
id: 53,
manufacturer: "grsai", manufacturer: "grsai",
model: "veo3.1-fast-1080p", model: "veo3.1-fast-1080p",
durationResolutionMap: JSON.stringify([]), durationResolutionMap: JSON.stringify([]),
@ -1183,7 +1057,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
type: JSON.stringify(["startEndRequired", "text"]), type: JSON.stringify(["startEndRequired", "text"]),
}, },
{ {
id: 54,
manufacturer: "grsai", manufacturer: "grsai",
model: "veo3.1-fast-4k", model: "veo3.1-fast-4k",
durationResolutionMap: JSON.stringify([]), durationResolutionMap: JSON.stringify([]),
@ -1191,6 +1064,153 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
audio: 0, audio: 0,
type: JSON.stringify(["startEndRequired", "text"]), type: JSON.stringify(["startEndRequired", "text"]),
}, },
{
manufacturer: "formal",
model: "Seedance-1.5-Pro",
durationResolutionMap: JSON.stringify([{ duration: [4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 1,
type: JSON.stringify(["endFrameOptional", "text"]),
},
{
manufacturer: "formal",
model: "Seedance-1.0-Pro",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0,
type: JSON.stringify(["text", "endFrameOptional"]),
},
{
manufacturer: "formal",
model: "Seedance-1.0-Pro-Fast",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0,
type: JSON.stringify(["text", "singleImage"]),
},
{
manufacturer: "formal",
model: "Seedance-1.0-Lite-I2V",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["endFrameOptional", "reference"]),
},
{
manufacturer: "formal",
model: "Seedance-1.0-Lite-T2V",
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], resolution: ["480p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0,
type: JSON.stringify(["text"]),
},
{
manufacturer: "formal",
model: "ViduQ3-turbo",
durationResolutionMap: JSON.stringify([
{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], resolution: ["540p", "720p", "1080p"] },
]),
aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]),
audio: 1,
type: JSON.stringify(["text", "singleImage"]),
},
{
manufacturer: "formal",
model: "ViduQ3-pro",
durationResolutionMap: JSON.stringify([
{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], resolution: ["540p", "720p", "1080p"] },
]),
aspectRatio: JSON.stringify(["16:9", "9:16", "3:4", "4:3", "1:1"]),
audio: 1,
type: JSON.stringify(["text", "singleImage"]),
},
{
manufacturer: "formal",
model: "ViduQ2-pro-fast",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["720p", "1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "startEndRequired"]),
},
{
manufacturer: "formal",
model: "ViduQ2-pro",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
},
{
manufacturer: "formal",
model: "ViduQ2-turbo",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
},
{
manufacturer: "formal",
model: "ViduQ2",
durationResolutionMap: JSON.stringify([{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
},
{
manufacturer: "formal",
model: "ViduQ1",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired", "text"]),
},
{
manufacturer: "formal",
model: "ViduQ1-classic",
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "startEndRequired"]),
},
{
manufacturer: "formal",
model: "Vidu2.0",
durationResolutionMap: JSON.stringify([
{ duration: [4], resolution: ["360p", "720p", "1080p"] },
{ duration: [8], resolution: ["720p"] },
]),
aspectRatio: JSON.stringify([]),
audio: 0,
type: JSON.stringify(["singleImage", "reference", "startEndRequired"]),
},
{
manufacturer: "formal",
model: "Hailuo-2.3-I2V",
durationResolutionMap: JSON.stringify([{ duration: [6, 7, 8, 9, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0,
type: JSON.stringify(["endFrameOptional"]),
},
{
manufacturer: "formal",
model: "Hailuo-2.3-Fast",
durationResolutionMap: JSON.stringify([{ duration: [6, 7, 8, 9, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0,
type: JSON.stringify(["endFrameOptional"]),
},
{
manufacturer: "formal",
model: "Hailuo-2.3-T2V",
durationResolutionMap: JSON.stringify([{ duration: [6, 7, 8, 9, 10], resolution: ["1080p"] }]),
aspectRatio: JSON.stringify(["16:9", "9:16"]),
audio: 0,
type: JSON.stringify(["text"]),
},
]); ]);
}, },
}, },

View File

@ -40,7 +40,7 @@ export default router.post(
const { id, type, projectId, base64, prompt, name } = req.body; const { id, type, projectId, base64, prompt, name } = req.body;
//获取风格 //获取风格
const project = await u.db("t_project").where("id", projectId).select("artStyle", "type", "intro").first(); const project = await u.db("t_project").where("id", projectId).select("artStyle", "type", "intro", "videoRatio").first();
if (!project) return res.status(500).send(success({ message: "项目为空" })); if (!project) return res.status(500).send(success({ message: "项目为空" }));
const promptsList = await u const promptsList = await u
@ -137,7 +137,7 @@ export default router.post(
prompt: userPrompt, prompt: userPrompt,
imageBase64: base64 ? [base64] : [], imageBase64: base64 ? [base64] : [],
size: "2K", size: "2K",
aspectRatio: "16:9", aspectRatio: project.videoRatio ?? "16:9",
taskClass: taskClass, taskClass: taskClass,
name: name, name: name,
describe: prompt, describe: prompt,

View File

@ -48,6 +48,7 @@ export default router.post(
); );
res.status(200).send(success(reply)); res.status(200).send(success(reply));
} catch (err) { } catch (err) {
console.log("%c Line:51 🍬 err", "background:#465975", err);
const msg = u.error(err).message; const msg = u.error(err).message;
console.error(msg); console.error(msg);
res.status(500).send(error(msg)); res.status(500).send(error(msg));

View File

@ -23,7 +23,7 @@ export default router.post(
"一张16:9比例的图片完美等分为2x2四宫格布局各区域无缝衔接\n左上宫格一只可爱的猫毛发蓬松眼睛明亮姿态俏皮\n右上宫格一只友善的狗金毛犬表情愉悦摇着尾巴\n左下宫格一头健壮的牛田园背景目光温和皮毛光泽\n右下宫格一匹骏马姿态优雅鬃毛飘逸肌肉健美\n风格要求四个宫格风格统一色彩鲜艳饱和高清画质细节清晰锐利专业插画风格线条干净统一的左上方光源柔和阴影和谐配色卡通/半写实风格,宫格间用白色或浅灰细线分隔", "一张16:9比例的图片完美等分为2x2四宫格布局各区域无缝衔接\n左上宫格一只可爱的猫毛发蓬松眼睛明亮姿态俏皮\n右上宫格一只友善的狗金毛犬表情愉悦摇着尾巴\n左下宫格一头健壮的牛田园背景目光温和皮毛光泽\n右下宫格一匹骏马姿态优雅鬃毛飘逸肌肉健美\n风格要求四个宫格风格统一色彩鲜艳饱和高清画质细节清晰锐利专业插画风格线条干净统一的左上方光源柔和阴影和谐配色卡通/半写实风格,宫格间用白色或浅灰细线分隔",
imageBase64: [], imageBase64: [],
aspectRatio: "9:16", aspectRatio: "9:16",
size: "1K", size: "4K",
taskClass: "测试任务", taskClass: "测试任务",
name: "测试图片生成", name: "测试图片生成",
describe: "测试语言模型生成图片", describe: "测试语言模型生成图片",
@ -38,6 +38,7 @@ export default router.post(
); );
res.status(200).send(success(image)); res.status(200).send(success(image));
} catch (err) { } catch (err) {
console.log("%c Line:41 🍖 err", "background:#fca650", err);
const msg = u.error(err).message; const msg = u.error(err).message;
console.error(msg); console.error(msg);
res.status(500).send(error(msg)); res.status(500).send(error(msg));

View File

@ -9,7 +9,7 @@ const router = express.Router();
export default router.post( export default router.post(
"/", "/",
validateFields({ validateFields({
projectType: z.string(), projectType: z.string().optional(),
name: z.string(), name: z.string(),
intro: z.string(), intro: z.string(),
type: z.string(), type: z.string(),
@ -20,7 +20,6 @@ export default router.post(
const { projectType, name, intro, type, artStyle, videoRatio } = req.body; const { projectType, name, intro, type, artStyle, videoRatio } = req.body;
await u.db("t_project").insert({ await u.db("t_project").insert({
projectType,
name, name,
intro, intro,
type, type,

View File

@ -27,7 +27,7 @@ export default router.post(
await u.db("t_novel").where("projectId", id).delete(); await u.db("t_novel").where("projectId", id).delete();
await u.db("t_storyline").where("projectId", id).delete(); await u.db("t_storyline").where("projectId", id).delete();
await u.db("t_outline").where("projectId", id).delete(); await u.db("t_outline").where("projectId", id).delete();
await u.db("t_myTasks").where("projectId", id).delete(); // await u.db("t_myTasks").where("projectId", id).delete();
await u.db("t_script").where("projectId", id).delete(); await u.db("t_script").where("projectId", id).delete();
await u.db("t_assets").where("projectId", id).delete(); await u.db("t_assets").where("projectId", id).delete();

View File

@ -24,7 +24,6 @@ export default router.post(
type, type,
artStyle, artStyle,
videoRatio, videoRatio,
projectType,
}); });
res.status(200).send(success({ message: "修改成功" })); res.status(200).send(success({ message: "修改成功" }));

View File

@ -99,9 +99,9 @@ const prompt = `
`; `;
async function urlToBase64(imageUrl: string): Promise<string> { async function urlToBase64(imageUrl: string): Promise<string> {
const response = await axios.get(imageUrl, { responseType: "arraybuffer" }); const response = await axios.get(imageUrl, { responseType: "arraybuffer" });
const contentType = response.headers["content-type"] || "image/png"; const contentType = response.headers["content-type"] || "image/jpg";
const base64 = Buffer.from(response.data, "binary").toString("base64"); const base64 = Buffer.from(response.data, "binary").toString("base64");
return `data:${contentType};base64,${base64}`; return `${base64}`;
} }
// 生成单个分镜提示 // 生成单个分镜提示
async function generateSingleVideoPrompt({ async function generateSingleVideoPrompt({
@ -113,6 +113,8 @@ async function generateSingleVideoPrompt({
storyboardPrompt: string; storyboardPrompt: string;
ossPath: string; ossPath: string;
}): Promise<{ content: string; time: number; name: string }> { }): Promise<{ content: string; time: number; name: string }> {
console.log("%c Line:116 🍭 ossPath", "background:#6ec1c2", ossPath);
const messages: any[] = [ const messages: any[] = [
{ {
role: "system", role: "system",
@ -134,8 +136,10 @@ async function generateSingleVideoPrompt({
]; ];
try { try {
console.log("%c Line:140 🍩", "background:#4fff4B");
const apiConfig = await u.getPromptAi("videoPrompt"); const apiConfig = await u.getPromptAi("videoPrompt");
console.log("%c Line:143 🍑", "background:#e41a6a");
const result = await u.ai.text.invoke( const result = await u.ai.text.invoke(
{ {
messages, messages,
@ -159,6 +163,7 @@ async function generateSingleVideoPrompt({
return result; return result;
} catch (err: any) { } catch (err: any) {
console.log("%c Line:167 🥤 err", "background:#465975", err);
console.error("generateSingleVideoPrompt 调用失败:", err?.message || err); console.error("generateSingleVideoPrompt 调用失败:", err?.message || err);
throw new Error(`生成视频提示词失败: ${err?.message || "未知错误"}`); throw new Error(`生成视频提示词失败: ${err?.message || "未知错误"}`);
} }

View File

@ -35,11 +35,18 @@ export default router.post(
return res.status(500).send(error("请先选择图片")); return res.status(500).send(error("请先选择图片"));
} }
const configData = await u.db("t_videoConfig").where("id", configId).first(); const configData = await u.db("t_videoConfig").where("id", configId).first();
if (!configData) { if (!configData) {
return res.status(500).send(error("视频配置不存在")); return res.status(500).send(error("视频配置不存在"));
} }
if (configData.manufacturer == "runninghub") { // 优先使用视频配置中的AI配置ID查询,查不到再使用传入的aiConfigId
let aiConfigData = null;
if (configData.aiConfigId) {
aiConfigData = await u.db("t_config").where("id", configData.aiConfigId).first();
}
if (!aiConfigData || !aiConfigData?.model) {
return res.status(500).send(error("模型不存在"));
}
if (aiConfigData.model?.includes("sora")) {
if (filePath.length > 1) { if (filePath.length > 1) {
const gridUrl = await sharpProcessingImage(filePath, projectId); const gridUrl = await sharpProcessingImage(filePath, projectId);
if (gridUrl) { if (gridUrl) {
@ -49,18 +56,6 @@ export default router.post(
} }
} }
// 优先使用视频配置中的AI配置ID查询,查不到再使用传入的aiConfigId
let aiConfigData = null;
if (configData.aiConfigId) {
aiConfigData = await u.db("t_config").where("id", configData.aiConfigId).first();
}
if (!aiConfigData) {
aiConfigData = await u.db("t_config").where("id", aiConfigId).first();
}
if (!aiConfigData) {
return res.status(500).send(error("模型配置不存在"));
}
// 过滤掉空值 // 过滤掉空值
let fileUrl = filePath.filter((p: string) => p && p.trim() !== ""); let fileUrl = filePath.filter((p: string) => p && p.trim() !== "");
@ -201,7 +196,7 @@ ${prompt}
await u.db("t_video").where("id", videoId).update({ state: -1 }); await u.db("t_video").where("id", videoId).update({ state: -1 });
} }
} catch (err) { } catch (err) {
console.error(`视频生成失败 videoId=${videoId}:`, err); // console.error(`视频生成失败 videoId=${videoId}:`, (err as any).response);
await u await u
.db("t_video") .db("t_video")
.where("id", videoId) .where("id", videoId)

View File

@ -1,4 +1,4 @@
// @db-hash 8171d26b6ac1f411a6ec46a0381b821a // @db-hash a7e02eb0ccc2f0608c1cafc9191f3291
//该文件由脚本自动生成,请勿手动修改 //该文件由脚本自动生成,请勿手动修改
export interface t_aiModelMap { export interface t_aiModelMap {
@ -64,17 +64,6 @@ export interface t_imageModel {
'model'?: string | null; 'model'?: string | null;
'type'?: string | null; 'type'?: string | null;
} }
export interface t_myTasks {
'describe'?: string | null;
'id'?: number;
'model'?: string | null;
'projectId'?: number | null;
'reason'?: string | null;
'relatedObjects'?: string | null;
'startTime'?: number | null;
'state'?: string | null;
'taskClass'?: string | null;
}
export interface t_novel { export interface t_novel {
'chapter'?: string | null; 'chapter'?: string | null;
'chapterData'?: string | null; 'chapterData'?: string | null;
@ -96,7 +85,6 @@ export interface t_project {
'id'?: number | null; 'id'?: number | null;
'intro'?: string | null; 'intro'?: string | null;
'name'?: string | null; 'name'?: string | null;
'projectType'?: string | null;
'type'?: string | null; 'type'?: string | null;
'userId'?: number | null; 'userId'?: number | null;
'videoRatio'?: string | null; 'videoRatio'?: string | null;
@ -197,7 +185,6 @@ export interface DB {
"t_config": t_config; "t_config": t_config;
"t_image": t_image; "t_image": t_image;
"t_imageModel": t_imageModel; "t_imageModel": t_imageModel;
"t_myTasks": t_myTasks;
"t_novel": t_novel; "t_novel": t_novel;
"t_outline": t_outline; "t_outline": t_outline;
"t_project": t_project; "t_project": t_project;

View File

@ -13,7 +13,7 @@ import gemini from "./owned/gemini";
import modelScope from "./owned/modelScope"; import modelScope from "./owned/modelScope";
import grsai from "./owned/grsai"; import grsai from "./owned/grsai";
import { tr } from "zod/locales"; import { tr } from "zod/locales";
import formal from "./owned/formal";
const urlToBase64 = async (url: string): Promise<string> => { const urlToBase64 = async (url: string): Promise<string> => {
const res = await axios.get(url, { responseType: "arraybuffer" }); const res = await axios.get(url, { responseType: "arraybuffer" });
const base64 = Buffer.from(res.data).toString("base64"); const base64 = Buffer.from(res.data).toString("base64");
@ -31,6 +31,7 @@ const modelInstance = {
modelScope, modelScope,
other, other,
grsai, grsai,
formal,
} as const; } as const;
export default async (input: ImageConfig, config: AIConfig) => { export default async (input: ImageConfig, config: AIConfig) => {
@ -46,15 +47,15 @@ export default async (input: ImageConfig, config: AIConfig) => {
// if (!owned) throw new Error("不支持的模型"); // if (!owned) throw new Error("不支持的模型");
// } // }
//添加到任务中心 //添加到任务中心
const [taskId] = await u.db("t_myTasks").insert({ // const [taskId] = await u.db("t_myTasks").insert({
taskClass: input.taskClass, // taskClass: input.taskClass,
relatedObjects: input.name, // relatedObjects: input.name,
model: config?.model ? config.model : "未知模型", // model: config?.model ? config.model : "未知模型",
describe: input.describe ? input.describe : "无", // describe: input.describe ? input.describe : "无",
state: "进行中", // state: "进行中",
startTime: Date.now(), // startTime: Date.now(),
projectId: input.projectId, // projectId: input.projectId,
}); // });
// 补充图片的 base64 内容类型字符串 // 补充图片的 base64 内容类型字符串
if (input.imageBase64 && input.imageBase64.length > 0) { if (input.imageBase64 && input.imageBase64.length > 0) {
input.imageBase64 = input.imageBase64.map((img) => { input.imageBase64 = input.imageBase64.map((img) => {
@ -82,15 +83,15 @@ export default async (input: ImageConfig, config: AIConfig) => {
let imageUrl = await manufacturerFn(input, { model, apiKey, baseURL }); let imageUrl = await manufacturerFn(input, { model, apiKey, baseURL });
if (!input.resType) input.resType = "b64"; if (!input.resType) input.resType = "b64";
if (input.resType === "b64" && imageUrl.startsWith("http")) imageUrl = await urlToBase64(imageUrl); if (input.resType === "b64" && imageUrl.startsWith("http")) imageUrl = await urlToBase64(imageUrl);
await u.db("t_myTasks").where("id", taskId).update({ // await u.db("t_myTasks").where("id", taskId).update({
state: "已完成", // state: "已完成",
}); // });
return imageUrl; return imageUrl;
} catch (error: any) { } catch (error: any) {
await u.db("t_myTasks").where("id", taskId).update({ // await u.db("t_myTasks").where("id", taskId).update({
state: "生成失败", // state: "生成失败",
reason: error.message, // reason: error.message,
}); // });
throw error; throw error;
} }
}; };

View File

@ -0,0 +1,114 @@
import "../type";
import { generateImage, generateText, ModelMessage } from "ai";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { pollTask } from "@/utils/ai/utils";
import u from "@/utils";
import axios from "axios";
function getApiUrl(apiUrl: string) {
if (apiUrl.includes("|")) {
const parts = apiUrl.split("|");
if (parts.length !== 2 || !parts[0].trim() || !parts[1].trim()) {
throw new Error("url 格式错误,请使用 url1|url2 格式");
}
return { requestUrl: parts[0].trim(), queryUrl: parts[1].trim() };
}
throw new Error("请填写正确的url");
}
function template(replaceObj: Record<string, any>, url: string) {
return url.replace(/\{(\w+)\}/g, (match, varName) => {
return replaceObj.hasOwnProperty(varName) ? replaceObj[varName] : match;
});
}
export default async (input: ImageConfig, config: AIConfig): Promise<string> => {
if (!config.model) throw new Error("缺少Model名称");
if (!config.apiKey) throw new Error("缺少API Key");
const defaultBaseURL = "http://192.168.0.74:3000/imagegenerator/task|http://192.168.0.74:3000/imagegenerator/task/{id}";
const { requestUrl, queryUrl } = getApiUrl(config.baseURL! ?? defaultBaseURL);
// 根据 size 配置映射到具体尺寸
const sizeMap: Record<string, Record<string, string>> = {
"1K": {
"16:9": "1664x928",
"9:16": "928x1664",
},
"2K": {
"16:9": "2048x1152",
"9:16": "1152x2048",
},
"4K": {
"16:9": "2048x1152",
"9:16": "1328*1328",
},
};
const modelSizeMap = {
"Qwen-Image": {
"16:9": "1664*928",
"9:16": "928*1664",
},
"Z-Image-Turbo": {
"16:9": "1024*768",
"9:16": "768*1024",
},
};
// 构建完整的提示词
const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt;
let mergedImage = input.imageBase64;
if (mergedImage && mergedImage.length) {
const smallImage = await u.imageTools.mergeImages(mergedImage, "5mb");
mergedImage = [smallImage];
}
const size = modelSizeMap?.[config.model]?.[input.size]?.[input.aspectRatio] ?? modelSizeMap?.[config.model]?.[input.size] ?? "1024*1024";
const taskBody: Record<string, any> = {
model: config.model,
input: {
prompt: fullPrompt,
...(input.imageBase64 && input.imageBase64.length ? { images: input.imageBase64 } : {}),
},
parameters: {
size:"1600*2848",
},
// negative_prompt: "",
};
const apiKey = config.apiKey.replace("Bearer ", "");
try {
const { data } = await axios.post(requestUrl, taskBody, { headers: { Authorization: `Bearer ${apiKey}` } });
console.log("%c Line:70 🥪 data", "background:#ed9ec7", data);
if (data.code != "success") throw new Error(`任务提交失败: ${data || "未知错误"}`);
const taskId = data.data;
return await pollTask(async () => {
const { data: queryData } = await axios.get(template({ id: taskId }, queryUrl), {
headers: { Authorization: `Bearer ${apiKey}` },
});
console.log("%c Line:77 🍧 data", "background:#f5ce50", data);
console.log("%c Line:76 🥑 queryData", "background:#2eafb0", queryData);
const { status, result_url, fail_reason } = queryData.data || {};
if (status === "FAILURE") {
return { completed: false, error: fail_reason ?? "图片生成失败" };
}
if (status === "SUCCESS") {
return { completed: true, url: result_url };
}
return { completed: false };
});
} catch (error: any) {
const msg = u.error(error).message || "图片生成失败";
throw new Error(msg);
}
};
async function urlToBase64(url: string): Promise<string> {
const res = await axios.get(url, { responseType: "arraybuffer" });
const base64 = Buffer.from(res.data).toString("base64");
const mimeType = res.headers["content-type"] || "image/png";
return `data:${mimeType};base64,${base64}`;
}

View File

@ -6,7 +6,7 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
if (!config.model) throw new Error("缺少Model名称"); if (!config.model) throw new Error("缺少Model名称");
if (!config.apiKey) throw new Error("缺少API Key"); if (!config.apiKey) throw new Error("缺少API Key");
if (!input.prompt) throw new Error("缺少提示词"); if (!input.prompt) throw new Error("缺少提示词");
const options: any = {}; const options: any = {};
if (config.apiKey) options.apiKey = config.apiKey; if (config.apiKey) options.apiKey = config.apiKey;
if (config?.baseURL) options.baseURL = config.baseURL; if (config?.baseURL) options.baseURL = config.baseURL;

View File

@ -44,7 +44,7 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
role: "user", role: "user",
content: input.imageBase64.map((i) => ({ content: input.imageBase64.map((i) => ({
type: "image", type: "image",
image: i, image: i.replace(/^data:image\/[^;]+;base64,/, ""),
})), })),
}); });
} else { } else {
@ -111,8 +111,14 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
aspectRatio: input.aspectRatio as "1:1" | "3:4" | "4:3" | "9:16" | "16:9", aspectRatio: input.aspectRatio as "1:1" | "3:4" | "4:3" | "9:16" | "16:9",
size: sizeMap[input.size] ?? "1024x1024", size: sizeMap[input.size] ?? "1024x1024",
}); });
console.log("%c Line:106 🥚 image", "background:#e41a6a", image);
return image.base64; if (image.base64.startsWith("data:image/")) {
return image.base64;
} else {
return `data:image/png;base64,${image.base64}`;
}
} }
}; };

View File

@ -35,7 +35,7 @@ const buildOptions = async (input: AIInput<any>, config: AIConfig = {}) => {
} }
if (!owned) throw new Error("不支持的厂商"); if (!owned) throw new Error("不支持的厂商");
const modelInstance = owned.instance({ apiKey, baseURL: baseURL!, name: "xixixi" }); const modelInstance = owned.instance({ apiKey: apiKey!, baseURL: baseURL! });
const maxStep = input.maxStep ?? (input.tools ? Object.keys(input.tools).length * 5 : undefined); const maxStep = input.maxStep ?? (input.tools ? Object.keys(input.tools).length * 5 : undefined);
const outputBuilders: Record<string, (schema: any) => any> = { const outputBuilders: Record<string, (schema: any) => any> = {
@ -61,7 +61,7 @@ const buildOptions = async (input: AIInput<any>, config: AIConfig = {}) => {
}; };
const output = input.output ? (outputBuilders[owned.responseFormat]?.(input.output) ?? null) : null; const output = input.output ? (outputBuilders[owned.responseFormat]?.(input.output) ?? null) : null;
const chatModelManufacturer = ["volcengine", "other", "openai", "modelScope","grsai"]; const chatModelManufacturer = ["volcengine", "other", "openai", "modelScope", "grsai"];
const modelFn = chatModelManufacturer.includes(owned.manufacturer) ? (modelInstance as OpenAIProvider).chat(model!) : modelInstance(model!); const modelFn = chatModelManufacturer.includes(owned.manufacturer) ? (modelInstance as OpenAIProvider).chat(model!) : modelInstance(model!);
return { return {
@ -86,7 +86,7 @@ const ai = Object.create({}) as {
ai.invoke = async (input: AIInput<any>, config: AIConfig) => { ai.invoke = async (input: AIInput<any>, config: AIConfig) => {
const options = await buildOptions(input, config); const options = await buildOptions(input, config);
const result = await generateText(options.config); const result = await generateText(options.config);
if (options.responseFormat === "object" && input.output) { if (options.responseFormat === "object" && input.output) {
const pattern = /{[^{}]*}|{(?:[^{}]*|{[^{}]*})*}/g; const pattern = /{[^{}]*}|{(?:[^{}]*|{[^{}]*})*}/g;

View File

@ -21,8 +21,7 @@ interface Owned {
| typeof createZhipu | typeof createZhipu
| typeof createQwen | typeof createQwen
| typeof createGoogleGenerativeAI | typeof createGoogleGenerativeAI
| typeof createAnthropic | typeof createAnthropic;
| typeof createOpenAICompatible;
} }
const instanceMap = { const instanceMap = {
deepSeek: createDeepSeek, deepSeek: createDeepSeek,
@ -35,7 +34,8 @@ const instanceMap = {
modelScope: (options: OpenAIProviderSettings) => createOpenAI({ ...options, headers: { ...options?.headers, "X-ModelScope-Async-Mode": "true" } }), modelScope: (options: OpenAIProviderSettings) => createOpenAI({ ...options, headers: { ...options?.headers, "X-ModelScope-Async-Mode": "true" } }),
xai: createXai, xai: createXai,
other: createOpenAI, other: createOpenAI,
grsai:createOpenAI grsai: createOpenAI,
formal: createOpenAI,
}; };
const modelList: Owned[] = [ const modelList: Owned[] = [
// DeepSeek // DeepSeek

View File

@ -12,6 +12,8 @@ import gemini from "./owned/gemini";
import apimart from "./owned/apimart"; import apimart from "./owned/apimart";
import other from "./owned/other"; import other from "./owned/other";
import grsai from "./owned/grsai"; import grsai from "./owned/grsai";
import formal from "./owned/formal";
const modelInstance = { const modelInstance = {
volcengine: volcengine, volcengine: volcengine,
kling: kling, kling: kling,
@ -22,6 +24,7 @@ const modelInstance = {
apimart: apimart, apimart: apimart,
other: other, other: other,
grsai: grsai, grsai: grsai,
formal: formal,
} as const; } as const;
export default async (input: VideoConfig, config?: AIConfig) => { export default async (input: VideoConfig, config?: AIConfig) => {
@ -33,15 +36,15 @@ export default async (input: VideoConfig, config?: AIConfig) => {
// const owned = modelList.find((m) => m.model === model); // const owned = modelList.find((m) => m.model === model);
// if (!owned) throw new Error("不支持的模型"); // if (!owned) throw new Error("不支持的模型");
//添加到任务中心 //添加到任务中心
const [taskId] = await u.db("t_myTasks").insert({ // const [taskId] = await u.db("t_myTasks").insert({
taskClass: input.taskClass, // taskClass: input.taskClass,
relatedObjects: input.name, // relatedObjects: input.name,
model: config?.model ? config.model : "未知模型", // model: config?.model ? config.model : "未知模型",
describe: input.describe ? input.describe : "无", // describe: input.describe ? input.describe : "无",
state: "进行中", // state: "进行中",
startTime: Date.now(), // startTime: Date.now(),
projectId: input.projectId, // projectId: input.projectId,
}); // });
// 补充图片的 base64 内容类型字符串 // 补充图片的 base64 内容类型字符串
if (input.imageBase64 && input.imageBase64.length > 0) { if (input.imageBase64 && input.imageBase64.length > 0) {
input.imageBase64 = input.imageBase64.map((img) => { input.imageBase64 = input.imageBase64.map((img) => {
@ -71,15 +74,15 @@ export default async (input: VideoConfig, config?: AIConfig) => {
try { try {
const response = await axios.get(videoUrl, { responseType: "stream" }); const response = await axios.get(videoUrl, { responseType: "stream" });
await u.oss.writeFile(input.savePath, response.data); await u.oss.writeFile(input.savePath, response.data);
await u.db("t_myTasks").where("id", taskId).update({ // await u.db("t_myTasks").where("id", taskId).update({
state: "已完成", // state: "已完成",
}); // });
return input.savePath; return input.savePath;
} catch (err: any) { } catch (err: any) {
await u.db("t_myTasks").where("id", taskId).update({ // await u.db("t_myTasks").where("id", taskId).update({
state: "生成失败", // state: "生成失败",
reason: err.message, // reason: err.message,
}); // });
return videoUrl; return videoUrl;
} }
} }

View File

@ -0,0 +1,120 @@
import "../type";
import { generateImage, generateText, ModelMessage } from "ai";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { pollTask } from "@/utils/ai/utils";
import u from "@/utils";
import axios from "axios";
function getApiUrl(apiUrl: string) {
if (apiUrl.includes("|")) {
const parts = apiUrl.split("|");
if (parts.length !== 2 || !parts[0].trim() || !parts[1].trim()) {
throw new Error("url 格式错误,请使用 url1|url2 格式");
}
return { requestUrl: parts[0].trim(), queryUrl: parts[1].trim() };
}
throw new Error("请填写正确的url");
}
function template(replaceObj: Record<string, any>, url: string) {
return url.replace(/\{(\w+)\}/g, (match, varName) => {
return replaceObj.hasOwnProperty(varName) ? replaceObj[varName] : match;
});
}
export default async (input: VideoConfig, config: AIConfig): Promise<string> => {
if (!config.model) throw new Error("缺少Model名称");
if (!config.apiKey) throw new Error("缺少API Key");
const defaultBaseURL = "http://192.168.0.74:3000/videogenerator/generate|http://192.168.0.74:3000/videogenerator/generate/{id}";
const { requestUrl, queryUrl } = getApiUrl(config.baseURL! ?? defaultBaseURL);
// 根据 size 配置映射到具体尺寸
const sizeMap: Record<string, Record<string, string>> = {
"480P": {
"16:9": "832*480",
"9:16": "480*332",
},
"720P": {
"16:9": "1280*720",
"9:16": "720*1280",
},
"1080P": {
"16:9": "1920*1080",
"9:16": "1080*1920",
},
};
// 构建完整的提示词
let mergedImage = input.imageBase64;
if (mergedImage && mergedImage.length) {
const smallImage = await u.imageTools.mergeImages(mergedImage, "5mb");
mergedImage = [smallImage];
}
const size = sizeMap[input.resolution]?.[input.aspectRatio] ?? "1280*720";
const imageCount: { type: string; image_url: string }[] = [];
if (input.imageBase64 && input.imageBase64.length) {
input.imageBase64.forEach((i, index) => {
imageCount.push({
type: "image_url",
image_url: { url: i },
role: index === 0 ? "first_frame" : "last_frame",
});
});
}
const taskBody: Record<string, any> = {
model: config.model,
content: [
{
type: "text",
text: input.prompt,
},
...imageCount,
],
// parameters: {
// aspect_ratio: input.aspectRatio,
// size: input.resolution,
// duration: input.duration,
// },
// ...(typeof input.audio === "boolean" ? { generate_audio: input.audio } : {}),
};
console.log("%c Line:62 🥑 taskBody", "background:#ea7e5c", taskBody);
const apiKey = config.apiKey.replace("Bearer ", "");
try {
const { data } = await axios.post(requestUrl, taskBody, { headers: { Authorization: `Bearer ${apiKey}` } });
console.log("%c Line:70 🥪 data", "background:#ed9ec7", data);
console.log("%c Line:84 🍐 data.code != uccess", "background:#e41a6a", data.code != "success");
console.log("%c Line:83 🍇 data.code", "background:#b03734", data.code);
if (data.code != "success") throw new Error(`任务提交失败: ${data || "未知错误"}`);
const taskId = data.data;
return await pollTask(async () => {
const { data: queryData } = await axios.get(template({ id: taskId }, queryUrl), {
headers: { Authorization: `Bearer ${apiKey}` },
});
console.log("%c Line:77 🍧 data", "background:#f5ce50", queryData);
const { status, result_url, fail_reason } = queryData.data || {};
if (status === "FAILURE") {
return { completed: false, error: fail_reason ? fail_reason : "视频生成失败" };
}
if (status === "SUCCESS") {
return { completed: true, url: result_url };
}
return { completed: false };
});
} catch (error: any) {
console.log("%c Line:105 🍖 error", "background:#ed9ec7", error);
const msg = u.error(error).message || "图片生成失败";
console.log("%c Line:107 🌽 u.error(error)", "background:#ea7e5c", u.error(error));
throw new Error(msg);
}
};
async function urlToBase64(url: string): Promise<string> {
const res = await axios.get(url, { responseType: "arraybuffer" });
const base64 = Buffer.from(res.data).toString("base64");
const mimeType = res.headers["content-type"] || "image/png";
return `data:${mimeType};base64,${base64}`;
}

View File

@ -2,58 +2,145 @@ import "../type";
import axios from "axios"; import axios from "axios";
import sharp from "sharp"; import sharp from "sharp";
import FormData from "form-data"; import FormData from "form-data";
import fs from "fs";
import path from "path";
import u from "@/utils";
import { pollTask, validateVideoConfig } from "@/utils/ai/utils"; import { pollTask, validateVideoConfig } from "@/utils/ai/utils";
import { createOpenAI } from "@ai-sdk/openai"; function template(replaceObj: Record<string, any>, url: string) {
import { experimental_generateVideo as generateVideo } from "ai"; return url.replace(/\{(\w+)\}/g, (match, varName) => {
return replaceObj.hasOwnProperty(varName) ? replaceObj[varName] : match;
});
}
export default async (input: VideoConfig, config: AIConfig) => { export default async (input: VideoConfig, config: AIConfig) => {
if (!config.apiKey) throw new Error("缺少API Key"); if (!config.apiKey) throw new Error("缺少API Key");
if (!config.baseURL) throw new Error("缺少baseURL"); if (!config.baseURL) throw new Error("缺少baseURL");
// const { owned, images, hasTextType } = validateVideoConfig(input, config); // const { owned, images, hasTextType } = validateVideoConfig(input, config);
const [requestUrl, queryUrl] = config.baseURL.split("|");
const authorization = `Bearer ${config.apiKey}`; const authorization = `Bearer ${config.apiKey}`;
const urls = config.baseURL.split("|");
const isThreeUrlMode = urls.length === 3;
console.log("%c Line:24 🌭 isThreeUrlMode", "background:#ed9ec7", isThreeUrlMode);
const formData = new FormData(); let requestUrl: string, queryUrl: string, downLoadUrl: string | undefined;
formData.append("model", config.model);
formData.append("prompt", input.prompt); if (isThreeUrlMode) {
formData.append("seconds", String(input.duration)); [requestUrl, queryUrl, downLoadUrl] = urls;
} else {
[requestUrl, queryUrl] = urls;
}
// 根据 aspectRatio 设置 size // 根据 aspectRatio 设置 size
const sizeMap: Record<string, string> = { const sizeMap: Record<string, string> = {
"16:9": "1280x720", "16:9": "1280x720",
"9:16": "720x1280", "9:16": "720x1280",
}; };
formData.append("size", sizeMap[input.aspectRatio] || "1920x1080"); let resData;
let taskId = "";
if (isThreeUrlMode) {
// 三个地址:使用 FormData 方式
const formData = new FormData();
formData.append("model", config.model);
formData.append("prompt", input.prompt);
formData.append("seconds", String(input.duration));
if (input.imageBase64 && input.imageBase64.length) { const size = sizeMap[input.aspectRatio] || "1280x720";
const base64Data = input.imageBase64[0]!.replace(/^data:image\/\w+;base64,/, ""); formData.append("size", size);
const buffer = Buffer.from(base64Data, "base64");
formData.append("input_reference", buffer, { filename: "image.jpg", contentType: "image/jpeg" });
}
const body = { if (input.imageBase64 && input.imageBase64.length) {
model: config.model, const base64Data = input.imageBase64[0]!.replace(/^data:image\/\w+;base64,/, "");
messages: [ const buffer = Buffer.from(base64Data, "base64");
{
role: "user", // 解析尺寸
content: [ const [width, height] = size.split("x").map(Number);
{
type: "text", // 使用 sharp 调整图片尺寸
text: input.prompt, const resizedBuffer = await sharp(buffer).resize(width, height, { fit: "cover" }).jpeg({ quality: 90 }).toBuffer();
},
], formData.append("input_reference", resizedBuffer, { filename: "image.jpg", contentType: "image/jpeg" });
}
const response = await axios.post(requestUrl, formData, {
headers: { Authorization: authorization, ...formData.getHeaders() },
});
taskId = response.data?.task_id || response.data?.id;
resData = response.data;
} else {
// 两个地址:使用 JSON 方式
const requestBody: any = {
model: config.model,
prompt: input.prompt,
aspect_ratio: input.aspectRatio || "16:9",
size: "720p",
};
if (input.imageBase64 && input.imageBase64.length) {
requestBody.images = input.imageBase64;
}
const response = await axios.post(requestUrl, JSON.stringify(requestBody), {
headers: {
Authorization: authorization,
"Content-Type": "application/json",
}, },
], });
}; taskId = response.data.id;
const { data } = await axios.post( resData = response.data;
config.baseURL, }
{ ...body }, console.log("%c Line:87 🥒 taskId", "background:#f5ce50", taskId);
{
headers: { "Content-Type": "application/json", Authorization: authorization },
},
);
console.log("%c Line:49 🥓 data", "background:#ffdd4d", data); if (!taskId) throw new Error(`任务提交失败: ${resData ? JSON.stringify(resData) : "未知错误"}`);
if (data.status === "FAILED") throw new Error(`任务提交失败: ${data.errorMessage || "未知错误"}`); return await pollTask(async () => {
// 构建查询URL两个地址模式时使用URL参数
const finalQueryUrl = isThreeUrlMode ? template({ id: taskId }, queryUrl) : `${queryUrl}?id=${taskId}`;
const { data: queryData } = await axios.get(finalQueryUrl, {
headers: { Authorization: authorization },
});
console.log("%c Line:100 🥑 queryData", "background:#42b983", queryData);
if (queryData.status === "completed") {
// 下载视频,带重试机制
let videoRes;
let retries = 3;
let lastError;
for (let i = 0; i < retries; i++) {
try {
// 构建下载URL
const finalDownloadUrl = isThreeUrlMode && downLoadUrl ? template({ id: taskId }, downLoadUrl) : queryData.video_url || queryData.url; // 从响应中获取视频URL
videoRes = await axios.get(finalDownloadUrl, {
headers: isThreeUrlMode ? { Authorization: authorization } : {},
responseType: "arraybuffer",
timeout: 60 * 1000 * 10, // 60秒超时
});
break; // 成功则跳出循环
} catch (error) {
lastError = error;
console.error(`视频下载失败,第 ${i + 1}/${retries} 次尝试:`, error);
if (i < retries - 1) {
// 等待后重试,使用指数退避
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}
if (!videoRes) {
throw new Error(`视频下载失败,已重试 ${retries} 次: ${lastError}`);
}
// 将视频buffer转换为base64或直接返回buffer
const savePath = input.savePath.endsWith(".mp4") ? input.savePath : path.join(input.savePath, `other_${Date.now()}.mp4`);
await u.oss.writeFile(input.savePath, videoRes.data);
return { completed: true, url: savePath };
}
if (queryData.status === "failed") return { completed: false, error: `任务失败: ${queryData.error || "未知错误"}` };
// if (queryData.status === "QUEUED" || queryData.status === "RUNNING") return { completed: false };
return { completed: false };
});
}; };

View File

@ -0,0 +1 @@
resizedBuffer

View File

@ -67,6 +67,9 @@ export default async (input: VideoConfig, config: AIConfig) => {
Authorization: authorization, Authorization: authorization,
}, },
}); });
console.log("%c Line:65 🍢 response", "background:#3f7cff", response);
taskId = response.data.task_id; taskId = response.data.task_id;
} else { } else {
// 图生视频 // 图生视频
@ -89,6 +92,8 @@ export default async (input: VideoConfig, config: AIConfig) => {
Authorization: authorization, Authorization: authorization,
}, },
}); });
console.log("%c Line:90 🍷 response", "background:#2eafb0", response.data);
taskId = response.data.task_id; taskId = response.data.task_id;
} }
@ -103,6 +108,7 @@ export default async (input: VideoConfig, config: AIConfig) => {
task_ids: [taskId], task_ids: [taskId],
}, },
}); });
console.log("%c Line:113 🧀 response.data", "background:#33a5ff", response.data);
const tasks = response.data.tasks; const tasks = response.data.tasks;
if (!tasks || tasks.length === 0) { if (!tasks || tasks.length === 0) {

View File

@ -46,6 +46,7 @@ export default async (input: VideoConfig, config: AIConfig) => {
Authorization: authorization, Authorization: authorization,
}, },
}); });
console.log("%c Line:44 🍡 createResponse", "background:#2eafb0", createResponse);
const taskId = createResponse.data.id; const taskId = createResponse.data.id;

View File

@ -66,6 +66,9 @@ class OSS {
* @throws OSS * @throws OSS
*/ */
async getFile(userRelPath: string): Promise<Buffer> { async getFile(userRelPath: string): Promise<Buffer> {
console.log("%c Line:69 🥔 userRelPath", "background:#ffdd4d", userRelPath);
console.log("%c Line:72 🥥 this.rootDir", "background:#ea7e5c", this.rootDir);
await this.ensureInit(); await this.ensureInit();
return fs.readFile(resolveSafeLocalPath(userRelPath, this.rootDir)); return fs.readFile(resolveSafeLocalPath(userRelPath, this.rootDir));
} }

136
yarn.lock
View File

@ -8,20 +8,20 @@
integrity sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A== integrity sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==
"@ai-sdk/anthropic@^3.0.35": "@ai-sdk/anthropic@^3.0.35":
version "3.0.50" version "3.0.58"
resolved "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-3.0.50.tgz#5ffdb638ae5418a2bf53d97448346af7ab77e09a" resolved "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-3.0.58.tgz#de49aa3cb7e8a0115eb9d42da05f108d23a90822"
integrity sha512-BkCUgGTp/iZJuuFBF1wv7GGnrEJg7X7hqbaa+/t4HTBt9dZn3e6NFn5NhPUvo2p5SreUeHEl0As0r2uaVn3K9Q== integrity sha512-/53SACgmVukO4bkms4dpxpRlYhW8Ct6QZRe6sj1Pi5H00hYhxIrqfiLbZBGxkdRvjsBQeP/4TVGsXgH5rQeb8Q==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@ai-sdk/deepseek@^2.0.17": "@ai-sdk/deepseek@^2.0.17":
version "2.0.21" version "2.0.24"
resolved "https://registry.npmmirror.com/@ai-sdk/deepseek/-/deepseek-2.0.21.tgz#7a08cb59e25bf5799c3a0461c6f6061a60d22f2e" resolved "https://registry.npmmirror.com/@ai-sdk/deepseek/-/deepseek-2.0.24.tgz#c2e8aa1af5b7e4c7c21b355408ee58f659581163"
integrity sha512-swIljtTiEBt5fTmnHftb20MnM06eBEANJzEYAUvU1m3yQH+HcduHxwVMLUtf9M7RqpTrBrAJxLtHHP5kPIVSCQ== integrity sha512-4vOEekW4TAYVHN0qgiwoUOQZhguGwZBiEw8LDeUmpWBm07QkLRAtxYCaSoMiA4hZZojao5mj6NRGEBW1CnDPtg==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@ai-sdk/devtools@^0.0.11": "@ai-sdk/devtools@^0.0.11":
version "0.0.11" version "0.0.11"
@ -32,52 +32,52 @@
"@hono/node-server" "^1.13.7" "@hono/node-server" "^1.13.7"
hono "^4.6.14" hono "^4.6.14"
"@ai-sdk/gateway@3.0.59": "@ai-sdk/gateway@3.0.66":
version "3.0.59" version "3.0.66"
resolved "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-3.0.59.tgz#1ce7933878656a74f132eb6230caaf22786fd5d3" resolved "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-3.0.66.tgz#64ad8f7b45acaa4c93c53be2bb39e772e49e31b5"
integrity sha512-MbtheWHgEFV/8HL1Z6E3hOAsmP73zZlNFg0F0nJAD0Adnjp4J/plqNK00Y896d+dWTw+r0OXzyov9/2wCFjH0Q== integrity sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@vercel/oidc" "3.1.0" "@vercel/oidc" "3.1.0"
"@ai-sdk/google@^3.0.20": "@ai-sdk/google@^3.0.43":
version "3.0.34" version "3.0.43"
resolved "https://registry.npmmirror.com/@ai-sdk/google/-/google-3.0.34.tgz#5e32b761c9434a0df1046fa8be1c0ffe48f29eac" resolved "https://registry.npmmirror.com/@ai-sdk/google/-/google-3.0.43.tgz#e955d8cb8a598bc75d5aa39d4eaf1cc580dc1ac8"
integrity sha512-1tXUr1W5YACXPgtHYWIU3raqMsayp6cMI8NUT4EEzzZSpvHzkkiNWHEr+bGxEGurSUukfo+pE1RKpLwBFOZtJg== integrity sha512-NGCgP5g8HBxrNdxvF8Dhww+UKfqAkZAmyYBvbu9YLoBkzAmGKDBGhVptN/oXPB5Vm0jggMdoLycZ8JReQM8Zqg==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@ai-sdk/openai-compatible@2.0.31", "@ai-sdk/openai-compatible@^2.0.27": "@ai-sdk/openai-compatible@2.0.35", "@ai-sdk/openai-compatible@^2.0.27":
version "2.0.31" version "2.0.35"
resolved "https://registry.npmmirror.com/@ai-sdk/openai-compatible/-/openai-compatible-2.0.31.tgz#11aca181c215049b1c79b86cf7d58dcf68170da9" resolved "https://registry.npmmirror.com/@ai-sdk/openai-compatible/-/openai-compatible-2.0.35.tgz#ab1edce39a255b1456efdf8e9a8fd4c5566c82fb"
integrity sha512-e78xiImcTe2aCMQoFbVJluQmUV4XgahOmmehAuRPlcwzRv2KtkvuLCXPC9Xcy2u83e8SimVva9k9G8SvZcnaBA== integrity sha512-g3wA57IAQFb+3j4YuFndgkUdXyRETZVvbfAWM+UX7bZSxA3xjes0v3XKgIdKdekPtDGsh4ZX2byHD0gJIMPfiA==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@ai-sdk/openai@^3.0.25": "@ai-sdk/openai@^3.0.25":
version "3.0.37" version "3.0.41"
resolved "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-3.0.37.tgz#8f5361eba21848b37663cbe113c91c666fe9ed58" resolved "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-3.0.41.tgz#22f559888cd4f9bb312c5c576441c3412f442e7b"
integrity sha512-bcYjT3/58i/C0DN3AnrjiGsAb0kYivZLWWUtgTjsBurHSht/LTEy+w3dw5XQe3FmZwX7Z/mUQCiA3wB/5Kf7ow== integrity sha512-IZ42A+FO+vuEQCVNqlnAPYQnnUpUfdJIwn1BEDOBywiEHa23fw7PahxVtlX9zm3/zMvTW4JKPzWyvAgDu+SQ2A==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@ai-sdk/provider-utils@4.0.16", "@ai-sdk/provider-utils@^4.0.0": "@ai-sdk/provider-utils@4.0.19", "@ai-sdk/provider-utils@^4.0.0":
version "4.0.16" version "4.0.19"
resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.16.tgz#24bb427d5ed023ef245f3a7af0e83590c45a74b5" resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.19.tgz#535f87c34f19d5584068c522005780ba59123093"
integrity sha512-kBvDqNkt5EwlzF9FujmNhhtl8FYg3e8FO8P5uneKliqfRThWemzBj+wfYr7ZCymAQhTRnwSSz1/SOqhOAwmx9g== integrity sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==
dependencies: dependencies:
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@standard-schema/spec" "^1.1.0" "@standard-schema/spec" "^1.1.0"
eventsource-parser "^3.0.6" eventsource-parser "^3.0.6"
"@ai-sdk/provider-utils@^3.0.0": "@ai-sdk/provider-utils@^3.0.0":
version "3.0.21" version "3.0.22"
resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-3.0.21.tgz#b98175079d2787f0dda7027d74482f4ae1acfbc8" resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-3.0.22.tgz#fc9824f5a5c290a95c14888de130b02e52020060"
integrity sha512-veuMwTLxsgh31Jjn0SnBABnM1f7ebHhRWcV2ZuY3hP3iJDCZ8VXBaYqcHXoOQDqUXTCas08sKQcHyWK+zl882Q== integrity sha512-fFT1KfUUKktfAFm5mClJhS1oux9tP2qgzmEZVl5UdwltQ1LO/s8hd7znVrgKzivwv1s1FIPza0s9OpJaNB/vHw==
dependencies: dependencies:
"@ai-sdk/provider" "2.0.1" "@ai-sdk/provider" "2.0.1"
"@standard-schema/spec" "^1.0.0" "@standard-schema/spec" "^1.0.0"
@ -105,13 +105,13 @@
json-schema "^0.4.0" json-schema "^0.4.0"
"@ai-sdk/xai@^3.0.47": "@ai-sdk/xai@^3.0.47":
version "3.0.60" version "3.0.67"
resolved "https://registry.npmmirror.com/@ai-sdk/xai/-/xai-3.0.60.tgz#9dd4f427121fb1fa63e531c0beda43a3669758eb" resolved "https://registry.npmmirror.com/@ai-sdk/xai/-/xai-3.0.67.tgz#b49f5c171c6515e38e3cbfafdff746054892c0b0"
integrity sha512-nDOUyzeepmyyoL5+9LxmwXy3BoX9mZy7cv3BjHPN4Xc+SVFVqL7uj/9m1oLRCNmpwfA/9QBq9kuD+J31EfdhMw== integrity sha512-KQQIDc91dUA5IGFMnXBuvPBeraYNTdpDC1qUS+JG8vE+/299//5sZFafI1kKYUu3f3p7LaZrKXYgZ1Ni7QIRbw==
dependencies: dependencies:
"@ai-sdk/openai-compatible" "2.0.31" "@ai-sdk/openai-compatible" "2.0.35"
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@develar/schema-utils@~2.6.5": "@develar/schema-utils@~2.6.5":
version "2.6.5" version "2.6.5"
@ -370,9 +370,9 @@
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@hono/node-server@^1.13.7": "@hono/node-server@^1.13.7":
version "1.19.9" version "1.19.11"
resolved "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.9.tgz#8f37119b1acf283fd3f6035f3d1356fdb97a09ac" resolved "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.11.tgz#dc419f0826dd2504e9fc86ad289d5636a0444e2f"
integrity sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw== integrity sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==
"@img/colour@^1.0.0": "@img/colour@^1.0.0":
version "1.1.0" version "1.1.0"
@ -774,16 +774,16 @@
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
"@types/node@*": "@types/node@*":
version "25.3.3" version "25.3.5"
resolved "https://registry.npmmirror.com/@types/node/-/node-25.3.3.tgz#605862544ee7ffd7a936bcbf0135a14012f1e549" resolved "https://registry.npmmirror.com/@types/node/-/node-25.3.5.tgz#beccb5915561f7a9970ace547ad44d6cdbf39b46"
integrity sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ== integrity sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==
dependencies: dependencies:
undici-types "~7.18.0" undici-types "~7.18.0"
"@types/node@^24.9.0": "@types/node@^24.9.0":
version "24.11.0" version "24.11.2"
resolved "https://registry.npmmirror.com/@types/node/-/node-24.11.0.tgz#34e8f9603ada03fdc36a532faefdb8e1bb3693a0" resolved "https://registry.npmmirror.com/@types/node/-/node-24.11.2.tgz#4d16d5f21256a0506c9d7b58fcda1d4d3dadc530"
integrity sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw== integrity sha512-HTsxyfkxTNxOXBsEdgIOzbMgBjDGPvkTfw0B1m09j1LFPk8u3tSL8SNBRTSc381wXXX/Wp93qPi1kQXwnWuHgA==
dependencies: dependencies:
undici-types "~7.16.0" undici-types "~7.16.0"
@ -801,9 +801,9 @@
integrity sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg== integrity sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==
"@types/qs@*": "@types/qs@*":
version "6.14.0" version "6.15.0"
resolved "https://registry.npmmirror.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5" resolved "https://registry.npmmirror.com/@types/qs/-/qs-6.15.0.tgz#963ab61779843fe910639a50661b48f162bc7f79"
integrity sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ== integrity sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==
"@types/range-parser@*": "@types/range-parser@*":
version "1.2.7" version "1.2.7"
@ -907,13 +907,13 @@ aggregate-error@^3.0.0:
indent-string "^4.0.0" indent-string "^4.0.0"
ai@^6.0.67: ai@^6.0.67:
version "6.0.105" version "6.0.116"
resolved "https://registry.npmmirror.com/ai/-/ai-6.0.105.tgz#85c38f7d67de571435f480cb5c49201a7207599e" resolved "https://registry.npmmirror.com/ai/-/ai-6.0.116.tgz#dc1c3d929453e165fcd3f188d8663617ecf94129"
integrity sha512-rp+exWtZS3J0DDvZIfetpKCIg7D3cCsvBPoFN3I67IDTs9aoBZDbpecoIkmNLT+U9RBkoEial3OGHRvme23HCw== integrity sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==
dependencies: dependencies:
"@ai-sdk/gateway" "3.0.59" "@ai-sdk/gateway" "3.0.66"
"@ai-sdk/provider" "3.0.8" "@ai-sdk/provider" "3.0.8"
"@ai-sdk/provider-utils" "4.0.16" "@ai-sdk/provider-utils" "4.0.19"
"@opentelemetry/api" "1.9.0" "@opentelemetry/api" "1.9.0"
ajv-keywords@^3.4.1: ajv-keywords@^3.4.1:
@ -1796,9 +1796,9 @@ electron-publish@26.8.1:
mime "^2.5.2" mime "^2.5.2"
electron@^40.0.0: electron@^40.0.0:
version "40.6.1" version "40.8.0"
resolved "https://registry.npmmirror.com/electron/-/electron-40.6.1.tgz#f7dca0c028a13144abe2192ec2b6a75ef7418dfc" resolved "https://registry.npmmirror.com/electron/-/electron-40.8.0.tgz#d149210300bf7df95e5d3db4a40d388e12ef7549"
integrity sha512-u9YfoixttdauciHV9Ut9Zf3YipJoU093kR1GSYTTXTAXqhiXI0G1A0NnL/f0O2m2UULCXaXMf2W71PloR6V9pQ== integrity sha512-WoPq0Nr9Yx3g7T6VnJXdwa/rr2+VRyH3a+K+ezfMKBlf6WjxE/LmhMQabKbb6yjm9RbZhJBRcYyoLph421O2mQ==
dependencies: dependencies:
"@electron/get" "^2.0.0" "@electron/get" "^2.0.0"
"@types/node" "^24.9.0" "@types/node" "^24.9.0"
@ -2139,9 +2139,9 @@ fs-extra@^10.0.0, fs-extra@^10.1.0:
universalify "^2.0.0" universalify "^2.0.0"
fs-extra@^11.1.1: fs-extra@^11.1.1:
version "11.3.3" version "11.3.4"
resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.3.tgz#a27da23b72524e81ac6c3815cc0179b8c74c59ee" resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.4.tgz#ab6934eca8bcf6f7f6b82742e33591f86301d6fc"
integrity sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg== integrity sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==
dependencies: dependencies:
graceful-fs "^4.2.0" graceful-fs "^4.2.0"
jsonfile "^6.0.1" jsonfile "^6.0.1"
@ -2399,9 +2399,9 @@ hasown@^2.0.2:
function-bind "^1.1.2" function-bind "^1.1.2"
hono@^4.6.14: hono@^4.6.14:
version "4.12.3" version "4.12.5"
resolved "https://registry.npmmirror.com/hono/-/hono-4.12.3.tgz#fd8dd1127c30956a9d58c1b0c4535d21c1ef3e16" resolved "https://registry.npmmirror.com/hono/-/hono-4.12.5.tgz#8c16209b35040025d3f110d18f3b821de6cab00f"
integrity sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg== integrity sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==
hosted-git-info@^2.1.4: hosted-git-info@^2.1.4:
version "2.8.9" version "2.8.9"
@ -4324,9 +4324,9 @@ tar@^6.0.2, tar@^6.1.11, tar@^6.1.2:
yallist "^4.0.0" yallist "^4.0.0"
tar@^7.4.3, tar@^7.5.6, tar@^7.5.7: tar@^7.4.3, tar@^7.5.6, tar@^7.5.7:
version "7.5.9" version "7.5.10"
resolved "https://registry.npmmirror.com/tar/-/tar-7.5.9.tgz#817ac12a54bc4362c51340875b8985d7dc9724b8" resolved "https://registry.npmmirror.com/tar/-/tar-7.5.10.tgz#2281541123f5507db38bc6eb22619f4bbaef73ad"
integrity sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg== integrity sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==
dependencies: dependencies:
"@isaacs/fs-minipass" "^4.0.0" "@isaacs/fs-minipass" "^4.0.0"
chownr "^3.0.0" chownr "^3.0.0"