diff --git a/data/web/index.html b/data/web/index.html index 5bdb86b..73fbb89 100644 --- a/data/web/index.html +++ b/data/web/index.html @@ -5,74 +5,74 @@ Toonflow - - + `),JDs=/enable|requires|diagnostic/,b2n=new RegExp("[_\\p{XID_Start}]\\p{XID_Continue}*","u"),JP="variable.predefined",eBs={tokenPostfix:".wgsl",defaultToken:"invalid",unicode:!0,atoms:zDs,keywords:HDs,reserved:$Ds,predeclared_enums:XDs,predeclared_types:GDs,predeclared_type_generators:YDs,predeclared_type_aliases:ZDs,predeclared_intrinsics:qDs,operators:KDs,symbols:/[!%&*+\-\.\/:;<=>^|_~,]+/,tokenizer:{root:[[JDs,"keyword","@directive"],[b2n,{cases:{"@atoms":JP,"@keywords":"keyword","@reserved":"invalid","@predeclared_enums":JP,"@predeclared_types":JP,"@predeclared_type_generators":JP,"@predeclared_type_aliases":JP,"@predeclared_intrinsics":JP,"@default":"identifier"}}],{include:"@commentOrSpace"},{include:"@numbers"},[/[{}()\[\]]/,"@brackets"],["@","annotation","@attribute"],[/@symbols/,{cases:{"@operators":"operator","@default":"delimiter"}}],[/./,"invalid"]],commentOrSpace:[[/\s+/,"white"],[/\/\*/,"comment","@blockComment"],[/\/\/.*$/,"comment"]],blockComment:[[/[^\/*]+/,"comment"],[/\/\*/,"comment","@push"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],attribute:[{include:"@commentOrSpace"},[/\w+/,"annotation","@pop"]],directive:[{include:"@commentOrSpace"},[/[()]/,"@brackets"],[/,/,"delimiter"],[b2n,"meta.content"],[/;/,"delimiter","@pop"]],numbers:[[/0[fh]/,"number.float"],[/[1-9][0-9]*[fh]/,"number.float"],[/[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[fh]?/,"number.float"],[/[0-9]+\.[0-9]*([eE][+-]?[0-9]+)?[fh]?/,"number.float"],[/[0-9]+[eE][+-]?[0-9]+[fh]?/,"number.float"],[/0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+(?:[pP][+-]?[0-9]+[fh]?)?/,"number.hex"],[/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*(?:[pP][+-]?[0-9]+[fh]?)?/,"number.hex"],[/0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+[fh]?/,"number.hex"],[/0[xX][0-9a-fA-F]+[iu]?/,"number.hex"],[/[1-9][0-9]*[iu]?/,"number"],[/0[iu]?/,"number"]]}},tBs=Object.freeze(Object.defineProperty({__proto__:null,conf:VDs,language:eBs},Symbol.toStringTag,{value:"Module"})),nBs={comments:{blockComment:["\x3C!--","-->"]},brackets:[["<",">"]],autoClosingPairs:[{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}],surroundingPairs:[{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}],onEnterRules:[{beforeText:new RegExp("<([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$","i"),afterText:/^<\/([_:\w][_:\w-.\d]*)\s*>$/i,action:{indentAction:Et.IndentAction.IndentOutdent}},{beforeText:new RegExp("<(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$","i"),action:{indentAction:Et.IndentAction.Indent}}]},iBs={defaultToken:"",tokenPostfix:".xml",ignoreCase:!0,qualifiedName:/(?:[\w\.\-]+:)?[\w\.\-]+/,tokenizer:{root:[[/[^<&]+/,""],{include:"@whitespace"},[/(<)(@qualifiedName)/,[{token:"delimiter"},{token:"tag",next:"@tag"}]],[/(<\/)(@qualifiedName)(\s*)(>)/,[{token:"delimiter"},{token:"tag"},"",{token:"delimiter"}]],[/(<\?)(@qualifiedName)/,[{token:"delimiter"},{token:"metatag",next:"@tag"}]],[/(<\!)(@qualifiedName)/,[{token:"delimiter"},{token:"metatag",next:"@tag"}]],[/<\!\[CDATA\[/,{token:"delimiter.cdata",next:"@cdata"}],[/&\w+;/,"string.escape"]],cdata:[[/[^\]]+/,""],[/\]\]>/,{token:"delimiter.cdata",next:"@pop"}],[/\]/,""]],tag:[[/[ \t\r\n]+/,""],[/(@qualifiedName)(\s*=\s*)("[^"]*"|'[^']*')/,["attribute.name","","attribute.value"]],[/(@qualifiedName)(\s*=\s*)("[^">?\/]*|'[^'>?\/]*)(?=[\?\/]\>)/,["attribute.name","","attribute.value"]],[/(@qualifiedName)(\s*=\s*)("[^">]*|'[^'>]*)/,["attribute.name","","attribute.value"]],[/@qualifiedName/,"attribute.name"],[/\?>/,{token:"delimiter",next:"@pop"}],[/(\/)(>)/,[{token:"tag"},{token:"delimiter",next:"@pop"}]],[/>/,{token:"delimiter",next:"@pop"}]],whitespace:[[/[ \t\r\n]+/,""],[/\x3C!--/,{token:"comment",next:"@comment"}]],comment:[[/[^<\-]+/,"comment.content"],[/-->/,{token:"comment",next:"@pop"}],[/\x3C!--/,"comment.content.invalid"],[/[<\-]/,"comment.content"]]}},rBs=Object.freeze(Object.defineProperty({__proto__:null,conf:nBs,language:iBs},Symbol.toStringTag,{value:"Module"})),oBs={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{offSide:!0},onEnterRules:[{beforeText:/:\s*$/,action:{indentAction:Et.IndentAction.Indent}}]},sBs={tokenPostfix:".yaml",brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.square",open:"[",close:"]"}],keywords:["true","True","TRUE","false","False","FALSE","null","Null","Null","~"],numberInteger:/(?:0|[+-]?[0-9]+)/,numberFloat:/(?:0|[+-]?[0-9]+)(?:\.[0-9]+)?(?:e[-+][1-9][0-9]*)?/,numberOctal:/0o[0-7]+/,numberHex:/0x[0-9a-fA-F]+/,numberInfinity:/[+-]?\.(?:inf|Inf|INF)/,numberNaN:/\.(?:nan|Nan|NAN)/,numberDate:/\d{4}-\d\d-\d\d([Tt ]\d\d:\d\d:\d\d(\.\d+)?(( ?[+-]\d\d?(:\d\d)?)|Z)?)?/,escapes:/\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/,tokenizer:{root:[{include:"@whitespace"},{include:"@comment"},[/%[^ ]+.*$/,"meta.directive"],[/---/,"operators.directivesEnd"],[/\.{3}/,"operators.documentEnd"],[/[-?:](?= )/,"operators"],{include:"@anchor"},{include:"@tagHandle"},{include:"@flowCollections"},{include:"@blockStyle"},[/@numberInteger(?![ \t]*\S+)/,"number"],[/@numberFloat(?![ \t]*\S+)/,"number.float"],[/@numberOctal(?![ \t]*\S+)/,"number.octal"],[/@numberHex(?![ \t]*\S+)/,"number.hex"],[/@numberInfinity(?![ \t]*\S+)/,"number.infinity"],[/@numberNaN(?![ \t]*\S+)/,"number.nan"],[/@numberDate(?![ \t]*\S+)/,"number.date"],[/(".*?"|'.*?'|[^#'"]*?)([ \t]*)(:)( |$)/,["type","white","operators","white"]],{include:"@flowScalars"},[/.+?(?=(\s+#|$))/,{cases:{"@keywords":"keyword","@default":"string"}}]],object:[{include:"@whitespace"},{include:"@comment"},[/\}/,"@brackets","@pop"],[/,/,"delimiter.comma"],[/:(?= )/,"operators"],[/(?:".*?"|'.*?'|[^,\{\[]+?)(?=: )/,"type"],{include:"@flowCollections"},{include:"@flowScalars"},{include:"@tagHandle"},{include:"@anchor"},{include:"@flowNumber"},[/[^\},]+/,{cases:{"@keywords":"keyword","@default":"string"}}]],array:[{include:"@whitespace"},{include:"@comment"},[/\]/,"@brackets","@pop"],[/,/,"delimiter.comma"],{include:"@flowCollections"},{include:"@flowScalars"},{include:"@tagHandle"},{include:"@anchor"},{include:"@flowNumber"},[/[^\],]+/,{cases:{"@keywords":"keyword","@default":"string"}}]],multiString:[[/^( +).+$/,"string","@multiStringContinued.$1"]],multiStringContinued:[[/^( *).+$/,{cases:{"$1==$S2":"string","@default":{token:"@rematch",next:"@popall"}}}]],whitespace:[[/[ \t\r\n]+/,"white"]],comment:[[/#.*$/,"comment"]],flowCollections:[[/\[/,"@brackets","@array"],[/\{/,"@brackets","@object"]],flowScalars:[[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/'[^']*'/,"string"],[/"/,"string","@doubleQuotedString"]],doubleQuotedString:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],blockStyle:[[/[>|][0-9]*[+-]?$/,"operators","@multiString"]],flowNumber:[[/@numberInteger(?=[ \t]*[,\]\}])/,"number"],[/@numberFloat(?=[ \t]*[,\]\}])/,"number.float"],[/@numberOctal(?=[ \t]*[,\]\}])/,"number.octal"],[/@numberHex(?=[ \t]*[,\]\}])/,"number.hex"],[/@numberInfinity(?=[ \t]*[,\]\}])/,"number.infinity"],[/@numberNaN(?=[ \t]*[,\]\}])/,"number.nan"],[/@numberDate(?=[ \t]*[,\]\}])/,"number.date"]],tagHandle:[[/\![^ ]*/,"tag"]],anchor:[[/[&*][^ ]+/,"namespace"]]}},aBs=Object.freeze(Object.defineProperty({__proto__:null,conf:oBs,language:sBs},Symbol.toStringTag,{value:"Module"})); +
diff --git a/package.json b/package.json index 715e75a..741b792 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "knex": "^3.2.5", "lodash": "^4.17.23", "morgan": "^1.10.1", + "p-limit": "^7.3.0", "qwen-ai-provider-v5": "^2.1.0", "serialize-error": "^13.0.1", "sharp": "^0.34.5", diff --git a/src/agents/productionAgent/index.ts b/src/agents/productionAgent/index.ts index af036e1..431f91a 100644 --- a/src/agents/productionAgent/index.ts +++ b/src/agents/productionAgent/index.ts @@ -51,7 +51,7 @@ export async function decisionAI(ctx: AgentContext) { const { textStream } = await u.Ai.Text("productionAgent").stream({ messages: [ { role: "system", content: prompt }, - { role: "system", content: mem }, + { role: "assistant", content: mem }, { role: "user", content: text }, ], abortSignal, @@ -174,8 +174,8 @@ function createSubAgent(parentCtx: AgentContext) { } async function createArtSkills(artName: string) { - const path = u.getPath(["skills", "art_prompts", artName, "driector_skills"]); - const skillList = await scanSkills(path + "/*.md"); + const workerPath = u.getPath(["skills", "art_prompts", artName, "driector_skills"]); + const skillList = await scanSkills(workerPath + "/*.md"); const mainSkills: { path: string; name: string; description: string }[] = []; for (const skillPath of skillList) { if (!fs.existsSync(skillPath)) throw new Error(`主技能文件不存在: ${skillPath}`); @@ -183,8 +183,9 @@ async function createArtSkills(artName: string) { const parsed = parseFrontmatter(content); mainSkills.push({ path: skillPath, ...parsed }); } - return { + const res = { prompt: buildSkillPrompt(mainSkills), - tools: createSkillTools(mainSkills, { mainSkill: mainSkills, secondarySkills: [], tertiarySkills: [] }), + tools: createSkillTools(mainSkills, { mainSkill: mainSkills, secondarySkills: [], tertiarySkills: [] },workerPath), }; -} + return res +} \ No newline at end of file diff --git a/src/agents/productionAgent/tools.ts b/src/agents/productionAgent/tools.ts index 41f954c..b3fc52b 100644 --- a/src/agents/productionAgent/tools.ts +++ b/src/agents/productionAgent/tools.ts @@ -53,7 +53,7 @@ const posterItemSchema = z.object({ id: z.number().describe("海报ID"), image: z.string().describe("海报图片路径"), }); -const flowDataSchema = z.object({ +export const flowDataSchema = z.object({ script: z.string().describe("剧本内容"), scriptPlan: z.string().describe("拍摄计划"), assets: z.array(assetItemSchema).describe("衍生资产"), @@ -150,7 +150,6 @@ export default (toolCpnfig: ToolConfig) => { return res ?? "删除成功"; }, }), - generate_deriveAsset: tool({ description: "生成衍生资产", inputSchema: z.object({ diff --git a/src/agents/scriptAgent/index.ts b/src/agents/scriptAgent/index.ts index de24001..ea57518 100644 --- a/src/agents/scriptAgent/index.ts +++ b/src/agents/scriptAgent/index.ts @@ -139,7 +139,7 @@ function createSubAgent(parentCtx: AgentContext) { const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ prompt, - system: systemPrompt + "你可以使用如下XML格式写入工作区:\n故事骨架内容", + system: systemPrompt + "\n你可以使用如下XML格式写入工作区:\n故事骨架内容", name: "编剧", memoryKey: "assistant:execution:storySkeleton", }); @@ -154,7 +154,7 @@ function createSubAgent(parentCtx: AgentContext) { const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ prompt, - system: systemPrompt + "你可以使用如下XML格式写入工作区:\n改编策略内容", + system: systemPrompt + "\n你可以使用如下XML格式写入工作区:\n改编策略内容", name: "编剧", memoryKey: "assistant:execution:adaptationStrategy", }); @@ -171,7 +171,7 @@ function createSubAgent(parentCtx: AgentContext) { prompt, system: systemPrompt + - `你可以使用如下XML格式写入工作区:\nXML不得添加任何额外标签`, + `\n你可以使用如下XML格式写入工作区:\nXML不得添加任何额外标签`, name: "编剧", memoryKey: "assistant:execution:script", }); diff --git a/src/router.ts b/src/router.ts index f9af96f..efdce9e 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash 8d0bd75a9e06280f64490cd32d7a5b2e +// @routes-hash fc02af7340ae26f567792eda4cde50a6 import { Express } from "express"; import route1 from "./routes/agents/clearMemory"; @@ -59,36 +59,36 @@ import route55 from "./routes/production/getStoryboardData"; import route56 from "./routes/production/saveFlowData"; import route57 from "./routes/production/storyboard/batchGenerateImage"; import route58 from "./routes/production/storyboard/downPreviewImage"; -import route59 from "./routes/production/storyboard/generatestory2Image"; -import route60 from "./routes/production/storyboard/getStoryboardData"; -import route61 from "./routes/production/storyboard/pollingImage"; -import route62 from "./routes/production/storyboard/previewImage"; -import route63 from "./routes/production/workbench/confirmSelection"; -import route64 from "./routes/production/workbench/delVideo"; -import route65 from "./routes/production/workbench/generateVideo"; -import route66 from "./routes/production/workbench/generateVideoPrompt"; -import route67 from "./routes/production/workbench/getChatLines"; -import route68 from "./routes/production/workbench/getVideoModelDetail"; -import route69 from "./routes/production/workbench/videoPolling"; -import route70 from "./routes/project/addProject"; -import route71 from "./routes/project/addVisual"; -import route72 from "./routes/project/addVisualManual"; -import route73 from "./routes/project/deleteVisualManual"; -import route74 from "./routes/project/delProject"; -import route75 from "./routes/project/editProject"; -import route76 from "./routes/project/editVisualManual"; -import route77 from "./routes/project/getProject"; -import route78 from "./routes/project/getVisualManual"; -import route79 from "./routes/project/visualManual"; -import route80 from "./routes/script/addScript"; -import route81 from "./routes/script/delScript"; -import route82 from "./routes/script/exportScript"; -import route83 from "./routes/script/extractAssets"; -import route84 from "./routes/script/getScrptApi"; -import route85 from "./routes/script/pollScriptAssets"; -import route86 from "./routes/script/updateScript"; -import route87 from "./routes/scriptAgent/getPlanData"; -import route88 from "./routes/scriptAgent/setPlanData"; +import route59 from "./routes/production/storyboard/getStoryboardData"; +import route60 from "./routes/production/storyboard/pollingImage"; +import route61 from "./routes/production/storyboard/previewImage"; +import route62 from "./routes/production/workbench/confirmSelection"; +import route63 from "./routes/production/workbench/delVideo"; +import route64 from "./routes/production/workbench/generateVideo"; +import route65 from "./routes/production/workbench/generateVideoPrompt"; +import route66 from "./routes/production/workbench/getChatLines"; +import route67 from "./routes/production/workbench/getVideoModelDetail"; +import route68 from "./routes/production/workbench/videoPolling"; +import route69 from "./routes/project/addProject"; +import route70 from "./routes/project/addVisual"; +import route71 from "./routes/project/addVisualManual"; +import route72 from "./routes/project/deleteVisualManual"; +import route73 from "./routes/project/delProject"; +import route74 from "./routes/project/editProject"; +import route75 from "./routes/project/editVisualManual"; +import route76 from "./routes/project/getProject"; +import route77 from "./routes/project/getVisualManual"; +import route78 from "./routes/project/visualManual"; +import route79 from "./routes/script/addScript"; +import route80 from "./routes/script/delScript"; +import route81 from "./routes/script/exportScript"; +import route82 from "./routes/script/extractAssets"; +import route83 from "./routes/script/getScrptApi"; +import route84 from "./routes/script/pollScriptAssets"; +import route85 from "./routes/script/updateScript"; +import route86 from "./routes/scriptAgent/getPlanData"; +import route87 from "./routes/scriptAgent/setPlanData"; +import route88 from "./routes/scriptAgent/updateData"; import route89 from "./routes/setting/about/checkUpdate"; import route90 from "./routes/setting/about/downloadApp"; import route91 from "./routes/setting/agentDeploy/agentSetKey"; @@ -180,36 +180,36 @@ export default async (app: Express) => { app.use("/api/production/saveFlowData", route56); app.use("/api/production/storyboard/batchGenerateImage", route57); app.use("/api/production/storyboard/downPreviewImage", route58); - app.use("/api/production/storyboard/generatestory2Image", route59); - app.use("/api/production/storyboard/getStoryboardData", route60); - app.use("/api/production/storyboard/pollingImage", route61); - app.use("/api/production/storyboard/previewImage", route62); - app.use("/api/production/workbench/confirmSelection", route63); - app.use("/api/production/workbench/delVideo", route64); - app.use("/api/production/workbench/generateVideo", route65); - app.use("/api/production/workbench/generateVideoPrompt", route66); - app.use("/api/production/workbench/getChatLines", route67); - app.use("/api/production/workbench/getVideoModelDetail", route68); - app.use("/api/production/workbench/videoPolling", route69); - app.use("/api/project/addProject", route70); - app.use("/api/project/addVisual", route71); - app.use("/api/project/addVisualManual", route72); - app.use("/api/project/deleteVisualManual", route73); - app.use("/api/project/delProject", route74); - app.use("/api/project/editProject", route75); - app.use("/api/project/editVisualManual", route76); - app.use("/api/project/getProject", route77); - app.use("/api/project/getVisualManual", route78); - app.use("/api/project/visualManual", route79); - app.use("/api/script/addScript", route80); - app.use("/api/script/delScript", route81); - app.use("/api/script/exportScript", route82); - app.use("/api/script/extractAssets", route83); - app.use("/api/script/getScrptApi", route84); - app.use("/api/script/pollScriptAssets", route85); - app.use("/api/script/updateScript", route86); - app.use("/api/scriptAgent/getPlanData", route87); - app.use("/api/scriptAgent/setPlanData", route88); + app.use("/api/production/storyboard/getStoryboardData", route59); + app.use("/api/production/storyboard/pollingImage", route60); + app.use("/api/production/storyboard/previewImage", route61); + app.use("/api/production/workbench/confirmSelection", route62); + app.use("/api/production/workbench/delVideo", route63); + app.use("/api/production/workbench/generateVideo", route64); + app.use("/api/production/workbench/generateVideoPrompt", route65); + app.use("/api/production/workbench/getChatLines", route66); + app.use("/api/production/workbench/getVideoModelDetail", route67); + app.use("/api/production/workbench/videoPolling", route68); + app.use("/api/project/addProject", route69); + app.use("/api/project/addVisual", route70); + app.use("/api/project/addVisualManual", route71); + app.use("/api/project/deleteVisualManual", route72); + app.use("/api/project/delProject", route73); + app.use("/api/project/editProject", route74); + app.use("/api/project/editVisualManual", route75); + app.use("/api/project/getProject", route76); + app.use("/api/project/getVisualManual", route77); + app.use("/api/project/visualManual", route78); + app.use("/api/script/addScript", route79); + app.use("/api/script/delScript", route80); + app.use("/api/script/exportScript", route81); + app.use("/api/script/extractAssets", route82); + app.use("/api/script/getScrptApi", route83); + app.use("/api/script/pollScriptAssets", route84); + app.use("/api/script/updateScript", route85); + app.use("/api/scriptAgent/getPlanData", route86); + app.use("/api/scriptAgent/setPlanData", route87); + app.use("/api/scriptAgent/updateData", route88); app.use("/api/setting/about/checkUpdate", route89); app.use("/api/setting/about/downloadApp", route90); app.use("/api/setting/agentDeploy/agentSetKey", route91); diff --git a/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts b/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts index 7f42327..130f7c0 100644 --- a/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts +++ b/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts @@ -111,7 +111,6 @@ export default router.post( 请根据以下参数生成${config.label}提示词: **基础参数:** - - 风格: ${project?.artStyle || "未指定"} - 小说类型: ${project?.type || "未指定"} - 小说背景: ${project?.intro || "未指定"} diff --git a/src/routes/production/assets/batchGenerateAssetsImage.ts b/src/routes/production/assets/batchGenerateAssetsImage.ts index 7d4e840..a65b413 100644 --- a/src/routes/production/assets/batchGenerateAssetsImage.ts +++ b/src/routes/production/assets/batchGenerateAssetsImage.ts @@ -60,7 +60,6 @@ export default router.post( }, ], }); - console.log("%c Line:35 🎂 text", "background:#3f7cff", text); const repeloadObj = { prompt: text, diff --git a/src/routes/production/exportImage.ts b/src/routes/production/exportImage.ts index cfd52ae..cd61be6 100644 --- a/src/routes/production/exportImage.ts +++ b/src/routes/production/exportImage.ts @@ -5,7 +5,6 @@ import { success } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; const router = express.Router(); import compressing from "compressing"; -import { flowDataSchema } from "@/agents/productionAgent/tools"; import path from "path"; import getPath from "@/utils/getPath"; diff --git a/src/routes/production/workbench/generateVideo.ts b/src/routes/production/workbench/generateVideo.ts index 2091683..cb38602 100644 --- a/src/routes/production/workbench/generateVideo.ts +++ b/src/routes/production/workbench/generateVideo.ts @@ -102,6 +102,7 @@ export default router.post( 3. 视频风格应与用户指定的模式数据相匹配,包括色彩、音乐、特效等元素。 4. 视频中应包含用户提供的图片,并在视频中适当展示,以增强视频的视觉效果。 5. 如果用户指定了音频,请确保视频中的音频与视频内容相匹配,符合用户的创意意图。`; + console.log("%c Line:110 🍑 prompt", "background:#b03734", prompt); const aiVideo = u.Ai.Video(model); await aiVideo.run({ diff --git a/src/routes/production/workbench/generateVideoPrompt.ts b/src/routes/production/workbench/generateVideoPrompt.ts index 70e5dde..24320a2 100644 --- a/src/routes/production/workbench/generateVideoPrompt.ts +++ b/src/routes/production/workbench/generateVideoPrompt.ts @@ -3,60 +3,55 @@ import u from "@/utils"; import { z } from "zod"; import { success } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; -import { Output } from "ai"; const router = express.Router(); export default router.post( "/", validateFields({ projectId: z.number(), - storyboardId: z.array(z.number()), + storyboardId: z.number(), }), async (req, res) => { const { projectId, storyboardId } = req.body; + // 查询分镜及其关联的资产提示词 const data = await u .db("o_storyboard") .leftJoin("o_assets2Storyboard", "o_storyboard.id", "o_assets2Storyboard.storyboardId") .leftJoin("o_assets", "o_assets2Storyboard.assetId", "o_assets.id") .leftJoin("o_videoConfig", "o_storyboard.id", "o_videoConfig.storyboardId") - .whereIn("o_storyboard.id", storyboardId) + .where("o_storyboard.id", storyboardId) .select("o_storyboard.id", "o_storyboard.prompt", "o_assets.prompt as assetPrompt", "o_videoConfig.model as videoModel"); - // 按分镜id分组,聚合资产提示词 - const storyboardMap = new Map(); - for (const row of data) { - if (!storyboardMap.has(row.id)) { - storyboardMap.set(row.id, { prompt: row.prompt || "", assetPrompts: [], videoModel: row.videoModel || "" }); - } - if (row.assetPrompt) { - storyboardMap.get(row.id)!.assetPrompts.push(row.assetPrompt); - } + if (data.length === 0) { + return res.status(200).send(success({ data: null })); } - // 逐个分镜生成视频提示词 - const results: { storyboardId: number; videoPrompt: string }[] = []; - for (const [id, { prompt, assetPrompts, videoModel }] of storyboardMap) { - let model = ""; - if (videoModel) { - model = videoModel; - } else { - const videoModel = await u.db("o_project").where("id", projectId).select("videoModel").first(); - model = videoModel?.videoModel || ""; - } - if (!model) return res.status(400).json({ error: "未找到视频模型,请检查项目配置" }); - const systemPrompt = `你是一个专业的${model}视频生成助手。请根据分镜提示词和关联资产提示词,生成一段完整的、可直接用于视频生成模型的中文提示词。`; - const userContent = `分镜提示词:${prompt || "无"}\n资产提示词:${assetPrompts.length > 0 ? assetPrompts.join("\n") : "无"}`; + // 聚合资产提示词 + const prompt = data[0].prompt || ""; + const videoModel = data[0].videoModel || ""; + const assetPrompts = data.map((row) => row.assetPrompt).filter(Boolean) as string[]; - const { text } = await u.Ai.Text("universalAi").invoke({ - system: systemPrompt, - messages: [{ role: "user", content: userContent }], - }); - - await u.db("o_storyboard").where("id", id).update({ videoPrompt: text }); - results.push({ storyboardId: id, videoPrompt: text }); + // 确定视频模型 + let model = videoModel; + if (!model) { + const project = await u.db("o_project").where("id", projectId).select("videoModel").first(); + model = project?.videoModel || ""; + } + if (!model) { + return res.status(200).send(success({ data: null })); } - res.status(200).send(success({ data: results })); + const systemPrompt = `你是一个专业的${model}视频生成助手。请根据分镜提示词和关联资产提示词,生成一段完整的、可直接用于视频生成模型的中文提示词。`; + const userContent = `分镜提示词:${prompt || "无"}\n资产提示词:${assetPrompts.length > 0 ? assetPrompts.join("\n") : "无"}`; + + const { text } = await u.Ai.Text("universalAi").invoke({ + system: systemPrompt, + messages: [{ role: "user", content: userContent }], + }); + + await u.db("o_storyboard").where("id", storyboardId).update({ videoPrompt: text }); + + res.status(200).send(success({ data: { storyboardId, videoPrompt: text } })); }, ); diff --git a/src/routes/script/extractAssets.ts b/src/routes/script/extractAssets.ts index 4acfc05..8aa7d4d 100644 --- a/src/routes/script/extractAssets.ts +++ b/src/routes/script/extractAssets.ts @@ -63,17 +63,34 @@ export default router.post( if (!scriptIds.length) return res.status(400).send(error("请先选择剧本")); const scripts = await u.db("o_script").whereIn("id", scriptIds); const intansce = u.Ai.Text("universalAi"); - await u.db("o_script").whereIn("id", scriptIds).update({ - extractState: 0, - }); + + // 查询已有的剧本-资产关联,找出已经提取过资产的剧本 + const existingScriptAssets = await u.db("o_scriptAssets").whereIn("scriptId", scriptIds).select("scriptId"); + const scriptIdsWithAssets = new Set(existingScriptAssets.map((sa: any) => sa.scriptId)); + // 构建 scriptId -> script 内容的映射 const scriptMap = new Map(scripts.map((s: o_script) => [s.id, s])); + // 过滤掉已成功提取过资产的剧本(extractState === 1 且有关联资产) + const filteredScriptIds = scriptIds.filter((id: number) => { + const script = scriptMap.get(id); + return !(script?.extractState === 1 && scriptIdsWithAssets.has(id)); + }); + const skippedCount = scriptIds.length - filteredScriptIds.length; + + if (!filteredScriptIds.length) { + return res.send(success("所有剧本已提取过资产,无需重复提取")); + } + + await u.db("o_script").whereIn("id", filteredScriptIds).update({ + extractState: 0, + }); + const errors: { scriptId: number; error: string }[] = []; let successCount = 0; - // 将 scriptIds 按 groupSize(默认5)分组,每组一起发给 AI - const scriptGroups = chunkArray(scriptIds, groupSize); + // 将过滤后的 scriptIds 按 groupSize(默认5)分组,每组一起发给 AI + const scriptGroups = chunkArray(filteredScriptIds, groupSize); /** 一组剧本提取完成后统一入库并建立关联 */ async function persistGroupResult(result: GroupResult) { @@ -157,9 +174,7 @@ export default router.post( // 查询当前项目已有的资产列表,提供给 AI 参考 const existingAssets = await u.db("o_assets").where("projectId", projectId).select("name", "type"); - console.log("%c Line:162 🍔 existingAssets", "background:#ea7e5c", existingAssets); const existingAssetsList = existingAssets.map((a) => `${a.name}(${a.type})`).join("、"); - console.log("%c Line:164 🍫 existingAssetsList", "background:#33a5ff", existingAssetsList); // 拼接多集剧本内容,每集用分隔标记 const scriptsContent = validScripts @@ -246,6 +261,6 @@ export default router.post( }); } - return res.send(success("开始提取资产")); + return res.send(success(skippedCount > 0 ? `开始提取资产,跳过 ${skippedCount} 个已提取的剧本` : "开始提取资产")); }, ); diff --git a/src/routes/scriptAgent/getPlanData.ts b/src/routes/scriptAgent/getPlanData.ts index 7f612ff..608af9b 100644 --- a/src/routes/scriptAgent/getPlanData.ts +++ b/src/routes/scriptAgent/getPlanData.ts @@ -34,6 +34,6 @@ export default router.post( const data = JSON.parse(row.data ?? "{}"); data.script = await u.db("o_script").where({ projectId }).select("id", "name", "content"); - res.status(200).send(success(data)); + res.status(200).send(success({ data, id: row.id })); }, ); diff --git a/src/routes/scriptAgent/updateData.ts b/src/routes/scriptAgent/updateData.ts new file mode 100644 index 0000000..5e5d3f5 --- /dev/null +++ b/src/routes/scriptAgent/updateData.ts @@ -0,0 +1,27 @@ +import express from "express"; +import { success } from "@/lib/responseFormat"; +import u from "@/utils"; +import { z } from "zod"; +import { validateFields } from "@/middleware/middleware"; +const router = express.Router(); + +export default router.post( + "/", + validateFields({ + id: z.number(), + data: z.object({ + storySkeleton: z.string(), + adaptationStrategy: z.string(), + }), + }), + async (req, res) => { + const { id, data } = req.body; + await u + .db("o_agentWorkData") + .where({ id: id }) + .update({ + data: JSON.stringify(data), + }); + res.status(200).send(success("更新成功")); + }, +); diff --git a/src/routes/setting/vendorConfig/addVendor.ts b/src/routes/setting/vendorConfig/addVendor.ts index 83cf3ca..09eb31a 100644 --- a/src/routes/setting/vendorConfig/addVendor.ts +++ b/src/routes/setting/vendorConfig/addVendor.ts @@ -1,5 +1,4 @@ import express from "express"; -import { serializeError } from "serialize-error"; import { success, error } from "@/lib/responseFormat"; import { validateFields } from "@/middleware/middleware"; import u from "@/utils"; @@ -29,14 +28,14 @@ const vendorConfigSchema = z.object({ name: z.string(), modelName: z.string(), type: z.literal("text"), - multimodal: z.boolean(), - tool: z.boolean(), + think: z.boolean(), }), z.object({ name: z.string(), modelName: z.string(), type: z.literal("image"), mode: z.array(z.enum(["text", "singleImage", "multiReference"])), + associationSkills:z.string().optional(), }), z.object({ name: z.string(), @@ -46,8 +45,6 @@ const vendorConfigSchema = z.object({ z.union([ z.enum([ "singleImage", - "multiImage", - "gridImage", "startEndRequired", "endFrameOptional", "startFrameOptional", @@ -55,7 +52,7 @@ const vendorConfigSchema = z.object({ "audioReference", "videoReference", ]), - z.array(z.enum(["video", "image", "audio", "text"])), + z.array(z.enum(["videoReference", "imageReference", "audioReference", "textReference"])), ]), ), audio: z.union([z.literal("optional"), z.boolean()]), diff --git a/src/routes/setting/vendorConfig/modelTest.ts b/src/routes/setting/vendorConfig/modelTest.ts index 495a24e..cc8749e 100644 --- a/src/routes/setting/vendorConfig/modelTest.ts +++ b/src/routes/setting/vendorConfig/modelTest.ts @@ -78,6 +78,7 @@ export default router.post( } res.status(200).send(success(fullResponse)); } else { + console.log("%c Line:83 🥔", "background:#e41a6a"); const aiTypeFn = { image: "Image", video: "Video", diff --git a/src/routes/setting/vendorConfig/updateCode.ts b/src/routes/setting/vendorConfig/updateCode.ts index aa1cf43..3f544e0 100644 --- a/src/routes/setting/vendorConfig/updateCode.ts +++ b/src/routes/setting/vendorConfig/updateCode.ts @@ -29,14 +29,14 @@ const vendorConfigSchema = z.object({ name: z.string(), modelName: z.string(), type: z.literal("text"), - multimodal: z.boolean(), - tool: z.boolean(), + think: z.boolean(), }), z.object({ name: z.string(), modelName: z.string(), type: z.literal("image"), mode: z.array(z.enum(["text", "singleImage", "multiReference"])), + associationSkills:z.string().optional(), }), z.object({ name: z.string(), @@ -46,8 +46,6 @@ const vendorConfigSchema = z.object({ z.union([ z.enum([ "singleImage", - "multiImage", - "gridImage", "startEndRequired", "endFrameOptional", "startFrameOptional", @@ -55,9 +53,10 @@ const vendorConfigSchema = z.object({ "audioReference", "videoReference", ]), - z.array(z.enum(["video", "image", "audio", "text"])), + z.array(z.enum(["audioReference", "videoReference", "textReference", "imageReference"])), ]), ), + associationSkills:z.string().optional(), audio: z.union([z.literal("optional"), z.boolean()]), durationResolutionMap: z.array( z.object({ diff --git a/src/routes/setting/vendorConfig/updateVendor.ts b/src/routes/setting/vendorConfig/updateVendor.ts index 71c7e42..0d066b8 100644 --- a/src/routes/setting/vendorConfig/updateVendor.ts +++ b/src/routes/setting/vendorConfig/updateVendor.ts @@ -6,69 +6,6 @@ import { z } from "zod"; import { transform } from "sucrase"; const router = express.Router(); -const vendorConfigSchema = z.object({ - id: z.string(), - author: z.string(), - description: z.string().optional(), - name: z.string(), - icon: z.string().optional(), - inputs: z.array( - z.object({ - key: z.string(), - label: z.string(), - type: z.enum(["text", "password", "url"]), - required: z.boolean(), - placeholder: z.string().optional(), - }), - ), - inputValues: z.record(z.string(), z.string()), - models: z.array( - z.discriminatedUnion("type", [ - z.object({ - name: z.string(), - modelName: z.string(), - type: z.literal("text"), - multimodal: z.boolean(), - tool: z.boolean(), - }), - z.object({ - name: z.string(), - modelName: z.string(), - type: z.literal("image"), - mode: z.array(z.enum(["text", "singleImage", "multiReference"])), - }), - z.object({ - name: z.string(), - modelName: z.string(), - type: z.literal("video"), - mode: z.array( - z.union([ - z.enum([ - "singleImage", - "multiImage", - "gridImage", - "startEndRequired", - "endFrameOptional", - "startFrameOptional", - "text", - "audioReference", - "videoReference", - ]), - z.array(z.enum(["video", "image", "audio", "text"])), - ]), - ), - audio: z.union([z.literal("optional"), z.boolean()]), - durationResolutionMap: z.array( - z.object({ - duration: z.array(z.number()), - resolution: z.array(z.string()), - }), - ), - }), - ]), - ), -}); - export default router.post( "/", validateFields({ @@ -89,14 +26,14 @@ export default router.post( name: z.string(), modelName: z.string(), type: z.literal("text"), - multimodal: z.boolean(), - tool: z.boolean(), + think: z.boolean(), }), z.object({ name: z.string(), modelName: z.string(), type: z.literal("image"), mode: z.array(z.enum(["text", "singleImage", "multiReference"])), + associationSkills: z.string().optional(), }), z.object({ name: z.string(), @@ -104,10 +41,11 @@ export default router.post( type: z.literal("video"), mode: z.array( z.union([ - z.enum(["singleImage", "multiImage", "gridImage", "startEndRequired", "endFrameOptional", "startFrameOptional", "text"]), + z.enum(["singleImage", "startEndRequired", "endFrameOptional", "startFrameOptional", "text"]), z.array(z.enum(["audioReference", "videoReference", "textReference", "imageReference"])), ]), ), + associationSkills: z.string().optional(), audio: z.union([z.literal("optional"), z.boolean()]), durationResolutionMap: z.array( z.object({ diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 4544078..bf7a13a 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,4 +1,8 @@ -// @db-hash f7bc2fdb80756d5536929eb47155578b +<<<<<<< HEAD +// @db-hash 93b2462070c45c2b449e9a18c4e88763 +======= +// @db-hash 24748d4ef971381a79c720c846f83847 +>>>>>>> 796947cef173e7fe2f96e21fa8aeae23ff0fdf4a //该文件由脚本自动生成,请勿手动修改 export interface _o_script_old_20260327 { diff --git a/src/utils/agent/skillsTools.ts b/src/utils/agent/skillsTools.ts index adb845c..f5ae0be 100644 --- a/src/utils/agent/skillsTools.ts +++ b/src/utils/agent/skillsTools.ts @@ -177,9 +177,9 @@ ${skillEntries} `; } -export function createSkillTools(skills: { name: string; description: string }[], skillPaths: SkillPaths) { +export function createSkillTools(skills: { name: string; description: string }[], skillPaths: SkillPaths, rootDir: string = getPath("skills")) { const activated = new Set(); // 已激活技能集合,防止重复加载 - const skillsRootDir = path.resolve(getPath("skills")); + const skillsRootDir = path.resolve(rootDir); const skillNames = skills.map((s) => s.name); const skillMap = new Map(skillPaths.mainSkill.map((s) => [s.name, s])); return { diff --git a/src/utils/ai.ts b/src/utils/ai.ts index ac8fea7..9c6df1e 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -25,10 +25,23 @@ 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 fn = u.vm(jsCode)[fnName]; + const running = u.vm(jsCode); + Object.assign(running.vendor.inputValues, JSON.parse(vendorConfigData.inputValues ?? "{}")); + running.vendor.models = modelList; + const fn = running[fnName]; if (!fn) throw new Error(`未找到供应商配置中的函数 ${fnName} id=${id}`); - if (fnName == "textRequest") return fn(selectedModel); - else return (input: T) => fn(input, selectedModel); + if (fnName == "textRequest") { + const model = fn(selectedModel); + if (!model) throw new Error(`供应商 textRequest 返回无效模型 id=${id}`); + return model; + } + return async (input: T) => { + const result = await fn(input, selectedModel); + if (result === undefined || result === null) { + throw new Error(`供应商函数 ${fnName} 未返回有效结果 id=${id}`); + } + return result; + }; } async function withTaskRecord( diff --git a/src/utils/vm.ts b/src/utils/vm.ts index 677fe47..133c4f6 100644 --- a/src/utils/vm.ts +++ b/src/utils/vm.ts @@ -11,33 +11,39 @@ import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { createXai } from "@ai-sdk/xai"; import { createMinimax } from "vercel-minimax-ai-provider"; import FormData from "form-data"; +import jsonwebtoken from "jsonwebtoken"; -export default function runCode(code: string) { +export default function runCode(code: string, vendor?: Record) { // 创建一个沙盒 const exports = {}; + const sandbox: Record = { + createOpenAI, + createDeepSeek, + createZhipu, + createQwen, + createAnthropic, + createOpenAICompatible, + createXai, + createMinimax, + createGoogleGenerativeAI, + zipImage, + zipImageResolution, + urlToBase64, + mergeImages, + pollTask, + fetch, + exports, + axios, + FormData, + logger, + jsonwebtoken, + }; + if (vendor !== undefined) { + sandbox.vendor = vendor; + } const vm = new VM({ timeout: 0, - sandbox: { - createOpenAI, - createDeepSeek, - createZhipu, - createQwen, - createAnthropic, - createOpenAICompatible, - createXai, - createMinimax, - createGoogleGenerativeAI, - zipImage, - zipImageResolution, - urlToBase64, - mergeImages, - pollTask, - fetch, - exports, - axios, - FormData, - logger, - }, + sandbox, compiler: "javascript", eval: false, wasm: false, diff --git a/yarn.lock b/yarn.lock index 038e4b1..3513455 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4022,6 +4022,13 @@ p-cancelable@^2.0.0: dependencies: yocto-queue "^0.1.0" +p-limit@^7.3.0: + version "7.3.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-7.3.0.tgz#821398d91491c6b6a1340ecd09cdc402a9c8d0ee" + integrity sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw== + dependencies: + yocto-queue "^1.2.1" + p-map@^4.0.0: version "4.0.0" resolved "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -5536,6 +5543,11 @@ yocto-queue@^0.1.0: resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +yocto-queue@^1.2.1: + version "1.2.2" + resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== + zhipu-ai-provider@^0.2.2: version "0.2.2" resolved "https://registry.npmmirror.com/zhipu-ai-provider/-/zhipu-ai-provider-0.2.2.tgz#cbee428475b1c2fca446f273ac09006ef86f6f00"