From 4b97d61af9f66a365f950ac0f0ff4e457ad853cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Mon, 13 Apr 2026 03:59:46 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=AB=98=E7=BA=A7?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/version.txt | 2 +- package.json | 2 +- src/agents/productionAgent/index.ts | 21 ++++++++++---- src/agents/scriptAgent/index.ts | 10 +++++-- src/types/database.d.ts | 4 +-- src/utils/ai.ts | 44 ++++++++++++++++++++++++++--- 6 files changed, 67 insertions(+), 16 deletions(-) diff --git a/data/version.txt b/data/version.txt index 314c3d7..eb8b7a0 100644 --- a/data/version.txt +++ b/data/version.txt @@ -1 +1 @@ -1.1.5 \ No newline at end of file +1.1.5-dev \ No newline at end of file diff --git a/package.json b/package.json index 4341097..cfdf8bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "toonflow", - "version": "1.1.5", + "version": "1.1.5-dev", "description": "Toonflow 是一款 AI 短剧漫剧工具,能够利用 AI 技术将小说自动转化为剧本,并结合 AI 生成的图片和视频,实现高效的短剧创作。", "author": "HBAI-Ltd ", "license": "Apache-2.0", diff --git a/src/agents/productionAgent/index.ts b/src/agents/productionAgent/index.ts index 21b5a9b..4e3c01e 100644 --- a/src/agents/productionAgent/index.ts +++ b/src/agents/productionAgent/index.ts @@ -50,8 +50,8 @@ export async function runDecisionAI(ctx: AgentContext) { const projectInfo = await u.db("o_project").where("id", ctx.resTool.data.projectId).first(); if (!projectInfo) throw new Error(`项目不存在,ID: ${ctx.resTool.data.projectId}`); - const [_, imageModelName] = projectInfo.imageModel!.split(/:(.+)/) - const [id, videoModelName] = projectInfo.videoModel!.split(/:(.+)/) + const [_, imageModelName] = projectInfo.imageModel!.split(/:(.+)/); + const [id, videoModelName] = projectInfo.videoModel!.split(/:(.+)/); const models = await u.vendor.getModelList(id); if (!models.length) throw new Error(`项目使用的模型不存在,ID: ${projectInfo.videoModel}`); const findData = models.find((i: any) => i.modelName == videoModelName); @@ -60,7 +60,7 @@ export async function runDecisionAI(ctx: AgentContext) { const mem = buildMemPrompt(await memory.get(text)); - const { fullStream } = await u.Ai.Text("productionAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({ + const { fullStream } = await u.Ai.Text("productionAgent:decisionAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({ messages: [ { role: "system", content: prompt }, { role: "assistant", content: mem + "\n" + modelInfo }, @@ -90,6 +90,7 @@ async function createSubAgent(parentCtx: AgentContext) { const { resTool, abortSignal } = parentCtx; const memory = new Memory("productionAgent", parentCtx.isolationKey); async function runAgent({ + key, prompt, system, name, @@ -97,6 +98,7 @@ async function createSubAgent(parentCtx: AgentContext) { tools: extraTools, messages, }: { + key: `${string}:${string}`; prompt: string; system: string; name: string; @@ -107,7 +109,7 @@ async function createSubAgent(parentCtx: AgentContext) { parentCtx.msg.complete(); const subMsg = resTool.newMessage("assistant", name); - const { fullStream } = await u.Ai.Text("productionAgent", parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({ + const { fullStream } = await u.Ai.Text(key, parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({ system, messages: messages ?? [{ role: "user", content: prompt }], abortSignal, @@ -135,8 +137,8 @@ async function createSubAgent(parentCtx: AgentContext) { if (!projectInfo) throw new Error(`项目不存在,ID: ${resTool.data.projectId}`); const artSkills = await createArtSkills(projectInfo?.artStyle!, projectInfo?.directorManual!); - const [_, imageModelName] = projectInfo.imageModel!.split(/:(.+)/) - const [id, videoModelName] = projectInfo.videoModel!.split(/:(.+)/) + const [_, imageModelName] = projectInfo.imageModel!.split(/:(.+)/); + const [id, videoModelName] = projectInfo.videoModel!.split(/:(.+)/); const models = await u.vendor.getModelList(id); if (!models.length) throw new Error(`项目使用的模型不存在,ID: ${projectInfo.videoModel}`); const findData = models.find((i: any) => i.modelName == videoModelName); @@ -181,6 +183,7 @@ async function createSubAgent(parentCtx: AgentContext) { const skill = path.join(u.getPath("skills"), "production_execution_derive_assets.md"); const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ + key: "productionAgent:deriveAssetsAgent", prompt, system: systemPrompt, name: "执行导演", @@ -202,6 +205,7 @@ async function createSubAgent(parentCtx: AgentContext) { const skill = path.join(u.getPath("skills"), "production_execution_generate_assets.md"); const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ + key: "productionAgent:generateAssetsAgent", prompt, system: systemPrompt, name: "执行导演", @@ -226,6 +230,7 @@ async function createSubAgent(parentCtx: AgentContext) { const addPrompt = "\n你必须使用如下XML格式写入工作区:\n```\n内容\n```"; return runAgent({ + key: "productionAgent:directorPlanAgent", prompt, system: systemPrompt + addPrompt, name: "执行导演", @@ -247,6 +252,7 @@ async function createSubAgent(parentCtx: AgentContext) { const skill = path.join(u.getPath("skills"), "production_execution_storyboard_gen.md"); const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ + key: "productionAgent:storyboardGenAgent", prompt, system: systemPrompt, name: "执行导演", @@ -284,6 +290,7 @@ async function createSubAgent(parentCtx: AgentContext) { "\n你必须使用如下XML格式写入工作区:\n```\n\n```"; return runAgent({ + key: "productionAgent:storyboardPanelAgent", prompt, system: systemPrompt + addPrompt, name: "执行导演", @@ -308,6 +315,7 @@ async function createSubAgent(parentCtx: AgentContext) { const addPrompt = "\n你必须使用如下XML格式写入工作区:\n```\n内容\n```"; return runAgent({ + key: "productionAgent:storyboardTableAgent", prompt, system: systemPrompt + addPrompt, name: "执行导演", @@ -328,6 +336,7 @@ async function createSubAgent(parentCtx: AgentContext) { const skill = path.join(u.getPath("skills"), "production_agent_supervision.md"); const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ + key: "productionAgent:supervisionAgent", prompt, system: systemPrompt, name: "监制", diff --git a/src/agents/scriptAgent/index.ts b/src/agents/scriptAgent/index.ts index 57a8fd8..d8f19d6 100644 --- a/src/agents/scriptAgent/index.ts +++ b/src/agents/scriptAgent/index.ts @@ -63,7 +63,7 @@ export async function runDecisionAI(ctx: AgentContext) { `章节数量:${novelData.length}章`, ].join("\n"); - const { fullStream } = await u.Ai.Text("scriptAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({ + const { fullStream } = await u.Ai.Text("scriptAgent:decisionAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({ messages: [ { role: "system", content: prompt }, { role: "assistant", content: projectInfo + "\n" + mem }, @@ -94,6 +94,7 @@ function createSubAgent(parentCtx: AgentContext) { const memory = new Memory("scriptAgent", parentCtx.isolationKey); async function runAgent({ + key, prompt, system, name, @@ -101,6 +102,7 @@ function createSubAgent(parentCtx: AgentContext) { tools: extraTools, messages, }: { + key: `${string}:${string}`; prompt: string; system: string; name: string; @@ -111,7 +113,7 @@ function createSubAgent(parentCtx: AgentContext) { parentCtx.msg.complete(); const subMsg = resTool.newMessage("assistant", name); - const { fullStream } = await u.Ai.Text("scriptAgent", parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({ + const { fullStream } = await u.Ai.Text(key, parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({ system, messages: messages ?? [{ role: "user", content: prompt }], abortSignal, @@ -145,6 +147,7 @@ function createSubAgent(parentCtx: AgentContext) { const formatPrompt = "\n你必须使用如下XML格式写入工作区:\n故事骨架内容"; return runAgent({ + key: "scriptAgent:storySkeletonAgent", prompt, system: systemPrompt + formatPrompt, name: "编剧", @@ -164,6 +167,7 @@ function createSubAgent(parentCtx: AgentContext) { const formatPrompt = "\n你必须使用如下XML格式写入工作区:\n改编策略内容"; return runAgent({ + key: "scriptAgent:adaptationStrategyAgent", prompt, system: systemPrompt + formatPrompt, name: "编剧", @@ -190,6 +194,7 @@ function createSubAgent(parentCtx: AgentContext) { const formatPrompt = `\n你必须使用如下XML格式写入工作区:\nXML不得添加任何额外标签剧本内容剧本内容剧本内容`; return runAgent({ + key: "scriptAgent:scriptAgent", prompt, system: systemPrompt + formatPrompt, messages: [ @@ -210,6 +215,7 @@ function createSubAgent(parentCtx: AgentContext) { const systemPrompt = await fs.promises.readFile(skill, "utf-8"); return runAgent({ + key: "scriptAgent:supervisionAgent", prompt, system: systemPrompt, name: "编辑", diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 74ef407..eb4d216 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,4 +1,4 @@ -// @db-hash 88c167ba73e2771e7b043419ca5089dd +// @db-hash 5364c2db0bf42b520761b813ce040489 //该文件由脚本自动生成,请勿手动修改 export interface memories { @@ -23,6 +23,7 @@ export interface o_agentDeploy { 'modelName'?: string | null; 'name'?: string | null; 'temperature'?: number | null; + 'topP'?: number | null; 'type'?: string | null; 'vendorId'?: string | null; } @@ -210,7 +211,6 @@ export interface o_user { 'password'?: string | null; } export interface o_vendorConfig { - 'code'?: string | null; 'enable'?: number | null; 'id'?: string; 'inputValues'?: string | null; diff --git a/src/utils/ai.ts b/src/utils/ai.ts index 91b4664..f29c7eb 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -4,15 +4,51 @@ import axios from "axios"; import { transform } from "sucrase"; import u from "@/utils"; -type AiType = "scriptAgent" | "productionAgent" | "universalAi"; +type AiType = + | "scriptAgent:decisionAgent" + | "scriptAgent:supervisionAgent" + | "scriptAgent:storySkeletonAgent" + | "scriptAgent:adaptationStrategyAgent" + | "scriptAgent:scriptAgent" + | "productionAgent:decisionAgent" + | "productionAgent:supervisionAgent" + | "productionAgent:deriveAssetsAgent" + | "productionAgent:generateAssetsAgent" + | "productionAgent:directorPlanAgent" + | "productionAgent:storyboardGenAgent" + | "productionAgent:storyboardPanelAgent" + | "productionAgent:storyboardTableAgent" + | "universalAi"; type FnName = "textRequest" | "imageRequest" | "videoRequest" | "ttsRequest"; -const AiTypeValues: AiType[] = ["scriptAgent", "productionAgent", "universalAi"]; +const AiTypeValues: AiType[] = [ + "scriptAgent:decisionAgent", + "scriptAgent:supervisionAgent", + "scriptAgent:storySkeletonAgent", + "scriptAgent:adaptationStrategyAgent", + "scriptAgent:scriptAgent", + "productionAgent:decisionAgent", + "productionAgent:supervisionAgent", + "productionAgent:deriveAssetsAgent", + "productionAgent:generateAssetsAgent", + "productionAgent:directorPlanAgent", + "productionAgent:storyboardGenAgent", + "productionAgent:storyboardPanelAgent", + "productionAgent:storyboardTableAgent", + "universalAi", +]; async function resolveModelName(value: AiType | `${string}:${string}`): Promise<`${string}:${string}`> { if (AiTypeValues.includes(value as AiType)) { const agentDeployData = await u.db("o_agentDeploy").where("key", value).first(); - if (!agentDeployData?.modelName) throw new Error(`${value}模型未配置`); - return agentDeployData.modelName as `${number}:${string}`; + let modelName = null; + if (!agentDeployData?.modelName) { + const [mainly] = value.split(/:(.+)/); + const mainlyData = await u.db("o_agentDeploy").where("key", mainly).first(); + if (!mainlyData?.modelName) throw new Error(`未找到部署配置 ${value}`); + modelName = mainlyData.modelName; + } + modelName = agentDeployData?.modelName || modelName; + return modelName as `${number}:${string}`; } return value as `${number}:${string}`; } From 961344ce03527a9a8e9abbb491bfe52b2428fc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Mon, 13 Apr 2026 04:05:10 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B8=A9=E5=BA=A6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/ai.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/utils/ai.ts b/src/utils/ai.ts index f29c7eb..ed28d6e 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -53,6 +53,17 @@ async function resolveModelName(value: AiType | `${string}:${string}`): Promise< return value as `${number}:${string}`; } +async function getModelConfig(value: AiType | `${string}:${string}`) { + const agentDeployData = await u.db("o_agentDeploy").where("key", value).first(); + if (!agentDeployData?.modelName) { + const [mainly] = value.split(/:(.+)/); + const mainlyData = await u.db("o_agentDeploy").where("key", mainly).first(); + if (!mainlyData?.modelName) throw new Error(`未找到部署配置 ${value}`); + return mainlyData; + } + return agentDeployData; +} + async function getVendorTemplateFn( fnName: "textRequest", modelName: `${string}:${string}`, @@ -137,21 +148,25 @@ class AiText { return mws.length > 0 ? wrapLanguageModel({ model: baseModel, middleware: mws.length === 1 ? mws[0] : mws }) : baseModel; } async invoke(input: Omit[0], "model">) { + const config = await getModelConfig(this.AiType); + return generateText({ ...(input.tools && { stopWhen: stepCountIs(Object.keys(input.tools).length * 50) }), ...input, model: await this.resolveModel(), - temperature: 1, - maxOutputTokens: 8129, + ...(config.temperature && { temperature: config.temperature }), + ...(config.maxOutputTokens && { maxOutputTokens: config.maxOutputTokens }), } as Parameters[0]); } async stream(input: Omit[0], "model">) { + const config = await getModelConfig(this.AiType); + return streamText({ ...(input.tools && { stopWhen: stepCountIs(Object.keys(input.tools).length * 50) }), ...input, model: await this.resolveModel(extractReasoningMiddleware({ tagName: "reasoning_content", separator: "\n" })), - temperature: 1, - maxOutputTokens: 8129, + ...(config.temperature && { temperature: config.temperature }), + ...(config.maxOutputTokens && { maxOutputTokens: config.maxOutputTokens }), } as Parameters[0]); } }