Merge branch 'master' of https://github.com/HBAI-Ltd/Toonflow-app
This commit is contained in:
commit
c80abaa694
1411
output.json
Normal file
1411
output.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
@ -176,13 +176,19 @@ async function processImages(images: ImageInfo[]): Promise<Buffer[]> {
|
|||||||
|
|
||||||
if (images.length <= maxImages) {
|
if (images.length <= maxImages) {
|
||||||
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)));
|
||||||
|
|
||||||
processedBuffers = await Promise.all(buffers.map((buffer) => compressImage(buffer)));
|
processedBuffers = await Promise.all(buffers.map((buffer) => compressImage(buffer)));
|
||||||
} else {
|
} else {
|
||||||
const mergeStartIndex = maxImages - 1;
|
const mergeStartIndex = maxImages - 1;
|
||||||
|
|
||||||
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)));
|
||||||
|
|
||||||
const compressedFirstImages = await Promise.all(firstBuffers.map((buffer) => compressImage(buffer)));
|
const compressedFirstImages = await Promise.all(firstBuffers.map((buffer) => compressImage(buffer)));
|
||||||
|
|
||||||
const imagesToMergeList = images.slice(mergeStartIndex).map((img) => img.filePath);
|
const imagesToMergeList = images.slice(mergeStartIndex).map((img) => img.filePath);
|
||||||
|
|
||||||
const mergedImage = await mergeImages(imagesToMergeList);
|
const mergedImage = await mergeImages(imagesToMergeList);
|
||||||
|
|
||||||
processedBuffers = [...compressedFirstImages, mergedImage];
|
processedBuffers = [...compressedFirstImages, mergedImage];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +296,7 @@ export default async (cells: { prompt: string }[], scriptId: number, projectId:
|
|||||||
const filteredImages = await filterRelevantAssets(cellPrompts, resources, allImages);
|
const filteredImages = await filterRelevantAssets(cellPrompts, resources, allImages);
|
||||||
|
|
||||||
const resourcesMapPrompts = buildResourcesMapPrompts(filteredImages);
|
const resourcesMapPrompts = buildResourcesMapPrompts(filteredImages);
|
||||||
console.log("====润色前:", cellPrompts);
|
|
||||||
const promptsData = await generateImagePromptsTool({
|
const promptsData = await generateImagePromptsTool({
|
||||||
prompts: cellPrompts,
|
prompts: cellPrompts,
|
||||||
style: `类型:${projectInfo?.type!},风格:${projectInfo?.artStyle!}`,
|
style: `类型:${projectInfo?.type!},风格:${projectInfo?.artStyle!}`,
|
||||||
@ -305,7 +311,6 @@ export default async (cells: { prompt: string }[], scriptId: number, projectId:
|
|||||||
// 注意:请严格按照提示词内容生成图片,确保人物样貌、艺术风格、色调光影一致。
|
// 注意:请严格按照提示词内容生成图片,确保人物样貌、艺术风格、色调光影一致。
|
||||||
// `;
|
// `;
|
||||||
const prompts = promptsData.prompt;
|
const prompts = promptsData.prompt;
|
||||||
console.log("====润色后:", prompts);
|
|
||||||
|
|
||||||
const processedImages = await processImages(filteredImages);
|
const processedImages = await processImages(filteredImages);
|
||||||
const apiConfig = await u.getPromptAi("storyboardImage");
|
const apiConfig = await u.getPromptAi("storyboardImage");
|
||||||
@ -317,10 +322,13 @@ export default async (cells: { prompt: string }[], scriptId: number, projectId:
|
|||||||
size: "4K",
|
size: "4K",
|
||||||
aspectRatio: projectInfo?.videoRatio ? (projectInfo.videoRatio as any) : "16:9",
|
aspectRatio: projectInfo?.videoRatio ? (projectInfo.videoRatio as any) : "16:9",
|
||||||
imageBase64: processedImages.map((buf) => buf.toString("base64")),
|
imageBase64: processedImages.map((buf) => buf.toString("base64")),
|
||||||
|
taskClass: "分镜图生成",
|
||||||
|
name: `分镜图-${outline?.title || "未知剧集"}`,
|
||||||
|
describe: prompts,
|
||||||
|
projectId,
|
||||||
},
|
},
|
||||||
apiConfig,
|
apiConfig,
|
||||||
);
|
);
|
||||||
|
|
||||||
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;
|
||||||
const buffer = Buffer.from(base64Str, "base64");
|
const buffer = Buffer.from(base64Str, "base64");
|
||||||
|
|||||||
@ -98,14 +98,13 @@ 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`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 剧本相关操作 ====================
|
// ==================== 剧本相关操作 ====================
|
||||||
|
|
||||||
getScript = tool({
|
getScript = tool({
|
||||||
title: "getScript",
|
title: "getScript",
|
||||||
description: "获取剧本内容",
|
description: "用于获取剧本内容",
|
||||||
inputSchema: z.object({}),
|
inputSchema: z.object({}),
|
||||||
execute: async () => {
|
execute: async () => {
|
||||||
this.log("获取剧本", `scriptId: ${this.scriptId}`);
|
this.log("获取剧本", `scriptId: ${this.scriptId}`);
|
||||||
@ -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);
|
||||||
|
|
||||||
// 每保存一张镜头图片通知进度
|
// 每保存一张镜头图片通知进度
|
||||||
@ -661,7 +662,9 @@ ${task}
|
|||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
taskDescription: z.string().describe("具体的任务描述,包含章节范围、修改要求等详细信息"),
|
taskDescription: z.string().describe("具体的任务描述,包含章节范围、修改要求等详细信息"),
|
||||||
}),
|
}),
|
||||||
execute: async ({ taskDescription }) => this.invokeSubAgent(agentType, taskDescription),
|
execute: async ({ taskDescription }) => {
|
||||||
|
return this.invokeSubAgent(agentType, taskDescription);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,7 +674,7 @@ ${task}
|
|||||||
return {
|
return {
|
||||||
segmentAgent: this.createSubAgentTool(
|
segmentAgent: this.createSubAgentTool(
|
||||||
"segmentAgent",
|
"segmentAgent",
|
||||||
"调用片段师。负责根据剧本生成片段,会自行调用 getScript 获取剧本内容,并调用 updateSegments 保存片段结果。",
|
"调用片段师。负责根据剧本生成片段,必须调用 getScript工具 获取剧本内容,并调用 updateSegments 保存片段结果。",
|
||||||
),
|
),
|
||||||
shotAgent: this.createSubAgentTool(
|
shotAgent: this.createSubAgentTool(
|
||||||
"shotAgent",
|
"shotAgent",
|
||||||
|
|||||||
1411
src/lib/artStyle.ts
Normal file
1411
src/lib/artStyle.ts
Normal file
File diff suppressed because it is too large
Load Diff
118
src/lib/fixDB.ts
118
src/lib/fixDB.ts
File diff suppressed because one or more lines are too long
@ -1,5 +1,6 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
import { artStyle } from "./artStyle";
|
||||||
interface TableSchema {
|
interface TableSchema {
|
||||||
name: string;
|
name: string;
|
||||||
builder: (table: Knex.CreateTableBuilder) => void;
|
builder: (table: Knex.CreateTableBuilder) => void;
|
||||||
@ -96,6 +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.text("name");
|
table.text("name");
|
||||||
table.text("intro");
|
table.text("intro");
|
||||||
table.text("type");
|
table.text("type");
|
||||||
@ -160,20 +162,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
|||||||
table.unique(["id"]);
|
table.unique(["id"]);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "t_taskList",
|
|
||||||
builder: (table) => {
|
|
||||||
table.integer("id").notNullable();
|
|
||||||
table.integer("projectName");
|
|
||||||
table.text("name");
|
|
||||||
table.text("prompt");
|
|
||||||
table.text("state");
|
|
||||||
table.text("startTime");
|
|
||||||
table.text("endTime");
|
|
||||||
table.primary(["id"]);
|
|
||||||
table.unique(["id"]);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "t_image",
|
name: "t_image",
|
||||||
builder: (table) => {
|
builder: (table) => {
|
||||||
@ -207,6 +195,36 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
|||||||
},
|
},
|
||||||
initData: async (knex) => {},
|
initData: async (knex) => {},
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// name: "t_myTasks",
|
||||||
|
// builder: (table) => {
|
||||||
|
// table.integer("id").notNullable();
|
||||||
|
// table.integer("projectId");
|
||||||
|
// table.string("taskClass");
|
||||||
|
// table.string("relatedObjects");
|
||||||
|
// table.string("model");
|
||||||
|
// table.text("describe");
|
||||||
|
// table.string("state");
|
||||||
|
// table.integer("startTime");
|
||||||
|
// table.text("reason");
|
||||||
|
// table.primary(["id"]);
|
||||||
|
// table.unique(["id"]);
|
||||||
|
// },
|
||||||
|
// initData: async (knex) => {},
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: "t_artStyle",
|
||||||
|
builder: (table) => {
|
||||||
|
table.integer("id").notNullable();
|
||||||
|
table.string("name");
|
||||||
|
table.text("styles");
|
||||||
|
table.primary(["id"]);
|
||||||
|
table.unique(["id"]);
|
||||||
|
},
|
||||||
|
initData: async (knex) => {
|
||||||
|
await knex("t_artStyle").insert(artStyle.map((item, index) => ({ id: index + 1, name: item.name, styles: JSON.stringify(item.styles) })));
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "t_videoConfig",
|
name: "t_videoConfig",
|
||||||
builder: (table) => {
|
builder: (table) => {
|
||||||
@ -573,54 +591,38 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
|||||||
{ manufacturer: "deepSeek", model: "deepseek-chat", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "deepSeek", model: "deepseek-chat", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
{ manufacturer: "deepSeek", model: "deepseek-reasoner", responseFormat: "schema", image: 0, think: 1, tool: 1 },
|
{ manufacturer: "deepSeek", model: "deepseek-reasoner", responseFormat: "schema", image: 0, think: 1, tool: 1 },
|
||||||
{ manufacturer: "volcengine", model: "doubao-seed-2-0-pro-260215", responseFormat: "object", image: 1, think: 1, tool: 1 },
|
{ manufacturer: "volcengine", model: "doubao-seed-2-0-pro-260215", responseFormat: "object", image: 1, think: 1, tool: 1 },
|
||||||
// { manufacturer: "volcengine", model: "doubao-seed-2-0-lite-260215", responseFormat: "object", image: 1, think: 1, tool: 1 },
|
|
||||||
// { manufacturer: "volcengine", model: "doubao-seed-2-0-mini-260215", responseFormat: "object", image: 1, think: 1, tool: 1 },
|
|
||||||
{ manufacturer: "volcengine", model: "doubao-seed-1-8-251228", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
{ manufacturer: "volcengine", model: "doubao-seed-1-8-251228", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
||||||
// { manufacturer: "volcengine", model: "doubao-seed-1-6-251015", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
|
||||||
// { manufacturer: "volcengine", model: "doubao-seed-1-6-lite-251015", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
|
||||||
// { manufacturer: "volcengine", model: "doubao-seed-1-6-flash-250828", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
|
||||||
{ manufacturer: "zhipu", model: "glm-4.7", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "zhipu", model: "glm-4.7", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
||||||
// { manufacturer: "zhipu", model: "glm-4.7-flashx", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "zhipu", model: "glm-4.6", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "zhipu", model: "glm-4.6", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
||||||
// { manufacturer: "zhipu", model: "glm-4.5-air", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "zhipu", model: "glm-4.5-airx", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "zhipu", model: "glm-4-long", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "zhipu", model: "glm-4-flashx-250414", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "zhipu", model: "glm-4.7-flash", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "zhipu", model: "glm-4.7-flash", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
||||||
// { manufacturer: "zhipu", model: "glm-4.5-flash", responseFormat: "object", image: 0, think: 1, tool: 1 },
|
|
||||||
// { manufacturer: "zhipu", model: "glm-4-flash-250414", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "zhipu", model: "glm-4.6v", responseFormat: "object", image: 1, think: 1, tool: 1 },
|
{ manufacturer: "zhipu", model: "glm-4.6v", responseFormat: "object", image: 1, think: 1, tool: 1 },
|
||||||
{ manufacturer: "qwen", model: "qwen-vl-max", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "qwen", model: "qwen-vl-max", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "qwen", model: "qwen-plus-latest", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "qwen", model: "qwen-plus-latest", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
{ manufacturer: "qwen", model: "qwen-max", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "qwen", model: "qwen-max", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
// { manufacturer: "qwen", model: "qwen2.5-72b-instruct", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "qwen", model: "qwen2.5-14b-instruct-1m", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "qwen", model: "qwen2.5-vl-72b-instruct", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "openai", model: "gpt-4o", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "openai", model: "gpt-4o-mini", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "openai", model: "gpt-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "openai", model: "gpt-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
// { manufacturer: "openai", model: "gpt-5.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "openai", model: "gpt-5.2", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "openai", model: "gpt-5.2", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "gemini", model: "gemini-3-pro-preview", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
{ manufacturer: "gemini", model: "gemini-3-pro-preview", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
||||||
{ manufacturer: "gemini", model: "gemini-2.5-pro", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
{ manufacturer: "gemini", model: "gemini-2.5-pro", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
||||||
// { manufacturer: "gemini", model: "gemini-2.5-flash", responseFormat: "schema", image: 1, think: 1, tool: 1 },
|
|
||||||
// { manufacturer: "gemini", model: "gemini-2.0-flash", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "gemini", model: "gemini-2.0-flash-lite", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "gemini", model: "gemini-1.5-pro", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "gemini", model: "gemini-1.5-flash", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "anthropic", model: "claude-opus-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "anthropic", model: "claude-opus-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "anthropic", model: "claude-haiku-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "anthropic", model: "claude-haiku-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "anthropic", model: "claude-sonnet-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "anthropic", model: "claude-sonnet-4-5", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "anthropic", model: "claude-opus-4-1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "anthropic", model: "claude-opus-4-1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
// { manufacturer: "anthropic", model: "claude-opus-4-0", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "anthropic", model: "claude-sonnet-4-0", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "anthropic", model: "claude-3-7-sonnet-latest", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
// { manufacturer: "anthropic", model: "claude-3-5-haiku-latest", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
|
||||||
{ manufacturer: "xai", model: "grok-3", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "xai", model: "grok-3", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
{ manufacturer: "xai", model: "grok-4", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "xai", model: "grok-4", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
{ manufacturer: "xai", model: "grok-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "xai", model: "grok-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "other", model: "", responseFormat: "object", image: 1, think: 0, tool: 1 },
|
{ manufacturer: "other", model: "", responseFormat: "object", image: 1, think: 0, tool: 1 },
|
||||||
{ manufacturer: "modelScope", model: "deepseek-ai/DeepSeek-V3.2", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
{ manufacturer: "modelScope", model: "deepseek-ai/DeepSeek-V3.2", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
||||||
|
|
||||||
|
// { manufacturer: "formal", model: "gpt-4.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "doubao-seed-2-0-pro-260215", responseFormat: "object", image: 0, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "doubao-seed-1-8-251215", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "gpt-5.2", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "gpt-5.1", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "claude-sonnet-4-6", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "claude-sonnet-4-5-20250929", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "claude-opus-4-5-20251101", responseFormat: "schema", image: 0, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "qwen3.5-plus", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
|
// { manufacturer: "formal", model: "qwen3-max-2026-01-23", responseFormat: "schema", image: 1, think: 0, tool: 1 },
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -638,7 +640,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
|||||||
await knex("t_imageModel").insert([
|
await knex("t_imageModel").insert([
|
||||||
{ manufacturer: "volcengine", model: "doubao-seedream-5-0-260128", grid: 1, type: "ti2i" },
|
{ manufacturer: "volcengine", model: "doubao-seedream-5-0-260128", grid: 1, type: "ti2i" },
|
||||||
{ manufacturer: "volcengine", model: "doubao-seedream-4-5-251128", grid: 0, type: "ti2i" },
|
{ manufacturer: "volcengine", model: "doubao-seedream-4-5-251128", grid: 0, type: "ti2i" },
|
||||||
// { manufacturer: "volcengine", model: "doubao-seedream-4-0-250828", grid: 0, type: "ti2i" },
|
|
||||||
{ manufacturer: "kling", model: "kling-image-o1", grid: 0, type: "ti2i" },
|
{ manufacturer: "kling", model: "kling-image-o1", grid: 0, type: "ti2i" },
|
||||||
{ manufacturer: "gemini", model: "gemini-2.5-flash-image", grid: 1, type: "ti2i" },
|
{ manufacturer: "gemini", model: "gemini-2.5-flash-image", grid: 1, type: "ti2i" },
|
||||||
{ manufacturer: "gemini", model: "gemini-3-pro-image-preview", grid: 1, type: "ti2i" },
|
{ manufacturer: "gemini", model: "gemini-3-pro-image-preview", grid: 1, type: "ti2i" },
|
||||||
@ -650,6 +651,10 @@ 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: "Doubao-Seedream-5.0-Lite", grid: 1, type: "ti2i" },
|
||||||
|
// { manufacturer: "formal", model: "doubao-seedream-4-5-251128", grid: 1, type: "ti2i" },
|
||||||
|
// { manufacturer: "formal", model: "doubao-seedream-4-0-250828", grid: 1, type: "ti2i" },
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -668,7 +673,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"] }]),
|
||||||
@ -677,7 +681,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"] }]),
|
||||||
@ -686,7 +689,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"] }]),
|
||||||
@ -695,7 +697,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"] }]),
|
||||||
@ -704,106 +705,54 @@ 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-2-0-260128",
|
||||||
durationResolutionMap: JSON.stringify([{ duration: [2, 3, 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, 13, 14, 15], resolution: ["720p", "480p"] }]),
|
||||||
aspectRatio: JSON.stringify(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]),
|
aspectRatio: JSON.stringify(["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"]),
|
||||||
audio: 0,
|
audio: 1,
|
||||||
type: JSON.stringify(["text"]),
|
type: JSON.stringify(["endFrameOptional", "multiImage"]),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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([
|
||||||
@ -811,21 +760,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"] }]),
|
||||||
@ -834,70 +771,22 @@ 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",
|
|
||||||
model: "viduq1",
|
|
||||||
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
|
|
||||||
aspectRatio: JSON.stringify([]),
|
|
||||||
audio: 0,
|
|
||||||
type: JSON.stringify(["singleImage", "reference", "startEndRequired"]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 25,
|
|
||||||
manufacturer: "vidu",
|
|
||||||
model: "viduq1-classic",
|
|
||||||
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["1080p"] }]),
|
|
||||||
aspectRatio: JSON.stringify([]),
|
|
||||||
audio: 0,
|
|
||||||
type: JSON.stringify(["singleImage", "startEndRequired"]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 26,
|
|
||||||
manufacturer: "vidu",
|
manufacturer: "vidu",
|
||||||
model: "vidu2.0",
|
model: "vidu2.0",
|
||||||
durationResolutionMap: JSON.stringify([
|
durationResolutionMap: JSON.stringify([
|
||||||
@ -909,7 +798,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"] }]),
|
||||||
@ -918,7 +806,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"] }]),
|
||||||
@ -927,7 +814,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"] }]),
|
||||||
@ -936,7 +822,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"] }]),
|
||||||
@ -945,7 +830,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"] }]),
|
||||||
@ -954,7 +838,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"] }]),
|
||||||
@ -963,7 +846,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"] }]),
|
||||||
@ -972,7 +854,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"] }]),
|
||||||
@ -981,7 +862,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"] }]),
|
||||||
@ -990,7 +870,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"] }]),
|
||||||
@ -999,25 +878,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
|||||||
type: JSON.stringify(["singleImage"]),
|
type: JSON.stringify(["singleImage"]),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 37,
|
|
||||||
manufacturer: "wan",
|
|
||||||
model: "wanx2.1-i2v-plus",
|
|
||||||
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]),
|
|
||||||
aspectRatio: JSON.stringify([]),
|
|
||||||
audio: 0,
|
|
||||||
type: JSON.stringify(["singleImage"]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 38,
|
|
||||||
manufacturer: "wan",
|
|
||||||
model: "wanx2.1-i2v-turbo",
|
|
||||||
durationResolutionMap: JSON.stringify([{ duration: [3, 4, 5], resolution: ["480p", "720p"] }]),
|
|
||||||
aspectRatio: JSON.stringify([]),
|
|
||||||
audio: 0,
|
|
||||||
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"] }]),
|
||||||
@ -1026,16 +886,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
|||||||
type: JSON.stringify(["startEndRequired"]),
|
type: JSON.stringify(["startEndRequired"]),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 40,
|
|
||||||
manufacturer: "wan",
|
|
||||||
model: "wanx2.1-kf2v-plus",
|
|
||||||
durationResolutionMap: JSON.stringify([{ duration: [5], resolution: ["720p"] }]),
|
|
||||||
aspectRatio: JSON.stringify([]),
|
|
||||||
audio: 0,
|
|
||||||
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([
|
||||||
@ -1047,7 +897,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([
|
||||||
@ -1059,7 +908,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([
|
||||||
@ -1071,7 +919,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([
|
||||||
@ -1083,7 +930,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"] }]),
|
||||||
@ -1092,34 +938,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([]),
|
||||||
@ -1129,7 +971,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([]),
|
||||||
@ -1138,7 +979,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([]),
|
||||||
@ -1147,7 +987,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([]),
|
||||||
@ -1156,7 +995,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([]),
|
||||||
@ -1165,7 +1003,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([]),
|
||||||
@ -1173,6 +1010,108 @@ 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-audio",
|
||||||
|
// 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: 0,
|
||||||
|
// type: JSON.stringify(["endFrameOptional"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// manufacturer: "formal",
|
||||||
|
// model: "Seedance-1.5-Pro-NotAudio",
|
||||||
|
// 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: 0,
|
||||||
|
// type: JSON.stringify(["endFrameOptional"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// 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(["endFrameOptional"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// 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(["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(["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"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// 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"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// 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"]),
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// manufacturer: "formal",
|
||||||
|
// model: "Sora-2-I2V",
|
||||||
|
// durationResolutionMap: JSON.stringify([{ duration: [4, 8, 12], resolution: [] }]),
|
||||||
|
// aspectRatio: JSON.stringify([]),
|
||||||
|
// audio: 0,
|
||||||
|
// type: JSON.stringify(["singleImage", "reference"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// manufacturer: "formal",
|
||||||
|
// model: "Wan2.6-I2V-720P",
|
||||||
|
// durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p"] }]),
|
||||||
|
// aspectRatio: JSON.stringify([]),
|
||||||
|
// audio: 1,
|
||||||
|
// type: JSON.stringify(["singleImage"]),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// manufacturer: "formal",
|
||||||
|
// model: "Wan2.6-I2V-720P-1080P",
|
||||||
|
// durationResolutionMap: JSON.stringify([{ duration: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["1080p"] }]),
|
||||||
|
// aspectRatio: JSON.stringify([]),
|
||||||
|
// audio: 1,
|
||||||
|
// type: JSON.stringify(["singleImage"]),
|
||||||
|
// },
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
// @routes-hash c97cf72361299980ea4b0c43549a0de8
|
// @routes-hash d8b95db972bd0ab01243d87d89a004f0
|
||||||
import { Express } from "express";
|
import { Express } from "express";
|
||||||
|
|
||||||
import route1 from "./routes/assets/addAssets";
|
import route1 from "./routes/artStyle/getArtStyle";
|
||||||
import route2 from "./routes/assets/delAssets";
|
import route2 from "./routes/assets/addAssets";
|
||||||
import route3 from "./routes/assets/delAssetsImage";
|
import route3 from "./routes/assets/delAssets";
|
||||||
import route4 from "./routes/assets/generateAssets";
|
import route4 from "./routes/assets/delAssetsImage";
|
||||||
import route5 from "./routes/assets/getAssets";
|
import route5 from "./routes/assets/generateAssets";
|
||||||
import route6 from "./routes/assets/getImage";
|
import route6 from "./routes/assets/getAssets";
|
||||||
import route7 from "./routes/assets/getStoryboard";
|
import route7 from "./routes/assets/getImage";
|
||||||
import route8 from "./routes/assets/polishPrompt";
|
import route8 from "./routes/assets/getScriptList";
|
||||||
import route9 from "./routes/assets/saveAssets";
|
import route9 from "./routes/assets/polishAssetsPrompt";
|
||||||
import route10 from "./routes/assets/updateAssets";
|
import route10 from "./routes/assets/saveAssets";
|
||||||
import route11 from "./routes/index/index";
|
import route11 from "./routes/assets/updateAssets";
|
||||||
import route12 from "./routes/novel/addNovel";
|
import route12 from "./routes/novel/addNovel";
|
||||||
import route13 from "./routes/novel/delNovel";
|
import route13 from "./routes/novel/delNovel";
|
||||||
import route14 from "./routes/novel/getNovel";
|
import route14 from "./routes/novel/getNovel";
|
||||||
@ -55,18 +55,18 @@ import route51 from "./routes/setting/getSetting";
|
|||||||
import route52 from "./routes/setting/getVideoModelDetail";
|
import route52 from "./routes/setting/getVideoModelDetail";
|
||||||
import route53 from "./routes/setting/getVideoModelList";
|
import route53 from "./routes/setting/getVideoModelList";
|
||||||
import route54 from "./routes/setting/updateModel";
|
import route54 from "./routes/setting/updateModel";
|
||||||
import route55 from "./routes/setting/updeteModel";
|
import route55 from "./routes/storyboard/batchSuperScoreImage";
|
||||||
import route56 from "./routes/storyboard/batchSuperScoreImage";
|
import route56 from "./routes/storyboard/chatStoryboard";
|
||||||
import route57 from "./routes/storyboard/chatStoryboard";
|
import route57 from "./routes/storyboard/delStoryboard";
|
||||||
import route58 from "./routes/storyboard/delStoryboard";
|
import route58 from "./routes/storyboard/generateShotImage";
|
||||||
import route59 from "./routes/storyboard/generateShotImage";
|
import route59 from "./routes/storyboard/generateVideoPrompt";
|
||||||
import route60 from "./routes/storyboard/generateStoryboardApi";
|
import route60 from "./routes/storyboard/getStoryboard";
|
||||||
import route61 from "./routes/storyboard/generateVideoPrompt";
|
import route61 from "./routes/storyboard/keepStoryboard";
|
||||||
import route62 from "./routes/storyboard/getStoryboard";
|
import route62 from "./routes/storyboard/saveStoryboard";
|
||||||
import route63 from "./routes/storyboard/keepStoryboard";
|
import route63 from "./routes/storyboard/storyboardImageEdit";
|
||||||
import route64 from "./routes/storyboard/saveStoryboard";
|
import route64 from "./routes/storyboard/uploadImage";
|
||||||
import route65 from "./routes/storyboard/uploadImage";
|
import route65 from "./routes/task/getMyTaskApi";
|
||||||
import route66 from "./routes/task/getTaskApi";
|
import route66 from "./routes/task/getTaskCategories";
|
||||||
import route67 from "./routes/task/taskDetails";
|
import route67 from "./routes/task/taskDetails";
|
||||||
import route68 from "./routes/user/getUser";
|
import route68 from "./routes/user/getUser";
|
||||||
import route69 from "./routes/user/saveUser";
|
import route69 from "./routes/user/saveUser";
|
||||||
@ -85,17 +85,17 @@ import route81 from "./routes/video/saveVideo";
|
|||||||
import route82 from "./routes/video/upDateVideoConfig";
|
import route82 from "./routes/video/upDateVideoConfig";
|
||||||
|
|
||||||
export default async (app: Express) => {
|
export default async (app: Express) => {
|
||||||
app.use("/assets/addAssets", route1);
|
app.use("/artStyle/getArtStyle", route1);
|
||||||
app.use("/assets/delAssets", route2);
|
app.use("/assets/addAssets", route2);
|
||||||
app.use("/assets/delAssetsImage", route3);
|
app.use("/assets/delAssets", route3);
|
||||||
app.use("/assets/generateAssets", route4);
|
app.use("/assets/delAssetsImage", route4);
|
||||||
app.use("/assets/getAssets", route5);
|
app.use("/assets/generateAssets", route5);
|
||||||
app.use("/assets/getImage", route6);
|
app.use("/assets/getAssets", route6);
|
||||||
app.use("/assets/getStoryboard", route7);
|
app.use("/assets/getImage", route7);
|
||||||
app.use("/assets/polishPrompt", route8);
|
app.use("/assets/getScriptList", route8);
|
||||||
app.use("/assets/saveAssets", route9);
|
app.use("/assets/polishAssetsPrompt", route9);
|
||||||
app.use("/assets/updateAssets", route10);
|
app.use("/assets/saveAssets", route10);
|
||||||
app.use("/index", route11);
|
app.use("/assets/updateAssets", route11);
|
||||||
app.use("/novel/addNovel", route12);
|
app.use("/novel/addNovel", route12);
|
||||||
app.use("/novel/delNovel", route13);
|
app.use("/novel/delNovel", route13);
|
||||||
app.use("/novel/getNovel", route14);
|
app.use("/novel/getNovel", route14);
|
||||||
@ -139,18 +139,18 @@ export default async (app: Express) => {
|
|||||||
app.use("/setting/getVideoModelDetail", route52);
|
app.use("/setting/getVideoModelDetail", route52);
|
||||||
app.use("/setting/getVideoModelList", route53);
|
app.use("/setting/getVideoModelList", route53);
|
||||||
app.use("/setting/updateModel", route54);
|
app.use("/setting/updateModel", route54);
|
||||||
app.use("/setting/updeteModel", route55);
|
app.use("/storyboard/batchSuperScoreImage", route55);
|
||||||
app.use("/storyboard/batchSuperScoreImage", route56);
|
app.use("/storyboard/chatStoryboard", route56);
|
||||||
app.use("/storyboard/chatStoryboard", route57);
|
app.use("/storyboard/delStoryboard", route57);
|
||||||
app.use("/storyboard/delStoryboard", route58);
|
app.use("/storyboard/generateShotImage", route58);
|
||||||
app.use("/storyboard/generateShotImage", route59);
|
app.use("/storyboard/generateVideoPrompt", route59);
|
||||||
app.use("/storyboard/generateStoryboardApi", route60);
|
app.use("/storyboard/getStoryboard", route60);
|
||||||
app.use("/storyboard/generateVideoPrompt", route61);
|
app.use("/storyboard/keepStoryboard", route61);
|
||||||
app.use("/storyboard/getStoryboard", route62);
|
app.use("/storyboard/saveStoryboard", route62);
|
||||||
app.use("/storyboard/keepStoryboard", route63);
|
app.use("/storyboard/storyboardImageEdit", route63);
|
||||||
app.use("/storyboard/saveStoryboard", route64);
|
app.use("/storyboard/uploadImage", route64);
|
||||||
app.use("/storyboard/uploadImage", route65);
|
app.use("/task/getMyTaskApi", route65);
|
||||||
app.use("/task/getTaskApi", route66);
|
app.use("/task/getTaskCategories", route66);
|
||||||
app.use("/task/taskDetails", route67);
|
app.use("/task/taskDetails", route67);
|
||||||
app.use("/user/getUser", route68);
|
app.use("/user/getUser", route68);
|
||||||
app.use("/user/saveUser", route69);
|
app.use("/user/saveUser", route69);
|
||||||
|
|||||||
19
src/routes/artStyle/getArtStyle.ts
Normal file
19
src/routes/artStyle/getArtStyle.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import express from "express";
|
||||||
|
import u from "@/utils";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { success } from "@/lib/responseFormat";
|
||||||
|
import { validateFields } from "@/middleware/middleware";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
export default router.post(
|
||||||
|
"/",
|
||||||
|
validateFields({
|
||||||
|
name: z.string(),
|
||||||
|
}),
|
||||||
|
async (req, res) => {
|
||||||
|
const { name } = req.body;
|
||||||
|
const data = await u.db("t_artStyle").where("name", name).select("styles").first();
|
||||||
|
const styles = data?.styles ? JSON.parse(data.styles) : [];
|
||||||
|
res.status(200).send(success(styles));
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -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
|
||||||
@ -123,8 +123,13 @@ export default router.post(
|
|||||||
state: "生成中",
|
state: "生成中",
|
||||||
assetsId: id,
|
assetsId: id,
|
||||||
});
|
});
|
||||||
const apiConfig = await u.getPromptAi("assetsImage");
|
let taskClass = "";
|
||||||
|
if (type == "role") taskClass = "角色图生成";
|
||||||
|
if (type == "scene") taskClass = "场景图生成";
|
||||||
|
if (type == "props") taskClass = "道具图生成";
|
||||||
|
if (type == "storyboard") taskClass = "分镜图生成";
|
||||||
|
|
||||||
|
const apiConfig = await u.getPromptAi("assetsImage");
|
||||||
try {
|
try {
|
||||||
const contentStr = await u.ai.image(
|
const contentStr = await u.ai.image(
|
||||||
{
|
{
|
||||||
@ -132,7 +137,11 @@ 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,
|
||||||
|
name: name,
|
||||||
|
describe: prompt,
|
||||||
|
projectId: projectId,
|
||||||
},
|
},
|
||||||
apiConfig,
|
apiConfig,
|
||||||
);
|
);
|
||||||
@ -171,7 +180,6 @@ export default router.post(
|
|||||||
filePath: imagePath,
|
filePath: imagePath,
|
||||||
type: insertType,
|
type: insertType,
|
||||||
});
|
});
|
||||||
|
|
||||||
const path = await u.oss.getFileUrl(imagePath!);
|
const path = await u.oss.getFileUrl(imagePath!);
|
||||||
|
|
||||||
// const state = await u.db("t_assets").where("id", id).select("state").first();
|
// const state = await u.db("t_assets").where("id", id).select("state").first();
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import express from "express";
|
|
||||||
import u from "@/utils";
|
|
||||||
const router = express.Router();
|
|
||||||
import { z } from "zod";
|
|
||||||
import { error } from "@/lib/responseFormat";
|
|
||||||
|
|
||||||
export default router.get("/", async (req, res, next) => {
|
|
||||||
const id = 14;
|
|
||||||
const targetOutlineData = await u.db("t_outline").where("id", id).select("data").first();
|
|
||||||
if (!targetOutlineData) return res.status(400).send(error("大纲不存在"));
|
|
||||||
//筛选出改大纲特有的资产
|
|
||||||
const allOutlineDataList = await u.db("t_outline").where("projectId", 8).andWhere("id", "!=", id).select("data");
|
|
||||||
//找出目标ID大纲特有的资产名称
|
|
||||||
const allOutlineData = allOutlineDataList
|
|
||||||
.map((item) => {
|
|
||||||
const data = JSON.parse(item?.data || "[]");
|
|
||||||
return [...data.characters, ...data.props, ...data.scenes].map((item: any) => item.name);
|
|
||||||
})
|
|
||||||
.flat();
|
|
||||||
|
|
||||||
const targetOutLineNames = JSON.parse(targetOutlineData?.data || "[]");
|
|
||||||
const targetNames = [...targetOutLineNames.characters, ...targetOutLineNames.props, ...targetOutLineNames.scenes].map((item: any) => item.name);
|
|
||||||
|
|
||||||
const diffAssetsNames = targetNames.filter((item) => !allOutlineData.includes(item));
|
|
||||||
|
|
||||||
res.status(200).send(123);
|
|
||||||
});
|
|
||||||
@ -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));
|
||||||
|
|||||||
@ -22,8 +22,12 @@ export default router.post(
|
|||||||
prompt:
|
prompt:
|
||||||
"一张16:9比例的图片,完美等分为2x2四宫格布局,各区域无缝衔接:\n左上宫格:一只可爱的猫,毛发蓬松,眼睛明亮,姿态俏皮\n右上宫格:一只友善的狗,金毛犬,表情愉悦,摇着尾巴\n左下宫格:一头健壮的牛,田园背景,目光温和,皮毛光泽\n右下宫格:一匹骏马,姿态优雅,鬃毛飘逸,肌肉健美\n风格要求:四个宫格风格统一,色彩鲜艳饱和,高清画质,细节清晰锐利,专业插画风格,线条干净,统一的左上方光源,柔和阴影,和谐配色,卡通/半写实风格,宫格间用白色或浅灰细线分隔",
|
"一张16:9比例的图片,完美等分为2x2四宫格布局,各区域无缝衔接:\n左上宫格:一只可爱的猫,毛发蓬松,眼睛明亮,姿态俏皮\n右上宫格:一只友善的狗,金毛犬,表情愉悦,摇着尾巴\n左下宫格:一头健壮的牛,田园背景,目光温和,皮毛光泽\n右下宫格:一匹骏马,姿态优雅,鬃毛飘逸,肌肉健美\n风格要求:四个宫格风格统一,色彩鲜艳饱和,高清画质,细节清晰锐利,专业插画风格,线条干净,统一的左上方光源,柔和阴影,和谐配色,卡通/半写实风格,宫格间用白色或浅灰细线分隔",
|
||||||
imageBase64: [],
|
imageBase64: [],
|
||||||
aspectRatio: "16:9",
|
aspectRatio: "9:16",
|
||||||
size: "1K",
|
size: "4K",
|
||||||
|
taskClass: "测试任务",
|
||||||
|
name: "测试图片生成",
|
||||||
|
describe: "测试语言模型生成图片",
|
||||||
|
projectId: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: modelName,
|
model: modelName,
|
||||||
@ -34,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));
|
||||||
|
|||||||
@ -28,6 +28,10 @@ export default router.post(
|
|||||||
aspectRatio: "16:9",
|
aspectRatio: "16:9",
|
||||||
audio: false,
|
audio: false,
|
||||||
mode: "single",
|
mode: "single",
|
||||||
|
taskClass: "测试视频生成",
|
||||||
|
name: "测试视频生成",
|
||||||
|
describe: "测试视频生成",
|
||||||
|
projectId: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: modelName,
|
model: modelName,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { error, success } from "@/lib/responseFormat";
|
|||||||
import { validateFields } from "@/middleware/middleware";
|
import { validateFields } from "@/middleware/middleware";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// 删除大纲
|
// 获取历史消息记录
|
||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { error, success } from "@/lib/responseFormat";
|
|||||||
import { validateFields } from "@/middleware/middleware";
|
import { validateFields } from "@/middleware/middleware";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// 删除大纲
|
// 保存历史消息记录
|
||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
|
|||||||
@ -9,6 +9,7 @@ const router = express.Router();
|
|||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
|
projectType: z.string().optional(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
intro: z.string(),
|
intro: z.string(),
|
||||||
type: z.string(),
|
type: z.string(),
|
||||||
@ -16,7 +17,7 @@ export default router.post(
|
|||||||
videoRatio: z.string(),
|
videoRatio: z.string(),
|
||||||
}),
|
}),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { 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({
|
||||||
name,
|
name,
|
||||||
@ -29,5 +30,5 @@ export default router.post(
|
|||||||
});
|
});
|
||||||
|
|
||||||
res.status(200).send(success({ message: "新增项目成功" }));
|
res.status(200).send(success({ message: "新增项目成功" }));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -27,6 +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_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();
|
||||||
@ -55,5 +56,5 @@ export default router.post(
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send(success({ message: "删除项目成功" }));
|
res.status(200).send(success({ message: "删除项目成功" }));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -14,9 +14,10 @@ export default router.post(
|
|||||||
type: z.string().optional().nullable(),
|
type: z.string().optional().nullable(),
|
||||||
artStyle: z.string().optional().nullable(),
|
artStyle: z.string().optional().nullable(),
|
||||||
videoRatio: z.string().optional().nullable(),
|
videoRatio: z.string().optional().nullable(),
|
||||||
|
projectType: z.string().optional().nullable(),
|
||||||
}),
|
}),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { id, intro, type, artStyle, videoRatio } = req.body;
|
const { id, intro, type, artStyle, videoRatio, projectType } = req.body;
|
||||||
|
|
||||||
await u.db("t_project").where("id", id).update({
|
await u.db("t_project").where("id", id).update({
|
||||||
intro,
|
intro,
|
||||||
@ -26,5 +27,5 @@ export default router.post(
|
|||||||
});
|
});
|
||||||
|
|
||||||
res.status(200).send(success({ message: "修改成功" }));
|
res.status(200).send(success({ message: "修改成功" }));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -21,13 +21,22 @@ export default router.post(
|
|||||||
.db(sqlTableMap[type as "image" | "text" | "video"])
|
.db(sqlTableMap[type as "image" | "text" | "video"])
|
||||||
.whereNot("manufacturer", "other")
|
.whereNot("manufacturer", "other")
|
||||||
.select("id", "manufacturer", "model");
|
.select("id", "manufacturer", "model");
|
||||||
|
|
||||||
const result: Record<string, any[]> = {};
|
const result: Record<string, any[]> = {};
|
||||||
|
const modelCache: Record<string, Set<string>> = {};
|
||||||
|
|
||||||
for (const row of modelLists) {
|
for (const row of modelLists) {
|
||||||
if (!result[row.manufacturer]) {
|
if (!result[row.manufacturer]) {
|
||||||
result[row.manufacturer] = [];
|
result[row.manufacturer] = [];
|
||||||
|
modelCache[row.manufacturer] = new Set();
|
||||||
|
}
|
||||||
|
if (!modelCache[row.manufacturer].has(row.model)) {
|
||||||
|
result[row.manufacturer].push({ label: row.model, value: row.model });
|
||||||
|
modelCache[row.manufacturer].add(row.model);
|
||||||
}
|
}
|
||||||
result[row.manufacturer].push({ label: row.model, value: row.model });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send(success(result));
|
res.status(200).send(success(result));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
import express from "express";
|
|
||||||
import u from "@/utils";
|
|
||||||
import { z } from "zod";
|
|
||||||
import { success } from "@/lib/responseFormat";
|
|
||||||
import { validateFields } from "@/middleware/middleware";
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
export default router.post(
|
|
||||||
"/",
|
|
||||||
validateFields({
|
|
||||||
id: z.number(),
|
|
||||||
type: z.enum(["text", "video", "image"]),
|
|
||||||
model: z.string(),
|
|
||||||
baseUrl: z.string(),
|
|
||||||
modelType: z.string(),
|
|
||||||
apiKey: z.string(),
|
|
||||||
manufacturer: z.string(),
|
|
||||||
}),
|
|
||||||
async (req, res) => {
|
|
||||||
const { id, type, model, baseUrl, apiKey, manufacturer, modelType } = req.body;
|
|
||||||
|
|
||||||
await u.db("t_config").where("id", id).update({
|
|
||||||
type,
|
|
||||||
model,
|
|
||||||
baseUrl,
|
|
||||||
apiKey,
|
|
||||||
manufacturer,
|
|
||||||
modelType,
|
|
||||||
});
|
|
||||||
res.status(200).send(success("编辑成功"));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@ -27,6 +27,10 @@ async function superResolutionAndSave(src: string, projectId: number, videoRatio
|
|||||||
systemPrompt: "你的核心任务是将所给的图片超分到 1K ,不改变图片任何内容,仅改变分辨率",
|
systemPrompt: "你的核心任务是将所给的图片超分到 1K ,不改变图片任何内容,仅改变分辨率",
|
||||||
prompt: "你的核心任务是将所给的图片超分到 1K ,不改变图片任何内容,仅改变分辨率",
|
prompt: "你的核心任务是将所给的图片超分到 1K ,不改变图片任何内容,仅改变分辨率",
|
||||||
imageBase64: [await urlToBase64(src)],
|
imageBase64: [await urlToBase64(src)],
|
||||||
|
taskClass: "分镜图超分",
|
||||||
|
name: `分镜图超分-${v4()}`,
|
||||||
|
describe: `原始图片链接: ${src}`,
|
||||||
|
projectId,
|
||||||
},
|
},
|
||||||
apiConfig,
|
apiConfig,
|
||||||
);
|
);
|
||||||
@ -37,7 +41,7 @@ async function superResolutionAndSave(src: string, projectId: number, videoRatio
|
|||||||
await u.oss.writeFile(ossPath, buffer);
|
await u.oss.writeFile(ossPath, buffer);
|
||||||
return { ossPath, base64: `data:image/jpg;base64,${base64Str}` };
|
return { ossPath, base64: `data:image/jpg;base64,${base64Str}` };
|
||||||
}
|
}
|
||||||
|
// 图片超分
|
||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import Storyboard from "@/agents/storyboard";
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
expressWs(router as unknown as Application);
|
expressWs(router as unknown as Application);
|
||||||
|
|
||||||
|
// 分镜对话Agent
|
||||||
router.ws("/", async (ws, req) => {
|
router.ws("/", async (ws, req) => {
|
||||||
let agent: Storyboard;
|
let agent: Storyboard;
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { success } from "@/lib/responseFormat";
|
|||||||
import { validateFields } from "@/middleware/middleware";
|
import { validateFields } from "@/middleware/middleware";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
//删除分镜
|
||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
|
|||||||
@ -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 || "未知错误"}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { validateFields } from "@/middleware/middleware";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// 生成分镜图
|
// 图片编辑
|
||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
@ -6,7 +6,7 @@ import { z } from "zod";
|
|||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// 上传对话图片
|
// 图片上传
|
||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
|
|||||||
@ -4,50 +4,45 @@ import { success } from "@/lib/responseFormat";
|
|||||||
import { validateFields } from "@/middleware/middleware";
|
import { validateFields } from "@/middleware/middleware";
|
||||||
import { number, z } from "zod";
|
import { number, z } from "zod";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
export default router.post(
|
||||||
export default router.get(
|
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
projectName: z.string(),
|
state: z.string().optional().nullable(),
|
||||||
taskName: z.string(),
|
taskClass: z.string().optional().nullable(),
|
||||||
state: z.string(),
|
|
||||||
page: z.number(),
|
page: z.number(),
|
||||||
limit: z.number(),
|
limit: z.number(),
|
||||||
|
projectId: z.number(),
|
||||||
}),
|
}),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { projectName, taskName, state, page = 1, limit = 10 }: any = req.query;
|
const { taskClass, state, page = 1, limit = 10, projectId }: any = req.body;
|
||||||
const offset = (page - 1) * limit;
|
const offset = (page - 1) * limit;
|
||||||
const data = await u
|
const data = await u
|
||||||
.db("t_taskList")
|
.db("t_myTasks")
|
||||||
|
.where("projectId", projectId)
|
||||||
.andWhere((qb) => {
|
.andWhere((qb) => {
|
||||||
if (projectName) {
|
if (taskClass) {
|
||||||
qb.andWhere("t_taskList.projectName", projectName);
|
qb.andWhere("t_myTasks.taskClass", taskClass);
|
||||||
}
|
|
||||||
if (taskName) {
|
|
||||||
qb.andWhere("t_taskList.name", taskName);
|
|
||||||
}
|
}
|
||||||
if (state) {
|
if (state) {
|
||||||
qb.andWhere("t_taskList.state", state);
|
qb.andWhere("t_myTasks.state", state);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.select("*")
|
.select("*")
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.limit(limit);
|
.limit(limit);
|
||||||
const totalQuery = (await u
|
const totalQuery = (await u
|
||||||
.db("t_taskList")
|
.db("t_myTasks")
|
||||||
|
.where("projectId", projectId)
|
||||||
.andWhere((qb) => {
|
.andWhere((qb) => {
|
||||||
if (projectName) {
|
if (taskClass) {
|
||||||
qb.andWhere("t_taskList.projectName", projectName);
|
qb.andWhere("t_myTasks.taskClass", taskClass);
|
||||||
}
|
|
||||||
if (taskName) {
|
|
||||||
qb.andWhere("t_taskList.name", taskName);
|
|
||||||
}
|
}
|
||||||
if (state) {
|
if (state) {
|
||||||
qb.andWhere("t_taskList.state", state);
|
qb.andWhere("t_myTasks.state", state);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.count("* as total")
|
.count("* as total")
|
||||||
.first()) as any;
|
.first()) as any;
|
||||||
res.status(200).send(success({ data, total: totalQuery?.total }));
|
res.status(200).send(success({ data, total: totalQuery?.total }));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
17
src/routes/task/getTaskCategories.ts
Normal file
17
src/routes/task/getTaskCategories.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import express from "express";
|
||||||
|
import u from "@/utils";
|
||||||
|
import { success } from "@/lib/responseFormat";
|
||||||
|
import { validateFields } from "@/middleware/middleware";
|
||||||
|
import { number, z } from "zod";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
export default router.post(
|
||||||
|
"/",
|
||||||
|
validateFields({
|
||||||
|
projectId: z.number(),
|
||||||
|
}),
|
||||||
|
async (req, res) => {
|
||||||
|
const data = await u.db("t_myTasks").where("projectId", req.body.projectId).select("taskClass").groupBy("taskClass");
|
||||||
|
res.status(200).send(success(data));
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -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() !== "");
|
||||||
|
|
||||||
@ -177,6 +172,10 @@ ${prompt}
|
|||||||
resolution: resolution as any,
|
resolution: resolution as any,
|
||||||
audio: audioEnabled,
|
audio: audioEnabled,
|
||||||
mode: mode as any,
|
mode: mode as any,
|
||||||
|
taskClass: "视频生成",
|
||||||
|
name: `视频生成-${videoId}`,
|
||||||
|
describe: `视频生成,时长${duration}秒,分辨率${resolution}`,
|
||||||
|
projectId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
baseURL: aiConfigData?.baseUrl!,
|
baseURL: aiConfigData?.baseUrl!,
|
||||||
@ -197,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)
|
||||||
|
|||||||
230
src/types/database.d.ts
vendored
230
src/types/database.d.ts
vendored
@ -1,12 +1,203 @@
|
|||||||
// @db-hash 0f9789bd5ad2eebd79bd502988efcb4e
|
// @db-hash f991a54893850ab9ff4a67665391191d
|
||||||
//该文件由脚本自动生成,请勿手动修改
|
//该文件由脚本自动生成,请勿手动修改
|
||||||
|
|
||||||
|
export interface memories {
|
||||||
|
'access_count'?: number;
|
||||||
|
'content': string;
|
||||||
|
'created_at': number;
|
||||||
|
'embedding': string;
|
||||||
|
'id'?: string;
|
||||||
|
'type': string;
|
||||||
|
}
|
||||||
|
export interface o_agentDeploy {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'startTime'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_artStyle {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'styles'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_assets {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'startTime'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_chatHistory {
|
||||||
|
'data'?: string | null;
|
||||||
|
'id'?: number;
|
||||||
|
'novel'?: string | null;
|
||||||
|
'projectId'?: number | null;
|
||||||
|
'type'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_event {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'detail'?: string | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_eventChapter {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_image {
|
||||||
|
'assetsId'?: number | null;
|
||||||
|
'filePath'?: string | null;
|
||||||
|
'id'?: number;
|
||||||
|
'projectId'?: number | null;
|
||||||
|
'scriptId'?: number | null;
|
||||||
|
'state'?: string | null;
|
||||||
|
'type'?: string | null;
|
||||||
|
'videoId'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_model {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'startTime'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_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 o_novel {
|
||||||
|
'chapter'?: string | null;
|
||||||
|
'chapterData'?: string | null;
|
||||||
|
'chapterIndex'?: number | null;
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'projectId'?: number | null;
|
||||||
|
'reel'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_outline {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_outlineNovel {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_project {
|
||||||
|
'artStyle'?: string | null;
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number | null;
|
||||||
|
'intro'?: string | null;
|
||||||
|
'name'?: string | null;
|
||||||
|
'projectType'?: string | null;
|
||||||
|
'type'?: string | null;
|
||||||
|
'userId'?: number | null;
|
||||||
|
'videoRatio'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_prompts {
|
||||||
|
'code'?: string | null;
|
||||||
|
'customValue'?: string | null;
|
||||||
|
'defaultValue'?: string | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'parentCode'?: string | null;
|
||||||
|
'type'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_script {
|
||||||
|
'content'?: string | null;
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'projectId'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_scriptAssets {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_scriptOutline {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_setting {
|
||||||
|
'id'?: number;
|
||||||
|
'imageModel'?: string | null;
|
||||||
|
'languageModel'?: string | null;
|
||||||
|
'projectId'?: number | null;
|
||||||
|
'tokenKey'?: string | null;
|
||||||
|
'userId'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_skills {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'startTime'?: number | null;
|
||||||
|
}
|
||||||
|
export interface o_storyboard {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_storyboardScript {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_user {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'password'?: string | null;
|
||||||
|
'tokenKey'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_vendorConfig {
|
||||||
|
'code'?: string | null;
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'icon'?: string | null;
|
||||||
|
'id'?: number;
|
||||||
|
'inputs'?: string | null;
|
||||||
|
'inputValues'?: string | null;
|
||||||
|
'models'?: string | null;
|
||||||
|
'name'?: string | null;
|
||||||
|
'version'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_video {
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
}
|
||||||
|
export interface o_videoConfig {
|
||||||
|
'aiConfigId'?: number | null;
|
||||||
|
'audioEnabled'?: number | null;
|
||||||
|
'createTime'?: number | null;
|
||||||
|
'duration'?: number | null;
|
||||||
|
'endFrame'?: string | null;
|
||||||
|
'id'?: number;
|
||||||
|
'images'?: string | null;
|
||||||
|
'manufacturer'?: string | null;
|
||||||
|
'mode'?: string | null;
|
||||||
|
'projectId'?: number | null;
|
||||||
|
'prompt'?: string | null;
|
||||||
|
'resolution'?: string | null;
|
||||||
|
'scriptId'?: number | null;
|
||||||
|
'selectedResultId'?: number | null;
|
||||||
|
'startFrame'?: string | null;
|
||||||
|
'updateTime'?: number | null;
|
||||||
|
}
|
||||||
export interface t_aiModelMap {
|
export interface t_aiModelMap {
|
||||||
'configId'?: number | null;
|
'configId'?: number | null;
|
||||||
'id'?: number;
|
'id'?: number;
|
||||||
'key'?: string | null;
|
'key'?: string | null;
|
||||||
'name'?: string | null;
|
'name'?: string | null;
|
||||||
}
|
}
|
||||||
|
export interface t_artStyle {
|
||||||
|
'id'?: number;
|
||||||
|
'name'?: string | null;
|
||||||
|
'styles'?: string | null;
|
||||||
|
}
|
||||||
export interface t_assets {
|
export interface t_assets {
|
||||||
'duration'?: string | null;
|
'duration'?: string | null;
|
||||||
'episode'?: string | null;
|
'episode'?: string | null;
|
||||||
@ -115,15 +306,6 @@ export interface t_storyline {
|
|||||||
'novelIds'?: string | null;
|
'novelIds'?: string | null;
|
||||||
'projectId'?: number | null;
|
'projectId'?: number | null;
|
||||||
}
|
}
|
||||||
export interface t_taskList {
|
|
||||||
'endTime'?: string | null;
|
|
||||||
'id'?: number;
|
|
||||||
'name'?: string | null;
|
|
||||||
'projectName'?: number | null;
|
|
||||||
'prompt'?: string | null;
|
|
||||||
'startTime'?: string | null;
|
|
||||||
'state'?: string | null;
|
|
||||||
}
|
|
||||||
export interface t_textModel {
|
export interface t_textModel {
|
||||||
'id'?: number;
|
'id'?: number;
|
||||||
'image'?: number | null;
|
'image'?: number | null;
|
||||||
@ -182,7 +364,34 @@ export interface t_videoModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface DB {
|
export interface DB {
|
||||||
|
"memories": memories;
|
||||||
|
"o_agentDeploy": o_agentDeploy;
|
||||||
|
"o_artStyle": o_artStyle;
|
||||||
|
"o_assets": o_assets;
|
||||||
|
"o_chatHistory": o_chatHistory;
|
||||||
|
"o_event": o_event;
|
||||||
|
"o_eventChapter": o_eventChapter;
|
||||||
|
"o_image": o_image;
|
||||||
|
"o_model": o_model;
|
||||||
|
"o_myTasks": o_myTasks;
|
||||||
|
"o_novel": o_novel;
|
||||||
|
"o_outline": o_outline;
|
||||||
|
"o_outlineNovel": o_outlineNovel;
|
||||||
|
"o_project": o_project;
|
||||||
|
"o_prompts": o_prompts;
|
||||||
|
"o_script": o_script;
|
||||||
|
"o_scriptAssets": o_scriptAssets;
|
||||||
|
"o_scriptOutline": o_scriptOutline;
|
||||||
|
"o_setting": o_setting;
|
||||||
|
"o_skills": o_skills;
|
||||||
|
"o_storyboard": o_storyboard;
|
||||||
|
"o_storyboardScript": o_storyboardScript;
|
||||||
|
"o_user": o_user;
|
||||||
|
"o_vendorConfig": o_vendorConfig;
|
||||||
|
"o_video": o_video;
|
||||||
|
"o_videoConfig": o_videoConfig;
|
||||||
"t_aiModelMap": t_aiModelMap;
|
"t_aiModelMap": t_aiModelMap;
|
||||||
|
"t_artStyle": t_artStyle;
|
||||||
"t_assets": t_assets;
|
"t_assets": t_assets;
|
||||||
"t_chatHistory": t_chatHistory;
|
"t_chatHistory": t_chatHistory;
|
||||||
"t_config": t_config;
|
"t_config": t_config;
|
||||||
@ -195,7 +404,6 @@ export interface DB {
|
|||||||
"t_script": t_script;
|
"t_script": t_script;
|
||||||
"t_setting": t_setting;
|
"t_setting": t_setting;
|
||||||
"t_storyline": t_storyline;
|
"t_storyline": t_storyline;
|
||||||
"t_taskList": t_taskList;
|
|
||||||
"t_textModel": t_textModel;
|
"t_textModel": t_textModel;
|
||||||
"t_user": t_user;
|
"t_user": t_user;
|
||||||
"t_video": t_video;
|
"t_video": t_video;
|
||||||
|
|||||||
35
src/utils/ai/image/adapter/volcengine.ts
Normal file
35
src/utils/ai/image/adapter/volcengine.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import "../type";
|
||||||
|
|
||||||
|
export function buildReqBody(input: ImageConfig, config: AIConfig) {
|
||||||
|
const size = input.size === "1K" ? "2K" : input.size;
|
||||||
|
const sizeMap: Record<string, Record<string, string>> = {
|
||||||
|
"16:9": {
|
||||||
|
"2K": "2848x1600",
|
||||||
|
"4K": "4096x2304",
|
||||||
|
},
|
||||||
|
"9:16": {
|
||||||
|
"2K": "1600x2848",
|
||||||
|
"4K": "2304x4096",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt;
|
||||||
|
|
||||||
|
const requestBody: Record<string, any> = {
|
||||||
|
model: config.model,
|
||||||
|
prompt: fullPrompt,
|
||||||
|
size: sizeMap[input.aspectRatio][size],
|
||||||
|
response_format: "url",
|
||||||
|
sequential_image_generation: "disabled",
|
||||||
|
stream: false,
|
||||||
|
watermark: false,
|
||||||
|
...(input.imageBase64 && { image: input.imageBase64 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
return requestBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildReqUrl(baseUrl: string) {
|
||||||
|
return {
|
||||||
|
requestUrl: `${baseUrl}/v1/images/generations`,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -12,7 +12,8 @@ import other from "./owned/other";
|
|||||||
import gemini from "./owned/gemini";
|
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 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");
|
||||||
@ -29,20 +30,32 @@ const modelInstance = {
|
|||||||
// apimart: apimart,
|
// apimart: apimart,
|
||||||
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) => {
|
||||||
const { model, apiKey, baseURL, manufacturer } = { ...config };
|
const { model, apiKey, baseURL, manufacturer } = { ...config };
|
||||||
|
|
||||||
if (!config || !config?.model || !config?.apiKey || !config?.manufacturer) throw new Error("请检查模型配置是否正确");
|
if (!config || !config?.model || !config?.apiKey || !config?.manufacturer) throw new Error("请检查模型配置是否正确");
|
||||||
|
|
||||||
const manufacturerFn = modelInstance[manufacturer as keyof typeof modelInstance];
|
const manufacturerFn = modelInstance[manufacturer as keyof typeof modelInstance];
|
||||||
if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的图片厂商");
|
if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的图片厂商");
|
||||||
|
|
||||||
// if (manufacturer !== "other") {
|
// if (manufacturer !== "other") {
|
||||||
// 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({
|
||||||
|
// taskClass: input.taskClass,
|
||||||
|
// relatedObjects: input.name,
|
||||||
|
// model: config?.model ? config.model : "未知模型",
|
||||||
|
// describe: input.describe ? input.describe : "无",
|
||||||
|
// state: "进行中",
|
||||||
|
// startTime: Date.now(),
|
||||||
|
// 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) => {
|
||||||
@ -66,9 +79,20 @@ export default async (input: ImageConfig, config: AIConfig) => {
|
|||||||
return `data:image/png;base64,${img}`;
|
return `data:image/png;base64,${img}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
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({
|
||||||
return imageUrl;
|
// state: "已完成",
|
||||||
|
// });
|
||||||
|
return imageUrl;
|
||||||
|
} catch (error: any) {
|
||||||
|
// await u.db("t_myTasks").where("id", taskId).update({
|
||||||
|
// state: "生成失败",
|
||||||
|
// reason: error.message,
|
||||||
|
// });
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
62
src/utils/ai/image/owned/formal.ts
Normal file
62
src/utils/ai/image/owned/formal.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
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";
|
||||||
|
import * as volcengine from "../adapter/volcengine";
|
||||||
|
const modelFn = {
|
||||||
|
volcengine,
|
||||||
|
} as const;
|
||||||
|
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 { requestUrl, queryUrl = null } = modelFn["volcengine"].buildReqUrl(config?.baseURL);
|
||||||
|
const taskBody = modelFn["volcengine"].buildReqBody(input, config);
|
||||||
|
|
||||||
|
const apiKey = config.apiKey.replace("Bearer ", "");
|
||||||
|
try {
|
||||||
|
const { data } = await axios.post(requestUrl, taskBody, { headers: { Authorization: `Bearer ${apiKey}` } });
|
||||||
|
|
||||||
|
if (queryUrl) {
|
||||||
|
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}` },
|
||||||
|
});
|
||||||
|
|
||||||
|
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 };
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return data.data[0]?.url;
|
||||||
|
}
|
||||||
|
} 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}`;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
@ -42,7 +42,6 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.files.length) {
|
if (!result.files.length) {
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import "../type";
|
import "../type";
|
||||||
import { generateImage, generateText, ModelMessage } from "ai";
|
import { generateImage, generateText, ModelMessage } from "ai";
|
||||||
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
||||||
|
import { createOpenAI, OpenAIProviderSettings } from "@ai-sdk/openai";
|
||||||
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export default async (input: ImageConfig, config: AIConfig): Promise<string> => {
|
export default async (input: ImageConfig, config: AIConfig): Promise<string> => {
|
||||||
@ -11,7 +14,7 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
|||||||
const apiKey = config.apiKey.replace("Bearer ", "");
|
const apiKey = config.apiKey.replace("Bearer ", "");
|
||||||
|
|
||||||
const otherProvider = createOpenAICompatible({
|
const otherProvider = createOpenAICompatible({
|
||||||
name: "xixixi",
|
name: "other",
|
||||||
baseURL: config.baseURL,
|
baseURL: config.baseURL,
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${apiKey}`,
|
Authorization: `Bearer ${apiKey}`,
|
||||||
@ -28,6 +31,12 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
|||||||
const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt;
|
const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt;
|
||||||
const model = config.model;
|
const model = config.model;
|
||||||
if (model.includes("gemini") || model.includes("nano")) {
|
if (model.includes("gemini") || model.includes("nano")) {
|
||||||
|
// 对于 Gemini 模型,使用 Google provider 以支持 imageConfig 参数
|
||||||
|
const googleProvider = createGoogleGenerativeAI({
|
||||||
|
apiKey: apiKey,
|
||||||
|
baseURL: config.baseURL,
|
||||||
|
});
|
||||||
|
|
||||||
let promptData;
|
let promptData;
|
||||||
if (input.imageBase64 && input.imageBase64.length) {
|
if (input.imageBase64 && input.imageBase64.length) {
|
||||||
promptData = [{ role: "system", content: fullPrompt + `请直接输出图片` }];
|
promptData = [{ role: "system", content: fullPrompt + `请直接输出图片` }];
|
||||||
@ -35,15 +44,14 @@ 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 {
|
||||||
promptData = fullPrompt + `请直接输出图片`;
|
promptData = fullPrompt + `请直接输出图片`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await generateText({
|
const result = await generateText({
|
||||||
model: otherProvider.languageModel(model),
|
model: googleProvider.languageModel(model),
|
||||||
prompt: promptData as string | ModelMessage[],
|
prompt: promptData as string | ModelMessage[],
|
||||||
providerOptions: {
|
providerOptions: {
|
||||||
google: {
|
google: {
|
||||||
@ -52,7 +60,6 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
|||||||
? { aspectRatio: input.aspectRatio }
|
? { aspectRatio: input.aspectRatio }
|
||||||
: { aspectRatio: input.aspectRatio, imageSize: input.size }),
|
: { aspectRatio: input.aspectRatio, imageSize: input.size }),
|
||||||
},
|
},
|
||||||
responseModalities: ["IMAGE"],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -105,7 +112,11 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
|||||||
size: sizeMap[input.size] ?? "1024x1024",
|
size: sizeMap[input.size] ?? "1024x1024",
|
||||||
});
|
});
|
||||||
|
|
||||||
return image.base64;
|
if (image.base64.startsWith("data:image/")) {
|
||||||
|
return image.base64;
|
||||||
|
} else {
|
||||||
|
return `data:image/png;base64,${image.base64}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,10 @@ interface ImageConfig {
|
|||||||
size: "1K" | "2K" | "4K";
|
size: "1K" | "2K" | "4K";
|
||||||
aspectRatio: string;
|
aspectRatio: string;
|
||||||
resType?: "url" | "b64";
|
resType?: "url" | "b64";
|
||||||
|
taskClass: string;
|
||||||
|
name: string;
|
||||||
|
describe: string;
|
||||||
|
projectId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AIConfig {
|
interface AIConfig {
|
||||||
|
|||||||
@ -35,11 +35,18 @@ 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> = {
|
||||||
schema: (s) => {
|
schema: (s) => {
|
||||||
|
const schemaPrompt = `\n请按照以下 schema 格式返回结果:\n${JSON.stringify(
|
||||||
|
z.toJSONSchema(z.object(s)),
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\n请输出JSON格式,只返回结果,不要将Schema返回。`;
|
||||||
|
input.system = (input.system ?? "") + schemaPrompt;
|
||||||
|
// 返回验证模式
|
||||||
return Output.object({ schema: z.object(s) });
|
return Output.object({ schema: z.object(s) });
|
||||||
},
|
},
|
||||||
object: () => {
|
object: () => {
|
||||||
@ -47,14 +54,14 @@ const buildOptions = async (input: AIInput<any>, config: AIConfig = {}) => {
|
|||||||
z.toJSONSchema(z.object(input.output)),
|
z.toJSONSchema(z.object(input.output)),
|
||||||
null,
|
null,
|
||||||
2,
|
2,
|
||||||
)}\n只返回结果,不要将Schema返回。`;
|
)}\n请输出JSON格式,只返回结果,不要将Schema返回。`;
|
||||||
input.system = (input.system ?? "") + jsonSchemaPrompt;
|
input.system = (input.system ?? "") + jsonSchemaPrompt;
|
||||||
// return Output.json();
|
// return Output.json();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
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", "formal"];
|
||||||
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 {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
39
src/utils/ai/video/adapter/openai.ts
Normal file
39
src/utils/ai/video/adapter/openai.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import sharp from "sharp";
|
||||||
|
import "../type";
|
||||||
|
import FormData from "form-data";
|
||||||
|
|
||||||
|
export async function buildReqBody(input: VideoConfig, config: AIConfig) {
|
||||||
|
const sizeMap: Record<string, string> = {
|
||||||
|
"16:9": "1280x720",
|
||||||
|
"9:16": "720x1280",
|
||||||
|
};
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("model", config.model!);
|
||||||
|
formData.append("prompt", input.prompt);
|
||||||
|
formData.append("seconds", String(input.duration));
|
||||||
|
|
||||||
|
const size = sizeMap[input.aspectRatio] || "1280x720";
|
||||||
|
formData.append("size", size);
|
||||||
|
if (input.imageBase64 && input.imageBase64.length) {
|
||||||
|
const base64Data = input.imageBase64[0]!.replace(/^data:image\/\w+;base64,/, "");
|
||||||
|
const buffer = Buffer.from(base64Data, "base64");
|
||||||
|
|
||||||
|
// 解析尺寸
|
||||||
|
const [width, height] = size.split("x").map(Number);
|
||||||
|
|
||||||
|
// 使用 sharp 调整图片尺寸
|
||||||
|
const resizedBuffer = await sharp(buffer).resize(width, height, { fit: "cover" }).jpeg({ quality: 100 }).toBuffer();
|
||||||
|
|
||||||
|
formData.append("input_reference", resizedBuffer, { filename: "image.jpg", contentType: "image/jpeg" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildReqUrl(baseUrl: string): { requestUrl: string; queryUrl: string; downLoadUrl: string } {
|
||||||
|
return {
|
||||||
|
requestUrl: `${baseUrl}/v1/videos`,
|
||||||
|
queryUrl: `${baseUrl}/v1/videos/{id}`,
|
||||||
|
downLoadUrl: `${baseUrl}/v1/videos/{id}/content`,
|
||||||
|
};
|
||||||
|
}
|
||||||
26
src/utils/ai/video/adapter/vidu.ts
Normal file
26
src/utils/ai/video/adapter/vidu.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import "../type";
|
||||||
|
|
||||||
|
export function buildReqBody(input: VideoConfig, config: AIConfig) {
|
||||||
|
const requestBody: any = {
|
||||||
|
model: config.model,
|
||||||
|
...(input.imageBase64 && input.imageBase64.length ? { images: input.imageBase64 } : {}),
|
||||||
|
prompt: input.prompt,
|
||||||
|
duration: input.duration,
|
||||||
|
size: input.resolution,
|
||||||
|
metadata: {
|
||||||
|
aspect_ratio: input.aspectRatio,
|
||||||
|
audio: input?.audio ?? false,
|
||||||
|
off_peak: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("%c Line:5 🍔 requestBody", "background:#465975", requestBody);
|
||||||
|
return requestBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildReqUrl(baseUrl: string): { requestUrl: string; queryUrl: string } {
|
||||||
|
return {
|
||||||
|
requestUrl: `${baseUrl}/v1/video/generations`,
|
||||||
|
queryUrl: `${baseUrl}/v1/video/generations/{id}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
54
src/utils/ai/video/adapter/volcengine.ts
Normal file
54
src/utils/ai/video/adapter/volcengine.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import "../type";
|
||||||
|
|
||||||
|
export function buildReqBody(input: VideoConfig, config: AIConfig) {
|
||||||
|
const hasStartEndType = input.mode === "startEnd";
|
||||||
|
const images = input.imageBase64 || [];
|
||||||
|
// 判断是否为首尾帧模式(需要两张图且类型支持首尾帧)
|
||||||
|
const isStartEndMode = images.length === 2 && hasStartEndType;
|
||||||
|
|
||||||
|
// 构建图片内容
|
||||||
|
const imageContent = images.map((base64, index) => {
|
||||||
|
const item: Record<string, any> = {
|
||||||
|
type: "image_url",
|
||||||
|
image_url: { url: base64 },
|
||||||
|
};
|
||||||
|
if (isStartEndMode) {
|
||||||
|
item.role = index === 0 ? "first_frame" : "last_frame";
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
|
// // 构建请求体
|
||||||
|
// const requestBody: Record<string, any> = {
|
||||||
|
// model: config.model,
|
||||||
|
// content: [{ type: "text", text: input.prompt }, ...imageContent],
|
||||||
|
// duration: input.duration,
|
||||||
|
// resolution: input.resolution,
|
||||||
|
// watermark: false,
|
||||||
|
// };
|
||||||
|
const requestBody: any = {
|
||||||
|
model: config.model,
|
||||||
|
...(input.imageBase64 && input.imageBase64.length ? { images: input.imageBase64 } : {}),
|
||||||
|
prompt: input.prompt,
|
||||||
|
duration: input.duration,
|
||||||
|
size: input.resolution,
|
||||||
|
metadata: {
|
||||||
|
generate_audio: input?.audio ?? false,
|
||||||
|
ratio: input.aspectRatio,
|
||||||
|
image_roles: ["first_frame", "last_frame"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// // 仅当模型支持音频时才添加 generate_audio 字段
|
||||||
|
// if (typeof input.audio == "boolean") {
|
||||||
|
// requestBody.generate_audio = input.audio ?? false;
|
||||||
|
// }
|
||||||
|
return requestBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildReqUrl(baseUrl: string): { requestUrl: string; queryUrl: string } {
|
||||||
|
return {
|
||||||
|
requestUrl: `${baseUrl}/v1/video/generations`,
|
||||||
|
queryUrl: `${baseUrl}/v1/video/generations/{id}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
61
src/utils/ai/video/adapter/wan.ts
Normal file
61
src/utils/ai/video/adapter/wan.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import "../type";
|
||||||
|
|
||||||
|
export function buildReqBody(input: VideoConfig, config: AIConfig) {
|
||||||
|
const images = input.imageBase64 || [];
|
||||||
|
|
||||||
|
// 构建图片内容
|
||||||
|
const imageContent = images.map((base64, index) => {
|
||||||
|
const item: Record<string, any> = {
|
||||||
|
type: "image_url",
|
||||||
|
image: { url: base64 },
|
||||||
|
};
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const sizeMap: Record<string, Record<string, string>> = {
|
||||||
|
"480p": {
|
||||||
|
"16:9": "832*480",
|
||||||
|
"9:16": "480*832",
|
||||||
|
},
|
||||||
|
"720p": {
|
||||||
|
"16:9": "1280*720",
|
||||||
|
"9:16": "720*1280",
|
||||||
|
},
|
||||||
|
"1080p": {
|
||||||
|
"16:9": "1920*1080",
|
||||||
|
"9:16": "1080*1920",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const hasStartEnd = input.mode == "startEnd";
|
||||||
|
|
||||||
|
const imageReq: Record<string, string> = {};
|
||||||
|
if (hasStartEnd && Array.isArray(images) && images.length) {
|
||||||
|
if (images[0]) imageReq.first_frame_url = images[0];
|
||||||
|
if (images[1]) imageReq.last_frame_url = images[1];
|
||||||
|
} else if (!hasStartEnd && Array.isArray(images) && images[0]) {
|
||||||
|
imageReq.img_url = images[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolutionKey = input.resolution;
|
||||||
|
|
||||||
|
const size = sizeMap[resolutionKey]?.[input.aspectRatio];
|
||||||
|
|
||||||
|
const requestBody: any = {
|
||||||
|
model: config.model,
|
||||||
|
...(imageReq?.img_url ? { input_reference: imageReq.img_url } : {}),
|
||||||
|
prompt: input.prompt,
|
||||||
|
size,
|
||||||
|
duration: input.duration,
|
||||||
|
metadata: {
|
||||||
|
...imageReq,
|
||||||
|
audio: input?.audio ?? false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return requestBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildReqUrl(baseUrl: string): { requestUrl: string; queryUrl: string } {
|
||||||
|
return {
|
||||||
|
requestUrl: `${baseUrl}/v1/video/generations`,
|
||||||
|
queryUrl: `${baseUrl}/v1/video/generations/{id}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -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,
|
||||||
@ -21,7 +23,8 @@ const modelInstance = {
|
|||||||
runninghub: runninghub,
|
runninghub: runninghub,
|
||||||
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) => {
|
||||||
@ -32,7 +35,16 @@ export default async (input: VideoConfig, config?: AIConfig) => {
|
|||||||
if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的视频厂商");
|
if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的视频厂商");
|
||||||
// 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({
|
||||||
|
// taskClass: input.taskClass,
|
||||||
|
// relatedObjects: input.name,
|
||||||
|
// model: config?.model ? config.model : "未知模型",
|
||||||
|
// describe: input.describe ? input.describe : "无",
|
||||||
|
// state: "进行中",
|
||||||
|
// startTime: Date.now(),
|
||||||
|
// 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) => {
|
||||||
@ -59,9 +71,20 @@ export default async (input: VideoConfig, config?: AIConfig) => {
|
|||||||
|
|
||||||
let videoUrl = await manufacturerFn(input, { model, apiKey, baseURL });
|
let videoUrl = await manufacturerFn(input, { model, apiKey, baseURL });
|
||||||
if (videoUrl) {
|
if (videoUrl) {
|
||||||
const response = await axios.get(videoUrl, { responseType: "stream" });
|
try {
|
||||||
await u.oss.writeFile(input.savePath, response.data);
|
const response = await axios.get(videoUrl, { responseType: "stream" });
|
||||||
return input.savePath;
|
await u.oss.writeFile(input.savePath, response.data);
|
||||||
|
// await u.db("t_myTasks").where("id", taskId).update({
|
||||||
|
// state: "已完成",
|
||||||
|
// });
|
||||||
|
return input.savePath;
|
||||||
|
} catch (err: any) {
|
||||||
|
// await u.db("t_myTasks").where("id", taskId).update({
|
||||||
|
// state: "生成失败",
|
||||||
|
// reason: err.message,
|
||||||
|
// });
|
||||||
|
return videoUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return videoUrl;
|
return videoUrl;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -159,15 +159,6 @@ const modelList: Owned[] = [
|
|||||||
audio: false,
|
audio: false,
|
||||||
},
|
},
|
||||||
// ================== ViduQ3系列 ==================
|
// ================== ViduQ3系列 ==================
|
||||||
// viduq3-pro 文生视频
|
|
||||||
{
|
|
||||||
manufacturer: "vidu",
|
|
||||||
model: "viduq3-pro",
|
|
||||||
durationResolutionMap: [{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], resolution: ["540p", "720p", "1080p"] }],
|
|
||||||
aspectRatio: ["16:9", "9:16", "3:4", "4:3", "1:1"],
|
|
||||||
type: ["text"],
|
|
||||||
audio: true,
|
|
||||||
},
|
|
||||||
// viduq3-pro 图生视频
|
// viduq3-pro 图生视频
|
||||||
{
|
{
|
||||||
manufacturer: "vidu",
|
manufacturer: "vidu",
|
||||||
@ -187,14 +178,6 @@ const modelList: Owned[] = [
|
|||||||
audio: false,
|
audio: false,
|
||||||
},
|
},
|
||||||
// viduq2-pro 文生视频
|
// viduq2-pro 文生视频
|
||||||
{
|
|
||||||
manufacturer: "vidu",
|
|
||||||
model: "viduq2-pro",
|
|
||||||
durationResolutionMap: [{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }],
|
|
||||||
aspectRatio: ["16:9", "9:16", "3:4", "4:3", "1:1"],
|
|
||||||
type: ["text"],
|
|
||||||
audio: false,
|
|
||||||
},
|
|
||||||
// viduq2-pro 图生视频
|
// viduq2-pro 图生视频
|
||||||
{
|
{
|
||||||
manufacturer: "vidu",
|
manufacturer: "vidu",
|
||||||
@ -205,14 +188,6 @@ const modelList: Owned[] = [
|
|||||||
audio: false,
|
audio: false,
|
||||||
},
|
},
|
||||||
// viduq2-turbo 文生视频
|
// viduq2-turbo 文生视频
|
||||||
{
|
|
||||||
manufacturer: "vidu",
|
|
||||||
model: "viduq2-turbo",
|
|
||||||
durationResolutionMap: [{ duration: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], resolution: ["540p", "720p", "1080p"] }],
|
|
||||||
aspectRatio: ["16:9", "9:16", "3:4", "4:3", "1:1"],
|
|
||||||
type: ["text"],
|
|
||||||
audio: false,
|
|
||||||
},
|
|
||||||
// viduq2-turbo 图生视频
|
// viduq2-turbo 图生视频
|
||||||
{
|
{
|
||||||
manufacturer: "vidu",
|
manufacturer: "vidu",
|
||||||
@ -223,14 +198,6 @@ const modelList: Owned[] = [
|
|||||||
audio: false,
|
audio: false,
|
||||||
},
|
},
|
||||||
// viduq1 文生视频
|
// viduq1 文生视频
|
||||||
{
|
|
||||||
manufacturer: "vidu",
|
|
||||||
model: "viduq1",
|
|
||||||
durationResolutionMap: [{ duration: [5], resolution: ["1080p"] }],
|
|
||||||
aspectRatio: ["16:9", "9:16", "1:1"],
|
|
||||||
type: ["text"],
|
|
||||||
audio: false,
|
|
||||||
},
|
|
||||||
// viduq1 图生视频
|
// viduq1 图生视频
|
||||||
{
|
{
|
||||||
manufacturer: "vidu",
|
manufacturer: "vidu",
|
||||||
@ -465,7 +432,7 @@ const modelList: Owned[] = [
|
|||||||
type: ["singleImage", "text"],
|
type: ["singleImage", "text"],
|
||||||
audio: false,
|
audio: false,
|
||||||
},
|
},
|
||||||
// ================== Apimart 系列 ==================
|
// ================== Apimart 系列 ==================
|
||||||
// sora
|
// sora
|
||||||
{
|
{
|
||||||
manufacturer: "apimart",
|
manufacturer: "apimart",
|
||||||
|
|||||||
169
src/utils/ai/video/owned/formal.ts
Normal file
169
src/utils/ai/video/owned/formal.ts
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import "../type";
|
||||||
|
import { pollTask } from "@/utils/ai/utils";
|
||||||
|
import u from "@/utils";
|
||||||
|
import axios from "axios";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
import * as volcengine from "../adapter/volcengine";
|
||||||
|
import * as openai from "../adapter/openai";
|
||||||
|
import * as vidu from "../adapter/vidu";
|
||||||
|
import * as wan from "../adapter/wan";
|
||||||
|
|
||||||
|
// 适配器映射
|
||||||
|
const modelFn = {
|
||||||
|
volcengine,
|
||||||
|
vidu,
|
||||||
|
openai,
|
||||||
|
wan,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 模型名称到适配器的映射(精确匹配)
|
||||||
|
const modelMapping: Record<string, keyof typeof modelFn> = {
|
||||||
|
// Volcengine 火山引擎模型
|
||||||
|
"doubao-seedance-1-5-pro-251215": "volcengine",
|
||||||
|
"doubao-seedance-1-0-pro-250528": "volcengine",
|
||||||
|
"Seedance-2.0": "volcengine",
|
||||||
|
// Vidu 模型
|
||||||
|
ViduQ2: "vidu",
|
||||||
|
"ViduQ2-turbo": "vidu",
|
||||||
|
"ViduQ2-pro": "vidu",
|
||||||
|
"ViduQ3-pro": "vidu",
|
||||||
|
// OpenAI 模型
|
||||||
|
sora2: "openai",
|
||||||
|
"sora2-pro": "openai",
|
||||||
|
"gpt-video": "openai",
|
||||||
|
// 万象/Wan 模型
|
||||||
|
"Wan2.6-T2V": "wan",
|
||||||
|
"Wan2.6-I2V": "wan",
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模型名称关键字到适配器的映射(模糊匹配)
|
||||||
|
const modelKeywords: Array<{ keywords: string[]; adapter: keyof typeof modelFn }> = [
|
||||||
|
{ keywords: ["doubao", "volcengine", "seedance"], adapter: "volcengine" },
|
||||||
|
{ keywords: ["vidu"], adapter: "vidu" },
|
||||||
|
{ keywords: ["sora", "openai", "gpt"], adapter: "openai" },
|
||||||
|
{ keywords: ["wan", "wanx"], adapter: "wan" },
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据模型名称获取对应的适配器
|
||||||
|
*/
|
||||||
|
function getModelAdapter(modelName: string) {
|
||||||
|
// 1. 先尝试精确匹配
|
||||||
|
const exactMatch = modelMapping[modelName.toLowerCase()];
|
||||||
|
if (exactMatch) {
|
||||||
|
return modelFn[exactMatch];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 尝试关键字模糊匹配
|
||||||
|
const lowerModelName = modelName.toLowerCase();
|
||||||
|
for (const { keywords, adapter } of modelKeywords) {
|
||||||
|
if (keywords.some((kw) => lowerModelName.includes(kw.toLowerCase()))) {
|
||||||
|
return modelFn[adapter];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 如果模型名称本身就是适配器名称
|
||||||
|
if (modelName in modelFn) {
|
||||||
|
return modelFn[modelName as keyof typeof modelFn];
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelFn["wan"];
|
||||||
|
}
|
||||||
|
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 modelAdapter = getModelAdapter(config.model);
|
||||||
|
|
||||||
|
const { requestUrl, queryUrl, downLoadUrl = null } = modelAdapter.buildReqUrl(config.baseURL);
|
||||||
|
const taskBody = await modelAdapter.buildReqBody(input, config);
|
||||||
|
|
||||||
|
const apiKey = config.apiKey.replace("Bearer ", "");
|
||||||
|
try {
|
||||||
|
const { data } = await axios.post(requestUrl, taskBody, { headers: { Authorization: `Bearer ${apiKey}` } });
|
||||||
|
console.log("%c Line:91 🌽 data", "background:#3f7cff", data);
|
||||||
|
|
||||||
|
const taskId = data.id ?? data.taskId ?? data.task_id ?? data.data;
|
||||||
|
|
||||||
|
if (!taskId) throw new Error(`任务提交失败: ${data ? JSON.stringify(data) : "未知错误"}`);
|
||||||
|
|
||||||
|
return await pollTask(async () => {
|
||||||
|
const { data: queryData } = await axios.get(template({ id: taskId }, queryUrl), {
|
||||||
|
headers: { Authorization: `Bearer ${apiKey}` },
|
||||||
|
});
|
||||||
|
console.log("%c Line:99 🥝 queryData", "background:#e41a6a", queryData);
|
||||||
|
|
||||||
|
// const { status, result_url, fail_reason } = queryData.data || {};
|
||||||
|
|
||||||
|
const status = queryData?.status ?? queryData?.data?.status;
|
||||||
|
const result_url = queryData?.metadata?.url ?? queryData?.data?.result_url;
|
||||||
|
const fail_reason = queryData?.data?.fail_reason ?? queryData?.data;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case "completed":
|
||||||
|
case "SUCCESS":
|
||||||
|
case "success":
|
||||||
|
if (downLoadUrl) {
|
||||||
|
// 下载视频,带重试机制
|
||||||
|
let videoRes;
|
||||||
|
let retries = 3;
|
||||||
|
let lastError;
|
||||||
|
|
||||||
|
for (let i = 0; i < retries; i++) {
|
||||||
|
try {
|
||||||
|
// 构建下载URL
|
||||||
|
const finalDownloadUrl = downLoadUrl
|
||||||
|
? template({ id: taskId }, downLoadUrl)
|
||||||
|
: queryData.video_url || queryData.url || queryData.metadata.url; // 从响应中获取视频URL
|
||||||
|
|
||||||
|
videoRes = await axios.get(finalDownloadUrl, {
|
||||||
|
headers: { Authorization: `Bearer ${apiKey}` },
|
||||||
|
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 };
|
||||||
|
} else {
|
||||||
|
return { completed: true, url: result_url };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
const msg = u.error(error).message || "图片生成失败";
|
||||||
|
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -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 };
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -21,6 +21,8 @@ export default async (input: VideoConfig, config: AIConfig) => {
|
|||||||
};
|
};
|
||||||
if (isStartEndMode) {
|
if (isStartEndMode) {
|
||||||
item.role = index === 0 ? "first_frame" : "last_frame";
|
item.role = index === 0 ? "first_frame" : "last_frame";
|
||||||
|
} else {
|
||||||
|
item.role = "reference_image";
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
@ -35,9 +37,10 @@ export default async (input: VideoConfig, config: AIConfig) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 仅当模型支持音频时才添加 generate_audio 字段
|
// 仅当模型支持音频时才添加 generate_audio 字段
|
||||||
if (input?.audio) {
|
if (typeof input?.audio == "boolean") {
|
||||||
requestBody.generate_audio = input.audio ?? false;
|
requestBody.generate_audio = input.audio ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建视频生成任务
|
// 创建视频生成任务
|
||||||
const createResponse = await axios.post(baseUrl, requestBody, {
|
const createResponse = await axios.post(baseUrl, requestBody, {
|
||||||
headers: {
|
headers: {
|
||||||
@ -45,6 +48,7 @@ export default async (input: VideoConfig, config: AIConfig) => {
|
|||||||
Authorization: authorization,
|
Authorization: authorization,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
console.log("%c Line:44 🍡 createResponse", "background:#2eafb0", createResponse.data);
|
||||||
|
|
||||||
const taskId = createResponse.data.id;
|
const taskId = createResponse.data.id;
|
||||||
|
|
||||||
@ -55,18 +59,29 @@ export default async (input: VideoConfig, config: AIConfig) => {
|
|||||||
const data = await axios.get(`${baseUrl}/${taskId}`, {
|
const data = await axios.get(`${baseUrl}/${taskId}`, {
|
||||||
headers: { Authorization: authorization },
|
headers: { Authorization: authorization },
|
||||||
});
|
});
|
||||||
|
console.log("%c Line:62 🥕 data.data", "background:#e41a6a", data.data);
|
||||||
|
|
||||||
const { status, content } = data.data;
|
const { status, content, error } = data.data;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "succeeded":
|
case "succeeded":
|
||||||
|
case "completed":
|
||||||
return { completed: true, url: content?.video_url };
|
return { completed: true, url: content?.video_url };
|
||||||
case "failed":
|
case "failed":
|
||||||
case "cancelled":
|
case "cancelled":
|
||||||
case "expired":
|
case "expired":
|
||||||
return { completed: false, error: `任务${status}` };
|
let errorMsg = "";
|
||||||
|
try {
|
||||||
|
errorMsg = typeof error === "string" ? error : JSON.stringify(error);
|
||||||
|
} catch (e) {
|
||||||
|
errorMsg = error || "";
|
||||||
|
}
|
||||||
|
return { completed: false, error: `任务${status}: ${errorMsg}` };
|
||||||
case "queued":
|
case "queued":
|
||||||
case "running":
|
case "running":
|
||||||
|
case "unknown":
|
||||||
|
case "submit":
|
||||||
|
case "in_progress":
|
||||||
return { completed: false };
|
return { completed: false };
|
||||||
default:
|
default:
|
||||||
return { completed: false, error: `未知状态: ${status}` };
|
return { completed: false, error: `未知状态: ${status}` };
|
||||||
|
|||||||
@ -7,6 +7,10 @@ interface VideoConfig {
|
|||||||
imageBase64?: string[];
|
imageBase64?: string[];
|
||||||
audio?: boolean;
|
audio?: boolean;
|
||||||
mode: "startEnd" | "multi" | "single" | "text";
|
mode: "startEnd" | "multi" | "single" | "text";
|
||||||
|
taskClass: string;
|
||||||
|
name: string;
|
||||||
|
projectId: number;
|
||||||
|
describe?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AIConfig {
|
interface AIConfig {
|
||||||
|
|||||||
@ -88,6 +88,10 @@ export default async (images: Record<string, string>, directive: string, project
|
|||||||
imageBase64: base64Images,
|
imageBase64: base64Images,
|
||||||
aspectRatio: aspectRatio ? aspectRatio : "16:9",
|
aspectRatio: aspectRatio ? aspectRatio : "16:9",
|
||||||
size: "1K",
|
size: "1K",
|
||||||
|
taskClass: "图片编辑",
|
||||||
|
name: `图片编辑-${uuid()}`,
|
||||||
|
describe: `编辑指令: ${directive}`,
|
||||||
|
projectId,
|
||||||
},
|
},
|
||||||
apiConfig,
|
apiConfig,
|
||||||
);
|
);
|
||||||
|
|||||||
2454
tempCodeRunnerFile.javascript
Normal file
2454
tempCodeRunnerFile.javascript
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user