ai生成任务字段单独拿出来

This commit is contained in:
小帅 2026-03-30 21:55:12 +08:00
parent 0fe8001d2f
commit 3998d441d4
6 changed files with 147 additions and 153 deletions

View File

@ -263,96 +263,95 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
{
name: "剧本资产提取",
type: "scriptAssetExtraction",
data: `
---
name: universal_agent
description: 专注于从剧本内容中提取所使用的资产
---
data: `---
name: universal_agent
description: 专注于从剧本内容中提取所使用的资产
---
# Script Assets Extract
# Script Assets Extract
使
使
## 使
## 使
AI
AI
##
##
-
-
- \`role\` — 角色(对应 \`o_assets.type = "role"\`
- \`scene\` — 场景(对应 \`o_assets.type = "scene"\`
- \`tool\` — 道具(对应 \`o_assets.type = "tool"\`
- AI
- AI
##
##
** \`resultTool\` 工具返回结果**禁止以纯文本、Markdown 表格或 JSON 代码块等形式直接输出资产列表。
\`resultTool\` 的 schema 会对字段类型和枚举值做强校验,调用时请严格按照下方字段定义填写,确保数据结构正确、字段完整、类型匹配。
** \`resultTool\` 工具返回结果**禁止以纯文本、Markdown 表格或 JSON 代码块等形式直接输出资产列表。
\`resultTool\` 的 schema 会对字段类型和枚举值做强校验,调用时请严格按照下方字段定义填写,确保数据结构正确、字段完整、类型匹配。
| | | | |
| ---- | ---- | ---- | ---- |
| \`name\` | string | 是 | 资产名称,使用剧本中的原始称呼,不做其他多余描述 |
| \`desc\` | string | 是 | 资产描述30-80 字的视觉化描述 |
| \`prompt\` | string | 是 | 生成提示词,英文,用于 AI 图片生成 |
| \`type\` | enum | 是 | 资产类型:\`role\` / \`scene\` / \`tool\` |
| | | | |
| ---- | ---- | ---- | ---- |
| \`name\` | string | 是 | 资产名称,使用剧本中的原始称呼,不做其他多余描述 |
| \`desc\` | string | 是 | 资产描述30-80 字的视觉化描述 |
| \`prompt\` | string | 是 | 生成提示词,英文,用于 AI 图片生成 |
| \`type\` | enum | 是 | 资产类型:\`role\` / \`scene\` / \`tool\` |
##
##
### role
### role
-
- \`desc\`:包含外貌特征、服饰风格、体态气质等视觉要素
- \`prompt\`:英文提示词,描述角色的外观特征,适用于 AI 角色图生成
- \`name\`
- "路人甲""士兵"
-
- \`desc\`:包含外貌特征、服饰风格、体态气质等视觉要素
- \`prompt\`:英文提示词,描述角色的外观特征,适用于 AI 角色图生成
- \`name\`
- "路人甲""士兵"
### scene
### scene
- /
- \`desc\`:包含空间结构、光照氛围、关键陈设、色调基调等视觉要素
- \`prompt\`:英文提示词,描述场景的整体视觉风格,适用于 AI 场景图生成
- / \`desc\` 中注明即可
- /
- \`desc\`:包含空间结构、光照氛围、关键陈设、色调基调等视觉要素
- \`prompt\`:英文提示词,描述场景的整体视觉风格,适用于 AI 场景图生成
- / \`desc\` 中注明即可
### tool
### tool
- /
- \`desc\`:包含外观形状、颜色材质、尺寸参考、特殊效果等视觉要素
- \`prompt\`:英文提示词,描述道具的外观细节,适用于 AI 道具图生成
-
- /
- \`desc\`:包含外观形状、颜色材质、尺寸参考、特殊效果等视觉要素
- \`prompt\`:英文提示词,描述道具的外观细节,适用于 AI 道具图生成
-
## prompt
## prompt
- /
- ****
- anime style, manga style
- prompt \`a young man, sharp eyebrows, black hair, pale skin, wearing a gray Taoist robe, slender build, cold expression\`
- prompt \`dark cave interior, glowing crystals on walls, misty atmosphere, dim blue lighting, stone altar in center\`
- prompt \`ancient jade pendant, oval shape, translucent green, carved dragon pattern, glowing faintly\`
- /
- ****
- anime style, manga style
- prompt \`a young man, sharp eyebrows, black hair, pale skin, wearing a gray Taoist robe, slender build, cold expression\`
- prompt \`dark cave interior, glowing crystals on walls, misty atmosphere, dim blue lighting, stone altar in center\`
- prompt \`ancient jade pendant, oval shape, translucent green, carved dragon pattern, glowing faintly\`
##
##
1.
2. \`name\`\`desc\`\`prompt\`\`type\`
3.
4. ** \`resultTool\` 工具输出完整资产列表**,不要分多次调用,一次性将所有资产放入 \`assetsList\` 数组中提交
1.
2. \`name\`\`desc\`\`prompt\`\`type\`
3.
4. ** \`resultTool\` 工具输出完整资产列表**,不要分多次调用,一次性将所有资产放入 \`assetsList\` 数组中提交
##
##
1. ****
2. ****便 AI
3. ****
4. **** role/scene/tool
5. **** AI
1. ****
2. ****便 AI
3. ****
4. **** role/scene/tool
5. **** AI
##
##
- ****使
-
-
- ****使
-
-
`,
},
]);

View File

@ -110,16 +110,20 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
try {
const aiImage = u.Ai.Image(model);
await aiImage.run({
await aiImage.run(
{
prompt: userPrompt,
imageBase64: item.base64 ? [item.base64] : [],
size: resolution,
aspectRatio: "16:9",
},
{
taskClass: cfg.taskClass,
describe,
projectId,
relatedObjects: JSON.stringify(relatedObjects),
});
},
);
aiImage.save(imagePath);
const imageData = await u.db("o_image").where("id", imageId).select("*").first();

View File

@ -98,16 +98,20 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
try {
// 4. 调用 AI 生成图片
const aiImage = u.Ai.Image(model);
await aiImage.run({
await aiImage.run(
{
prompt: userPrompt,
imageBase64: base64 ? [base64] : [],
size: resolution,
aspectRatio: "16:9",
},
{
taskClass: cfg.taskClass,
describe,
projectId,
relatedObjects: JSON.stringify(relatedObjects),
});
},
);
aiImage.save(imagePath);
// 5. 更新记录 & 返回结果

View File

@ -105,8 +105,8 @@ export default router.post(
console.log("%c Line:110 🍑 prompt", "background:#b03734", prompt);
const aiVideo = u.Ai.Video(model);
await aiVideo.run({
projectId,
await aiVideo.run(
{
prompt,
imageBase64: base64.filter((item) => item !== null) as string[],
mode,
@ -114,10 +114,14 @@ export default router.post(
aspectRatio: (ratio?.videoRatio as `${number}:${number}`) || "16:9",
resolution,
audio,
},
{
projectId,
taskClass: "视频生成",
describe: "根据提示词生成视频",
relatedObjects: JSON.stringify(relatedObjects),
});
},
);
await aiVideo.save(videoPath);
await u.db("o_video").where("id", videoId).update({ state: "生成成功" });
// await u.db("o_videoConfig").where("storyboardId", storyboardId).update({ videoId, updateTime: Date.now() });

View File

@ -1,8 +1,4 @@
<<<<<<< HEAD
// @db-hash 93b2462070c45c2b449e9a18c4e88763
=======
// @db-hash 24748d4ef971381a79c720c846f83847
>>>>>>> 796947cef173e7fe2f96e21fa8aeae23ff0fdf4a
//该文件由脚本自动生成,请勿手动修改
export interface memories {
@ -182,6 +178,7 @@ export interface o_storyboard {
'sound'?: string | null;
'state'?: string | null;
'title'?: string | null;
'videoPrompt'?: string | null;
}
export interface o_tasks {
'describe'?: string | null;

View File

@ -25,23 +25,10 @@ async function getVendorTemplateFn(fnName: FnName, modelName: `${string}:${strin
const selectedModel = modelList.find((i: any) => i.modelName == name);
if (!selectedModel) throw new Error(`未找到模型 ${name} id=${id}`);
const jsCode = transform(vendorConfigData.code!, { transforms: ["typescript"] }).code;
const running = u.vm(jsCode);
Object.assign(running.vendor.inputValues, JSON.parse(vendorConfigData.inputValues ?? "{}"));
running.vendor.models = modelList;
const fn = running[fnName];
const fn = u.vm(jsCode)[fnName];
if (!fn) throw new Error(`未找到供应商配置中的函数 ${fnName} id=${id}`);
if (fnName == "textRequest") {
const model = fn(selectedModel);
if (!model) throw new Error(`供应商 textRequest 返回无效模型 id=${id}`);
return model;
}
return async <T>(input: T) => {
const result = await fn(input, selectedModel);
if (result === undefined || result === null) {
throw new Error(`供应商函数 ${fnName} 未返回有效结果 id=${id}`);
}
return result;
};
if (fnName == "textRequest") return fn(selectedModel);
else return <T>(input: T) => fn(input, selectedModel);
}
async function withTaskRecord<T>(
@ -113,6 +100,9 @@ interface ImageConfig {
imageBase64: string[]; //输入的图片提示词
size: "1K" | "2K" | "4K"; // 图片尺寸
aspectRatio: `${number}:${number}`; // 长宽比
}
interface TaskRecord {
taskClass: string; // 任务分类
describe: string; // 任务描述
relatedObjects: string; // 相关对象信息,便于后续分析和追踪
@ -125,8 +115,8 @@ class AiImage {
constructor(key: `${string}:${string}`) {
this.key = key;
}
async run(input: ImageConfig) {
return withTaskRecord(this.key, input.taskClass, input.describe, input.relatedObjects, input.projectId, async (modelName) => {
async run(input: ImageConfig, taskRecord: TaskRecord) {
return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, async (modelName) => {
const fn = await getVendorTemplateFn("imageRequest", modelName);
this.result = await fn(input);
if (this.result.startsWith("http")) this.result = await urlToBase64(this.result);
@ -139,7 +129,6 @@ class AiImage {
}
}
interface VideoConfig {
projectId: number; // 项目ID
prompt: string; //视频提示词
imageBase64: string[]; //输入的图片提示词
aspectRatio: `${number}:${number}`; // 长宽比
@ -147,9 +136,6 @@ interface VideoConfig {
duration: number; // 视频时长,单位秒
resolution: string; // 视频分辨率
audio: boolean; // 是否需要配音
taskClass: string; // 任务分类
describe: string; // 任务描述
relatedObjects: string; // 相关对象信息,便于后续分析和追踪
}
class AiVideo {
@ -158,8 +144,8 @@ class AiVideo {
constructor(key: `${string}:${string}`) {
this.key = key;
}
async run(input: VideoConfig) {
return withTaskRecord(this.key, input.taskClass, input.describe, input.relatedObjects, input.projectId, async (modelName) => {
async run(input: VideoConfig, taskRecord: TaskRecord) {
return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, async (modelName) => {
const fn = await getVendorTemplateFn("videoRequest", modelName);
this.result = await fn(input);
if (this.result.startsWith("http")) this.result = await urlToBase64(this.result);
@ -177,8 +163,8 @@ class AiAudio {
constructor(key: `${string}:${string}`) {
this.key = key;
}
async run(input: VideoConfig) {
return withTaskRecord(this.key, input.taskClass, input.describe, input.relatedObjects, input.projectId, async (modelName) => {
async run(input: VideoConfig, taskRecord: TaskRecord) {
return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, async (modelName) => {
const fn = await getVendorTemplateFn("ttsRequest", modelName);
this.result = await fn(input);
if (this.result.startsWith("http")) this.result = await urlToBase64(this.result);