修正供应商,修正多余代码
This commit is contained in:
parent
493e9c2ef0
commit
4a5ac8732f
8
data/vendor/volcengine.ts
vendored
8
data/vendor/volcengine.ts
vendored
@ -133,7 +133,7 @@ declare const exports: {
|
||||
|
||||
const vendor: VendorConfig = {
|
||||
id: "volcengine",
|
||||
version: "2.1",
|
||||
version: "2.2",
|
||||
author: "leeqi",
|
||||
name: "火山引擎(豆包)",
|
||||
description:
|
||||
@ -301,10 +301,10 @@ const textRequest = (model: TextModel, think: boolean, thinkLevel: 0 | 1 | 2 | 3
|
||||
3: "high",
|
||||
};
|
||||
|
||||
return createOpenAI({
|
||||
return createOpenAICompatible({
|
||||
name: "volcengine",
|
||||
baseURL: getBaseUrl(),
|
||||
apiKey,
|
||||
compatibility: "compatible",
|
||||
fetch: async (url: string, options?: RequestInit) => {
|
||||
const rawBody = JSON.parse((options?.body as string) ?? "{}");
|
||||
const modifiedBody = {
|
||||
@ -319,7 +319,7 @@ const textRequest = (model: TextModel, think: boolean, thinkLevel: 0 | 1 | 2 | 3
|
||||
body: JSON.stringify(modifiedBody),
|
||||
});
|
||||
},
|
||||
}).chat(model.modelName);
|
||||
}).chatModel(model.modelName);
|
||||
};
|
||||
|
||||
const imageRequest = async (config: ImageConfig, model: ImageModel): Promise<string> => {
|
||||
|
||||
@ -1 +1 @@
|
||||
1.1.3
|
||||
1.1.4
|
||||
@ -17,6 +17,11 @@ export interface AgentContext {
|
||||
abortSignal?: AbortSignal;
|
||||
resTool: ResTool;
|
||||
msg: ReturnType<ResTool["newMessage"]>;
|
||||
messages?: { role: "user" | "assistant" | "system"; content: string }[];
|
||||
thinkConfig: {
|
||||
think: boolean;
|
||||
thinlLevel: 0 | 1 | 2 | 3;
|
||||
};
|
||||
}
|
||||
|
||||
function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
@ -35,7 +40,7 @@ function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
return `## Memory\n以下是你对用户的记忆,可作为参考但不要主动提及:\n${memoryContext}`;
|
||||
}
|
||||
|
||||
export async function decisionAI(ctx: AgentContext) {
|
||||
export async function runDecisionAI(ctx: AgentContext) {
|
||||
const { isolationKey, text, abortSignal } = ctx;
|
||||
const memory = new Memory("productionAgent", isolationKey);
|
||||
await memory.add("user", text);
|
||||
@ -45,17 +50,17 @@ export async function decisionAI(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}`);
|
||||
if (!models.length) throw new Error(`项目使用的模型不存在,ID: ${projectInfo.videoModel}`);
|
||||
const findData = models.find((i: any) => i.modelName == videoModelName);
|
||||
const isRef = findData.mode.every((i: any) => Array.isArray(i));
|
||||
const modelInfo = `项目使用的模型如下:\n图像模型:${imageModelName}\n视频模型:${videoModelName}\n多参:${isRef ? "是" : "否"}`;
|
||||
|
||||
const mem = buildMemPrompt(await memory.get(text));
|
||||
|
||||
const { textStream } = await u.Ai.Text("productionAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text("productionAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({
|
||||
messages: [
|
||||
{ role: "system", content: prompt },
|
||||
{ role: "assistant", content: mem + "\n" + modelInfo },
|
||||
@ -72,7 +77,13 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
},
|
||||
});
|
||||
|
||||
return textStream;
|
||||
let currentMsg = ctx.msg;
|
||||
await consumeFullStream(fullStream, currentMsg, () => {
|
||||
if (ctx.msg === currentMsg) return currentMsg;
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
return currentMsg;
|
||||
});
|
||||
}
|
||||
|
||||
async function createSubAgent(parentCtx: AgentContext) {
|
||||
@ -95,29 +106,15 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
}) {
|
||||
parentCtx.msg.complete();
|
||||
const subMsg = resTool.newMessage("assistant", name);
|
||||
const text = subMsg.text();
|
||||
let fullResponse = "";
|
||||
|
||||
const { textStream } = await u.Ai.Text("productionAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text("productionAgent", parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({
|
||||
system,
|
||||
messages: messages ?? [{ role: "user", content: prompt }],
|
||||
abortSignal,
|
||||
tools: { ...extraTools, ...useTools({ resTool, msg: subMsg }) },
|
||||
});
|
||||
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
text.append(chunk);
|
||||
fullResponse += chunk;
|
||||
}
|
||||
text.complete();
|
||||
subMsg.complete();
|
||||
} catch (err: any) {
|
||||
text.complete();
|
||||
subMsg.stop();
|
||||
throw err;
|
||||
}
|
||||
const fullResponse = await consumeFullStream(fullStream, subMsg);
|
||||
|
||||
if (fullResponse.trim()) {
|
||||
await memory.add(memoryKey, removeAllXmlTags(fullResponse), {
|
||||
@ -138,10 +135,10 @@ 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}`);
|
||||
if (!models.length) throw new Error(`项目使用的模型不存在,ID: ${projectInfo.videoModel}`);
|
||||
const findData = models.find((i: any) => i.modelName == videoModelName);
|
||||
const isRef = findData.mode.every((i: any) => Array.isArray(i));
|
||||
const modelInfo = `项目使用的模型如下:\n图像模型:${imageModelName}\n视频模型:${videoModelName}\n多参:${isRef ? "是" : "否"}`;
|
||||
@ -370,7 +367,53 @@ ${buildSkillPrompt(mainSkills)}`,
|
||||
};
|
||||
return res;
|
||||
}
|
||||
async function consumeFullStream(
|
||||
fullStream: AsyncIterable<any>,
|
||||
initialMsg: ReturnType<ResTool["newMessage"]>,
|
||||
syncMsg?: () => ReturnType<ResTool["newMessage"]>,
|
||||
): Promise<string> {
|
||||
let msg = initialMsg;
|
||||
let text = msg.text();
|
||||
let thinking: ReturnType<typeof msg.thinking> | null = null;
|
||||
let thinkTime = 0;
|
||||
let fullResponse = "";
|
||||
|
||||
try {
|
||||
for await (const chunk of fullStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
if (syncMsg) {
|
||||
const newMsg = syncMsg();
|
||||
if (newMsg !== msg) {
|
||||
msg = newMsg;
|
||||
text = msg.text();
|
||||
}
|
||||
}
|
||||
if (chunk.type === "reasoning-start") {
|
||||
thinkTime = Date.now();
|
||||
thinking = msg.thinking("思考中...");
|
||||
} else if (chunk.type === "reasoning-delta") {
|
||||
thinking?.append(chunk.text);
|
||||
} else if (chunk.type === "reasoning-end") {
|
||||
thinkTime = Date.now() - thinkTime;
|
||||
thinking?.updateTitle(`思考完毕(${(thinkTime / 1000).toFixed(1)} 秒)`);
|
||||
thinking?.complete();
|
||||
thinking = null;
|
||||
} else if (chunk.type === "text-delta") {
|
||||
text.append(chunk.text);
|
||||
fullResponse += chunk.text;
|
||||
}
|
||||
}
|
||||
text.complete();
|
||||
msg.complete();
|
||||
} catch (err: any) {
|
||||
thinking?.complete();
|
||||
text.complete();
|
||||
msg.stop();
|
||||
throw err;
|
||||
}
|
||||
|
||||
return fullResponse;
|
||||
}
|
||||
function removeAllXmlTags(text: string): string {
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?>([\s\S]*?)<\/\1>/g, "");
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?\/>/g, "");
|
||||
|
||||
@ -16,6 +16,10 @@ export interface AgentContext {
|
||||
abortSignal?: AbortSignal;
|
||||
resTool: ResTool;
|
||||
msg: ReturnType<ResTool["newMessage"]>;
|
||||
thinkConfig: {
|
||||
think: boolean;
|
||||
thinlLevel: 0 | 1 | 2 | 3;
|
||||
};
|
||||
}
|
||||
|
||||
function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
@ -34,7 +38,7 @@ function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
return `## Memory\n以下是你对用户的记忆,可作为参考但不要主动提及:\n${memoryContext}`;
|
||||
}
|
||||
|
||||
export async function decisionAI(ctx: AgentContext) {
|
||||
export async function runDecisionAI(ctx: AgentContext) {
|
||||
const { isolationKey, text, userMessageTime, abortSignal, resTool } = ctx;
|
||||
|
||||
const memory = new Memory("scriptAgent", isolationKey);
|
||||
@ -59,7 +63,7 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
`章节数量:${novelData.length}章`,
|
||||
].join("\n");
|
||||
|
||||
const { textStream } = await u.Ai.Text("scriptAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text("scriptAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({
|
||||
messages: [
|
||||
{ role: "system", content: prompt },
|
||||
{ role: "assistant", content: projectInfo + "\n" + mem },
|
||||
@ -76,7 +80,13 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
},
|
||||
});
|
||||
|
||||
return textStream;
|
||||
let currentMsg = ctx.msg;
|
||||
await consumeFullStream(fullStream, currentMsg, () => {
|
||||
if (ctx.msg === currentMsg) return currentMsg;
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
return currentMsg;
|
||||
});
|
||||
}
|
||||
|
||||
function createSubAgent(parentCtx: AgentContext) {
|
||||
@ -100,29 +110,15 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
}) {
|
||||
parentCtx.msg.complete();
|
||||
const subMsg = resTool.newMessage("assistant", name);
|
||||
const text = subMsg.text();
|
||||
let fullResponse = "";
|
||||
|
||||
const { textStream } = await u.Ai.Text("scriptAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text("scriptAgent", parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel ).stream({
|
||||
system,
|
||||
messages: messages ?? [{ role: "user", content: prompt }],
|
||||
abortSignal,
|
||||
tools: { ...extraTools, ...useTools({ resTool, msg: subMsg }) },
|
||||
});
|
||||
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
text.append(chunk);
|
||||
fullResponse += chunk;
|
||||
}
|
||||
text.complete();
|
||||
subMsg.complete();
|
||||
} catch (err: any) {
|
||||
text.complete();
|
||||
subMsg.stop();
|
||||
throw err;
|
||||
}
|
||||
const fullResponse = await consumeFullStream(fullStream, subMsg);
|
||||
|
||||
if (fullResponse.trim()) {
|
||||
await memory.add(memoryKey, removeAllXmlTags(fullResponse), {
|
||||
@ -230,6 +226,54 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
};
|
||||
}
|
||||
|
||||
async function consumeFullStream(
|
||||
fullStream: AsyncIterable<any>,
|
||||
initialMsg: ReturnType<ResTool["newMessage"]>,
|
||||
syncMsg?: () => ReturnType<ResTool["newMessage"]>,
|
||||
): Promise<string> {
|
||||
let msg = initialMsg;
|
||||
let text = msg.text();
|
||||
let thinking: ReturnType<typeof msg.thinking> | null = null;
|
||||
let thinkTime = 0;
|
||||
let fullResponse = "";
|
||||
|
||||
try {
|
||||
for await (const chunk of fullStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
if (syncMsg) {
|
||||
const newMsg = syncMsg();
|
||||
if (newMsg !== msg) {
|
||||
msg = newMsg;
|
||||
text = msg.text();
|
||||
}
|
||||
}
|
||||
if (chunk.type === "reasoning-start") {
|
||||
thinkTime = Date.now();
|
||||
thinking = msg.thinking("思考中...");
|
||||
} else if (chunk.type === "reasoning-delta") {
|
||||
thinking?.append(chunk.text);
|
||||
} else if (chunk.type === "reasoning-end") {
|
||||
thinkTime = Date.now() - thinkTime;
|
||||
thinking?.updateTitle(`思考完毕(${(thinkTime / 1000).toFixed(1)} 秒)`);
|
||||
thinking?.complete();
|
||||
thinking = null;
|
||||
} else if (chunk.type === "text-delta") {
|
||||
text.append(chunk.text);
|
||||
fullResponse += chunk.text;
|
||||
}
|
||||
}
|
||||
text.complete();
|
||||
msg.complete();
|
||||
} catch (err: any) {
|
||||
thinking?.complete();
|
||||
text.complete();
|
||||
msg.stop();
|
||||
throw err;
|
||||
}
|
||||
|
||||
return fullResponse;
|
||||
}
|
||||
|
||||
function removeAllXmlTags(text: string): string {
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?>([\s\S]*?)<\/\1>/g, "");
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?\/>/g, "");
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -261,29 +261,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
//大纲表
|
||||
{
|
||||
name: "o_outline",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.integer("episode");
|
||||
table.text("data");
|
||||
table.integer("projectId");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
//大纲-原文表
|
||||
{
|
||||
name: "o_outlineNovel",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.integer("outlineId").unsigned().references("id").inTable("o_outline");
|
||||
table.integer("novelId").unsigned().references("id").inTable("o_novel");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
//剧本
|
||||
{
|
||||
name: "o_script",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// @routes-hash 62534cff632db5d31442f1bca1932925
|
||||
// @routes-hash 4d6cbfaad479bdfafe13bc61e7550f55
|
||||
import { Express } from "express";
|
||||
|
||||
import route1 from "./routes/agents/clearMemory";
|
||||
@ -34,22 +34,22 @@ import route30 from "./routes/general/generalStatistics";
|
||||
import route31 from "./routes/general/getSingleProject";
|
||||
import route32 from "./routes/general/updateProject";
|
||||
import route33 from "./routes/login/login";
|
||||
import route34 from "./routes/migrate/migrateData";
|
||||
import route35 from "./routes/modelSelect/getModelDetail";
|
||||
import route36 from "./routes/modelSelect/getModelList";
|
||||
import route37 from "./routes/novel/addNovel";
|
||||
import route38 from "./routes/novel/batchDeleteNovel";
|
||||
import route39 from "./routes/novel/delNovel";
|
||||
import route40 from "./routes/novel/event/batchDeleteEvent";
|
||||
import route41 from "./routes/novel/event/deletEvent";
|
||||
import route42 from "./routes/novel/event/generateEvents";
|
||||
import route43 from "./routes/novel/event/getEvent";
|
||||
import route44 from "./routes/novel/getNovel";
|
||||
import route45 from "./routes/novel/getNovelData";
|
||||
import route46 from "./routes/novel/getNovelEventState";
|
||||
import route47 from "./routes/novel/getNovelIndex";
|
||||
import route48 from "./routes/novel/updateNovel";
|
||||
import route49 from "./routes/other/deleteAllData";
|
||||
import route34 from "./routes/modelSelect/getModelDetail";
|
||||
import route35 from "./routes/modelSelect/getModelList";
|
||||
import route36 from "./routes/novel/addNovel";
|
||||
import route37 from "./routes/novel/batchDeleteNovel";
|
||||
import route38 from "./routes/novel/delNovel";
|
||||
import route39 from "./routes/novel/event/batchDeleteEvent";
|
||||
import route40 from "./routes/novel/event/deletEvent";
|
||||
import route41 from "./routes/novel/event/generateEvents";
|
||||
import route42 from "./routes/novel/event/getEvent";
|
||||
import route43 from "./routes/novel/getNovel";
|
||||
import route44 from "./routes/novel/getNovelData";
|
||||
import route45 from "./routes/novel/getNovelEventState";
|
||||
import route46 from "./routes/novel/getNovelIndex";
|
||||
import route47 from "./routes/novel/updateNovel";
|
||||
import route48 from "./routes/other/deleteAllData";
|
||||
import route49 from "./routes/other/getModelDetails";
|
||||
import route50 from "./routes/other/getVersion";
|
||||
import route51 from "./routes/production/assets/batchGenerateAssetsImage";
|
||||
import route52 from "./routes/production/assets/deleteAssetsDireve";
|
||||
@ -179,22 +179,22 @@ export default async (app: Express) => {
|
||||
app.use("/api/general/getSingleProject", route31);
|
||||
app.use("/api/general/updateProject", route32);
|
||||
app.use("/api/login/login", route33);
|
||||
app.use("/api/migrate/migrateData", route34);
|
||||
app.use("/api/modelSelect/getModelDetail", route35);
|
||||
app.use("/api/modelSelect/getModelList", route36);
|
||||
app.use("/api/novel/addNovel", route37);
|
||||
app.use("/api/novel/batchDeleteNovel", route38);
|
||||
app.use("/api/novel/delNovel", route39);
|
||||
app.use("/api/novel/event/batchDeleteEvent", route40);
|
||||
app.use("/api/novel/event/deletEvent", route41);
|
||||
app.use("/api/novel/event/generateEvents", route42);
|
||||
app.use("/api/novel/event/getEvent", route43);
|
||||
app.use("/api/novel/getNovel", route44);
|
||||
app.use("/api/novel/getNovelData", route45);
|
||||
app.use("/api/novel/getNovelEventState", route46);
|
||||
app.use("/api/novel/getNovelIndex", route47);
|
||||
app.use("/api/novel/updateNovel", route48);
|
||||
app.use("/api/other/deleteAllData", route49);
|
||||
app.use("/api/modelSelect/getModelDetail", route34);
|
||||
app.use("/api/modelSelect/getModelList", route35);
|
||||
app.use("/api/novel/addNovel", route36);
|
||||
app.use("/api/novel/batchDeleteNovel", route37);
|
||||
app.use("/api/novel/delNovel", route38);
|
||||
app.use("/api/novel/event/batchDeleteEvent", route39);
|
||||
app.use("/api/novel/event/deletEvent", route40);
|
||||
app.use("/api/novel/event/generateEvents", route41);
|
||||
app.use("/api/novel/event/getEvent", route42);
|
||||
app.use("/api/novel/getNovel", route43);
|
||||
app.use("/api/novel/getNovelData", route44);
|
||||
app.use("/api/novel/getNovelEventState", route45);
|
||||
app.use("/api/novel/getNovelIndex", route46);
|
||||
app.use("/api/novel/updateNovel", route47);
|
||||
app.use("/api/other/deleteAllData", route48);
|
||||
app.use("/api/other/getModelDetails", route49);
|
||||
app.use("/api/other/getVersion", route50);
|
||||
app.use("/api/production/assets/batchGenerateAssetsImage", route51);
|
||||
app.use("/api/production/assets/deleteAssetsDireve", route52);
|
||||
|
||||
@ -27,22 +27,6 @@ interface NovelChapter {
|
||||
|
||||
type ItemType = "characters" | "props" | "scenes";
|
||||
|
||||
interface ResultItem {
|
||||
type: ItemType;
|
||||
name: string;
|
||||
chapterRange: number[];
|
||||
}
|
||||
function findItemByName(items: ResultItem[], name: string, type?: ItemType): ResultItem | undefined {
|
||||
return items.find((item) => (!type || item.type === type) && item.name === name);
|
||||
}
|
||||
function mergeNovelText(novelData: NovelChapter[]): string {
|
||||
if (!Array.isArray(novelData)) return "";
|
||||
return novelData
|
||||
.map((chap) => {
|
||||
return `${chap.chapter.trim()}\n\n${chap.chapterData.trim().replace(/\r?\n/g, "\n")}\n`;
|
||||
})
|
||||
.join("\n");
|
||||
}
|
||||
//润色提示词
|
||||
export default router.post(
|
||||
"/",
|
||||
@ -66,23 +50,6 @@ export default router.post(
|
||||
if (!project) return res.status(500).send(success({ message: "项目为空" }));
|
||||
|
||||
// 预加载公共数据
|
||||
const allOutlineDataList: { data: string }[] = await u.db("o_outline").where("projectId", projectId).select("data");
|
||||
const itemMap: Record<string, ResultItem> = {};
|
||||
if (allOutlineDataList.length > 0)
|
||||
allOutlineDataList.forEach((row) => {
|
||||
const data: OutlineData = JSON.parse(row?.data || "{}");
|
||||
(["characters", "props", "scenes"] as ItemType[]).forEach((type) => {
|
||||
(data[type] || []).forEach((item) => {
|
||||
const key = `${type}-${item.name}`;
|
||||
if (!itemMap[key]) {
|
||||
itemMap[key] = { type, name: item.name, chapterRange: [...(data.chapterRange || [])] };
|
||||
} else {
|
||||
itemMap[key].chapterRange = Array.from(new Set([...itemMap[key].chapterRange, ...(data.chapterRange || [])]));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
const result: ResultItem[] = Object.values(itemMap);
|
||||
const assetsIds = items.map((item: { assetsId: number }) => item.assetsId);
|
||||
//查询所有资产,用于判断每个资产是否是衍生资产
|
||||
const assetsDataList = await u.db("o_assets").whereIn("id", assetsIds).select("id", "assetsId");
|
||||
@ -132,7 +99,6 @@ export default router.post(
|
||||
await u.db("o_assets").where("id", item.assetsId).update({ promptState: "生成失败", promptErrorReason: "视觉手册未定义" });
|
||||
return;
|
||||
}
|
||||
findItemByName(result, item.name, config.itemType);
|
||||
const systemPrompt = visualManual;
|
||||
try {
|
||||
const { _output } = (await u.Ai.Text("universalAi").invoke({
|
||||
|
||||
@ -4,36 +4,10 @@ import * as zod from "zod";
|
||||
import { error, success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
const router = express.Router();
|
||||
interface OutlineItem {
|
||||
description: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface OutlineData {
|
||||
chapterRange: number[];
|
||||
characters?: OutlineItem[];
|
||||
props?: OutlineItem[];
|
||||
scenes?: OutlineItem[];
|
||||
}
|
||||
|
||||
interface NovelChapter {
|
||||
id: number;
|
||||
reel: string;
|
||||
chapter: string;
|
||||
chapterData: string;
|
||||
projectId: number;
|
||||
}
|
||||
|
||||
type ItemType = "characters" | "props" | "scenes";
|
||||
|
||||
interface ResultItem {
|
||||
type: ItemType;
|
||||
name: string;
|
||||
chapterRange: number[];
|
||||
}
|
||||
function findItemByName(items: ResultItem[], name: string, type?: ItemType): ResultItem | undefined {
|
||||
return items.find((item) => (!type || item.type === type) && item.name === name);
|
||||
}
|
||||
//润色提示词
|
||||
export default router.post(
|
||||
"/",
|
||||
@ -51,31 +25,8 @@ export default router.post(
|
||||
//如果没有找到对应的项目,返回错误
|
||||
if (!project) return res.status(500).send(success({ message: "项目为空" }));
|
||||
|
||||
const allOutlineDataList: { data: string }[] = await u.db("o_outline").where("projectId", projectId).select("data");
|
||||
await u.db("o_assets").where("id", assetsId).update({ promptState: "生成中" });
|
||||
|
||||
const itemMap: Record<string, ResultItem> = {};
|
||||
|
||||
if (allOutlineDataList.length > 0)
|
||||
allOutlineDataList.forEach((row) => {
|
||||
const data: OutlineData = JSON.parse(row?.data || "{}");
|
||||
(["characters", "props", "scenes"] as ItemType[]).forEach((type) => {
|
||||
(data[type] || []).forEach((item) => {
|
||||
const key = `${type}-${item.name}`;
|
||||
if (!itemMap[key]) {
|
||||
itemMap[key] = {
|
||||
type,
|
||||
name: item.name,
|
||||
chapterRange: [...(data.chapterRange || [])],
|
||||
};
|
||||
} else {
|
||||
itemMap[key].chapterRange = Array.from(new Set([...itemMap[key].chapterRange, ...(data.chapterRange || [])]));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const result: ResultItem[] = Object.values(itemMap);
|
||||
//查询资产是否是衍生资产
|
||||
const assetsData = await u.db("o_assets").where("id", assetsId).select("assetsId").first();
|
||||
if (!assetsData) return { code: 500, message: "资产不存在" };
|
||||
@ -109,7 +60,6 @@ export default router.post(
|
||||
//获取到视觉手册
|
||||
const visualManual = await u.getArtPrompt(project.artStyle as string, "art_skills", config.visualManual);
|
||||
if (!visualManual) return res.status(500).send(error("视觉手册未定义"));
|
||||
findItemByName(result, name, config.itemType);
|
||||
const systemPrompt = visualManual;
|
||||
try {
|
||||
const { _output } = (await u.Ai.Text("universalAi").invoke({
|
||||
|
||||
@ -1,133 +0,0 @@
|
||||
import express from "express";
|
||||
import { success } from "@/lib/responseFormat";
|
||||
import db from "@/utils/db";
|
||||
import type { DB } from "@/types/database";
|
||||
import knex from "knex";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { tr } from "zod/locales";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 迁移数据
|
||||
export default router.post(
|
||||
"/",
|
||||
async (req, res) => {
|
||||
// return res.status(200).send({
|
||||
// success: true,
|
||||
// message: '数据迁移功能已关闭,建议手动迁移数据后删除旧数据库文件'
|
||||
// });
|
||||
//连接旧数据库,读取数据
|
||||
try {
|
||||
let db2: knex.Knex | null = null;
|
||||
//读取旧数据库路径
|
||||
let db2Path: string;
|
||||
if (typeof process.versions?.electron !== "undefined") {
|
||||
const { app } = require("electron");
|
||||
const userDataDir: string = app.getPath("userData");
|
||||
db2Path = path.join(userDataDir, "db2.sqlite");
|
||||
} else {
|
||||
db2Path = path.join(process.cwd(), "db2.sqlite");
|
||||
}
|
||||
const dbDir = path.dirname(db2Path);
|
||||
// 确保数据库目录存在
|
||||
if (!fs.existsSync(dbDir)) {
|
||||
fs.mkdirSync(dbDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(db2Path)) {
|
||||
return res.status(404).send({
|
||||
success: false,
|
||||
message: `源数据库文件不存在: ${db2Path}`
|
||||
});
|
||||
}
|
||||
//连接旧数据库
|
||||
db2 = knex({
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: db2Path,
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
});
|
||||
//需要迁移的旧数据表
|
||||
const db2TableNames = [
|
||||
't_project',
|
||||
't_assets',
|
||||
't_event',
|
||||
't_image',
|
||||
't_novel',
|
||||
't_outline',
|
||||
't_script',
|
||||
't_storyboard',
|
||||
't_video',
|
||||
]
|
||||
//新数据库的表
|
||||
const dbTableNames = [
|
||||
'o_project',
|
||||
'o_assets',
|
||||
'o_event',
|
||||
'o_eventChapter',
|
||||
'o_image',
|
||||
'o_novel',
|
||||
'o_outline',
|
||||
'o_outlineNovel',
|
||||
'o_script',
|
||||
'o_scriptAssets',
|
||||
'o_scriptOutline',
|
||||
'o_storyboard',
|
||||
'o_storyboardScript',
|
||||
'o_video',
|
||||
]
|
||||
|
||||
for (const tableName of db2TableNames) {
|
||||
try {
|
||||
// 从 db2 读取数据
|
||||
const sourceData = await db2(tableName).select('*');
|
||||
for (const item of sourceData) {
|
||||
//迁移项目表
|
||||
if (tableName === 't_project') {
|
||||
// await db("o_project").insert({
|
||||
// name: item.name,
|
||||
// intro: item.intro,
|
||||
// type: item.type,
|
||||
// artStyle: item.artStyle,
|
||||
// videoRatio: item.videoRatio,
|
||||
// createTime: item.createTime,
|
||||
// userId: item.userId,
|
||||
// projectType: "基于小说原文"
|
||||
// })
|
||||
}
|
||||
//迁移资产表
|
||||
if (tableName === 't_assets') {
|
||||
}
|
||||
//迁移事件表
|
||||
if (tableName === 't_event') { }
|
||||
//迁移图片表
|
||||
if (tableName === 't_image') { }
|
||||
//迁移小说表
|
||||
if (tableName === 't_novel') { }
|
||||
//迁移大纲表
|
||||
if (tableName === 't_outline') { }
|
||||
//迁移脚本表
|
||||
if (tableName === 't_script') { }
|
||||
//迁移分镜面板
|
||||
if (tableName === 't_storyboard') { }
|
||||
//迁移视频表
|
||||
if (tableName === 't_video') { }
|
||||
}
|
||||
// // 将数据插入到 db 中
|
||||
// const targetTableName = dbTableNames[db2TableNames.indexOf(tableName)];
|
||||
// await db(targetTableName).insert(sourceData);
|
||||
// console.log(`成功迁移表 ${tableName} 的数据到 ${targetTableName}`);
|
||||
} catch (error) {
|
||||
console.error(`连接旧数据库失败: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('连接旧数据库失败:', error);
|
||||
}
|
||||
return res.status(200).send({
|
||||
success: true,
|
||||
message: '数据迁移功能已关闭,建议手动迁移数据后删除旧数据库文件'
|
||||
});
|
||||
}
|
||||
);
|
||||
@ -12,7 +12,7 @@ export default router.post(
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { modelId } = req.body;
|
||||
const [id, name] = modelId.split(":");
|
||||
const [id, name] = modelId.split(/:(.+)/);
|
||||
const models = await u.vendor.getModelList(id);
|
||||
const findData = models.find((i: any) => i.modelName == name);
|
||||
res.status(200).send(success(findData));
|
||||
|
||||
21
src/routes/other/getModelDetails.ts
Normal file
21
src/routes/other/getModelDetails.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import express from "express";
|
||||
import { success, error } 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({
|
||||
key: z.string().optional(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { key } = req.body;
|
||||
const [id, modelName] = key ? key.split(":") : [];
|
||||
const models = await u.vendor.getModelList(id);
|
||||
const model = models.find((m) => m.modelName === modelName);
|
||||
if (!model) return res.status(400).send(error("未找到模型"));
|
||||
res.status(200).send(success(model));
|
||||
},
|
||||
);
|
||||
@ -73,7 +73,7 @@ export default router.post(
|
||||
shouldGenerateImage: item.shouldGenerateImage,
|
||||
});
|
||||
}
|
||||
const [id, modelData] = model.split(":");
|
||||
const [id, modelData] = model.split(/:(.+)/);
|
||||
const projectData = await u.db("o_project").select("*").where({ id: projectId }).first();
|
||||
const videoPrompt = await u.db("o_prompt").where("type", "videoPromptGeneration").first();
|
||||
let videoPromptGeneration = "" as string | undefined;
|
||||
|
||||
@ -18,9 +18,6 @@ export default router.post(
|
||||
await u.db("o_agentWorkData").where("projectId", id).delete();
|
||||
const novelData = await u.db("o_novel").where("projectId", id).select("id");
|
||||
const novelId = novelData.map((item: any) => item.id);
|
||||
if (novelId.length > 0) {
|
||||
await u.db("o_outlineNovel").whereIn("novelId", novelId).delete();
|
||||
}
|
||||
//删除项目下的原文
|
||||
await u.db("o_novel").where("projectId", id).delete();
|
||||
// 删除项目下的剧本信息
|
||||
|
||||
@ -41,6 +41,11 @@ export default (nsp: Namespace) => {
|
||||
});
|
||||
let abortController: AbortController | null = null;
|
||||
|
||||
const thinkConfig: agent.AgentContext["thinkConfig"] = {
|
||||
think: false,
|
||||
thinlLevel: 0,
|
||||
};
|
||||
|
||||
socket.on("updateContext", (data: { isolationKey: string; projectId: number; scriptId: number }, callback) => {
|
||||
isolationKey = data.isolationKey;
|
||||
resTool = new ResTool(socket, {
|
||||
@ -66,46 +71,11 @@ export default (nsp: Namespace) => {
|
||||
abortSignal: currentController.signal,
|
||||
resTool,
|
||||
msg,
|
||||
thinkConfig,
|
||||
};
|
||||
|
||||
try {
|
||||
const textStream = await agent.decisionAI(ctx);
|
||||
|
||||
let currentMsg = ctx.msg;
|
||||
let text = currentMsg.text();
|
||||
|
||||
const syncCurrentMessage = () => {
|
||||
if (ctx.msg === currentMsg) return;
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
text = currentMsg.text();
|
||||
};
|
||||
|
||||
let aborted = false;
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
syncCurrentMessage();
|
||||
text.append(chunk);
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err.name === "AbortError" || currentController.signal.aborted) {
|
||||
aborted = true;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
syncCurrentMessage();
|
||||
if (aborted) {
|
||||
text.append("[已停止]");
|
||||
text.complete();
|
||||
currentMsg.stop();
|
||||
} else {
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
}
|
||||
}
|
||||
await agent.runDecisionAI(ctx);
|
||||
} catch (err: any) {
|
||||
if (err.name !== "AbortError" && !currentController.signal.aborted) {
|
||||
const errorMsg = u.error(err).message;
|
||||
@ -120,6 +90,12 @@ export default (nsp: Namespace) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("updateThinkConfig", (data: { think: boolean; thinlLevel: 0 | 1 | 2 | 3 }) => {
|
||||
thinkConfig.think = data.think;
|
||||
thinkConfig.thinlLevel = data.thinlLevel;
|
||||
console.log("[productionAgent] 更新思考配置:", thinkConfig);
|
||||
});
|
||||
|
||||
socket.on("stop", () => {
|
||||
abortController?.abort();
|
||||
abortController = null;
|
||||
|
||||
@ -40,6 +40,11 @@ export default (nsp: Namespace) => {
|
||||
});
|
||||
let abortController: AbortController | null = null;
|
||||
|
||||
const thinkConfig: agent.AgentContext["thinkConfig"] = {
|
||||
think:false,
|
||||
thinlLevel: 0,
|
||||
}
|
||||
|
||||
socket.on("chat", async (data: { content: string }) => {
|
||||
const { content } = data;
|
||||
abortController?.abort();
|
||||
@ -55,45 +60,11 @@ export default (nsp: Namespace) => {
|
||||
abortSignal: currentController.signal,
|
||||
resTool,
|
||||
msg,
|
||||
thinkConfig,
|
||||
};
|
||||
|
||||
try {
|
||||
const textStream = await agent.decisionAI(ctx);
|
||||
|
||||
let currentMsg = ctx.msg;
|
||||
let text = currentMsg.text();
|
||||
|
||||
const syncCurrentMessage = () => {
|
||||
if (ctx.msg === currentMsg) return;
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
text = currentMsg.text();
|
||||
};
|
||||
|
||||
let aborted = false;
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
syncCurrentMessage();
|
||||
text.append(chunk);
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err.name === "AbortError" || currentController.signal.aborted) {
|
||||
aborted = true;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
syncCurrentMessage();
|
||||
if (aborted) {
|
||||
text.complete();
|
||||
currentMsg.stop();
|
||||
} else {
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
}
|
||||
}
|
||||
await agent.runDecisionAI(ctx);
|
||||
} catch (err: any) {
|
||||
if (err.name !== "AbortError" && !currentController.signal.aborted) {
|
||||
const errorMsg = u.error(err).message;
|
||||
@ -108,6 +79,12 @@ export default (nsp: Namespace) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("updateThinkConfig", (data: { think: boolean; thinlLevel: 0 | 1 | 2 | 3 }) => {
|
||||
thinkConfig.think = data.think;
|
||||
thinkConfig.thinlLevel = data.thinlLevel;
|
||||
console.log("[scriptAgent] 更新思考配置:", thinkConfig);
|
||||
});
|
||||
|
||||
socket.on("stop", () => {
|
||||
abortController?.abort();
|
||||
abortController = null;
|
||||
|
||||
2
src/types/database.d.ts
vendored
2
src/types/database.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
// @db-hash 3296433eb24314b094ac5d3839c049c5
|
||||
// @db-hash 9248d7bcfe0a1bc57e5b9bc33d8c7d83
|
||||
//该文件由脚本自动生成,请勿手动修改
|
||||
|
||||
export interface memories {
|
||||
|
||||
@ -23,7 +23,7 @@ async function getVendorTemplateFn(
|
||||
): Promise<(think?: boolean, thinkLevel?: 0 | 1 | 2 | 3) => any>;
|
||||
async function getVendorTemplateFn(fnName: Exclude<FnName, "textRequest">, modelName: `${string}:${string}`): Promise<(input: any) => any>;
|
||||
async function getVendorTemplateFn(fnName: FnName, modelName: `${string}:${string}`): Promise<any> {
|
||||
const [id, name] = modelName.split(":");
|
||||
const [id, name] = modelName.split(/:(.+)/);
|
||||
const vendorConfigData = await u.db("o_vendorConfig").where("id", id).first();
|
||||
if (!vendorConfigData) throw new Error(`未找到供应商配置 id=${id}`);
|
||||
const modelList = await u.vendor.getModelList(id);
|
||||
@ -55,7 +55,7 @@ async function withTaskRecord<T>(
|
||||
fn: (modelName: `${string}:${string}`, think: Boolean, thinkLevel: 0 | 1 | 2 | 3) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const modelName = await resolveModelName(modelKey);
|
||||
const [id, model] = modelName.split(":");
|
||||
const [_, model] = modelName.split(/:(.+)/);
|
||||
const taskRecord = await u.task(projectId, taskClass, model, { describe: describe, content: relatedObjects });
|
||||
try {
|
||||
const result = await fn(modelName, false, 0);
|
||||
@ -89,46 +89,29 @@ class AiText {
|
||||
this.think = think;
|
||||
this.thinkLevel = thinkLevel;
|
||||
}
|
||||
async invoke(input: Omit<Parameters<typeof generateText>[0], "model">) {
|
||||
private async resolveModel(middleware?: any | any[]) {
|
||||
const switchAiDevTool = await u.db("o_setting").where("key", "switchAiDevTool").first();
|
||||
const modelName = await resolveModelName(this.AiType);
|
||||
const sdkFn = await getVendorTemplateFn("textRequest", modelName);
|
||||
const baseModel = await sdkFn(this.think, this.thinkLevel);
|
||||
const mws = [
|
||||
...(switchAiDevTool?.value === "1" ? [devToolsMiddleware()] : []),
|
||||
...(middleware ? (Array.isArray(middleware) ? middleware : [middleware]) : []),
|
||||
];
|
||||
return mws.length > 0 ? wrapLanguageModel({ model: baseModel, middleware: mws.length === 1 ? mws[0] : mws }) : baseModel;
|
||||
}
|
||||
async invoke(input: Omit<Parameters<typeof generateText>[0], "model">) {
|
||||
return generateText({
|
||||
...(input.tools && { stopWhen: stepCountIs(Object.keys(input.tools).length * 50) }),
|
||||
...input,
|
||||
model:
|
||||
switchAiDevTool?.value === "1"
|
||||
? wrapLanguageModel({
|
||||
model: await sdkFn(this.think, this.thinkLevel),
|
||||
middleware: devToolsMiddleware(),
|
||||
})
|
||||
: await sdkFn(this.think, this.thinkLevel),
|
||||
model: await this.resolveModel(),
|
||||
} as Parameters<typeof generateText>[0]);
|
||||
}
|
||||
async stream(input: Omit<Parameters<typeof streamText>[0], "model">) {
|
||||
const switchAiDevTool = await u.db("o_setting").where("key", "switchAiDevTool").first();
|
||||
const modelName = await resolveModelName(this.AiType);
|
||||
const sdkFn = await getVendorTemplateFn("textRequest", modelName);
|
||||
return streamText({
|
||||
...(input.tools && { stopWhen: stepCountIs(Object.keys(input.tools).length * 50) }),
|
||||
...input,
|
||||
model:
|
||||
switchAiDevTool?.value == "1"
|
||||
? wrapLanguageModel({
|
||||
model: sdkFn(this.think, this.thinkLevel),
|
||||
middleware: [
|
||||
devToolsMiddleware(),
|
||||
extractReasoningMiddleware({
|
||||
tagName: "reasoning_content",
|
||||
}),
|
||||
],
|
||||
})
|
||||
: wrapLanguageModel({
|
||||
model: sdkFn(this.think, this.thinkLevel),
|
||||
middleware: extractReasoningMiddleware({
|
||||
tagName: "reasoning_content",
|
||||
}),
|
||||
}),
|
||||
model: await this.resolveModel(extractReasoningMiddleware({ tagName: "reasoning_content", separator: "\n" })),
|
||||
} as Parameters<typeof streamText>[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user