# Conflicts:
#	src/router.ts
#	src/types/database.d.ts
This commit is contained in:
小帅 2026-03-23 17:44:10 +08:00
commit 2367a7bc5e
12 changed files with 268 additions and 290 deletions

View File

@ -32,6 +32,16 @@ export default (resTool: ResTool, toolsNames?: string[]) => {
return planData[key];
},
}),
get_novel_text: tool({
description: "获取小说章节原始文本内容",
inputSchema: z.object({
id: z.string().describe("章节id"),
}),
execute: async ({ id }) => {
console.log(id);
return "";
},
}),
set_planData_event: tool({
description: "保存章节事件到工作区",
inputSchema: z.object({ value: planData.shape.event }),

View File

@ -202,6 +202,8 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
table.text("chapter");
table.text("chapterData");
table.integer("projectId");
table.integer("eventState");
table.text("event");
table.integer("createTime");
table.primary(["id"]);
table.unique(["id"]);

View File

@ -1,4 +1,4 @@
// @routes-hash 0a85dfe35e0882ce29f9d4fc68c3fd73
// @routes-hash 30de02ae85f1e841f356d128583a5867
import { Express } from "express";
import route1 from "./routes/agents/clearMemory";
@ -31,50 +31,52 @@ import route27 from "./routes/novel/event/deletEvent";
import route28 from "./routes/novel/event/generateEvents";
import route29 from "./routes/novel/event/getEvent";
import route30 from "./routes/novel/getNovel";
import route31 from "./routes/novel/updateNovel";
import route32 from "./routes/other/deleteAllData";
import route33 from "./routes/other/getCaptcha";
import route34 from "./routes/production/editStoryboard/generateStoryboardImage";
import route35 from "./routes/production/editStoryboard/getStoryboardFlow";
import route36 from "./routes/production/editStoryboard/saveStoryboardFlow";
import route37 from "./routes/production/editStoryboard/updateStoryboardFlow";
import route38 from "./routes/production/exportImage";
import route39 from "./routes/production/getFlowData";
import route40 from "./routes/production/getProductionData";
import route41 from "./routes/production/getStoryboardData";
import route42 from "./routes/production/saveFlowData";
import route43 from "./routes/production/workbench/confirmSelection";
import route44 from "./routes/production/workbench/delVideo";
import route45 from "./routes/production/workbench/generateVideo";
import route46 from "./routes/production/workbench/getVideoModelDetail";
import route47 from "./routes/production/workbench/videoPolling";
import route48 from "./routes/project/addProject";
import route49 from "./routes/project/delProject";
import route50 from "./routes/project/editProject";
import route51 from "./routes/project/getProject";
import route52 from "./routes/script/addScript";
import route53 from "./routes/script/delScript";
import route54 from "./routes/script/exportScript";
import route55 from "./routes/script/getScrptApi";
import route56 from "./routes/script/updateScript";
import route57 from "./routes/setting/agentDeploy/deployAgentModel";
import route58 from "./routes/setting/agentDeploy/getAgentDeploy";
import route59 from "./routes/setting/agentDeploy/updateKey";
import route60 from "./routes/setting/dbConfig/clearData";
import route61 from "./routes/setting/getTextModel";
import route62 from "./routes/setting/loginConfig/getUser";
import route63 from "./routes/setting/loginConfig/updateUserPwd";
import route64 from "./routes/setting/memoryConfig/getMemory";
import route65 from "./routes/setting/memoryConfig/sureMemory";
import route66 from "./routes/setting/vendorConfig/addVendor";
import route67 from "./routes/setting/vendorConfig/deleteVendor";
import route68 from "./routes/setting/vendorConfig/getVendorList";
import route69 from "./routes/setting/vendorConfig/modelTest";
import route70 from "./routes/setting/vendorConfig/updateVendor";
import route71 from "./routes/task/getTaskApi";
import route72 from "./routes/task/getTaskCategories";
import route73 from "./routes/task/taskDetails";
import route74 from "./routes/test/test";
import route31 from "./routes/novel/getNovelEventState";
import route32 from "./routes/novel/getNovelIndex";
import route33 from "./routes/novel/updateNovel";
import route34 from "./routes/other/deleteAllData";
import route35 from "./routes/other/getCaptcha";
import route36 from "./routes/production/assets/getAssetsData";
import route37 from "./routes/production/editStoryboard/generateStoryboardImage";
import route38 from "./routes/production/editStoryboard/getStoryboardFlow";
import route39 from "./routes/production/editStoryboard/saveStoryboardFlow";
import route40 from "./routes/production/editStoryboard/updateStoryboardFlow";
import route41 from "./routes/production/getFlowData";
import route42 from "./routes/production/getProductionData";
import route43 from "./routes/production/getStoryboardData";
import route44 from "./routes/production/saveFlowData";
import route45 from "./routes/production/workbench/confirmSelection";
import route46 from "./routes/production/workbench/delVideo";
import route47 from "./routes/production/workbench/generateVideo";
import route48 from "./routes/production/workbench/getVideoModelDetail";
import route49 from "./routes/production/workbench/videoPolling";
import route50 from "./routes/project/addProject";
import route51 from "./routes/project/delProject";
import route52 from "./routes/project/editProject";
import route53 from "./routes/project/getProject";
import route54 from "./routes/script/addScript";
import route55 from "./routes/script/delScript";
import route56 from "./routes/script/exportScript";
import route57 from "./routes/script/getScrptApi";
import route58 from "./routes/script/updateScript";
import route59 from "./routes/setting/agentDeploy/deployAgentModel";
import route60 from "./routes/setting/agentDeploy/getAgentDeploy";
import route61 from "./routes/setting/agentDeploy/updateKey";
import route62 from "./routes/setting/dbConfig/clearData";
import route63 from "./routes/setting/getTextModel";
import route64 from "./routes/setting/loginConfig/getUser";
import route65 from "./routes/setting/loginConfig/updateUserPwd";
import route66 from "./routes/setting/memoryConfig/getMemory";
import route67 from "./routes/setting/memoryConfig/sureMemory";
import route68 from "./routes/setting/vendorConfig/addVendor";
import route69 from "./routes/setting/vendorConfig/deleteVendor";
import route70 from "./routes/setting/vendorConfig/getVendorList";
import route71 from "./routes/setting/vendorConfig/modelTest";
import route72 from "./routes/setting/vendorConfig/updateVendor";
import route73 from "./routes/task/getTaskApi";
import route74 from "./routes/task/getTaskCategories";
import route75 from "./routes/task/taskDetails";
import route76 from "./routes/test/test";
export default async (app: Express) => {
app.use("/api/agents/clearMemory", route1);
@ -107,48 +109,50 @@ export default async (app: Express) => {
app.use("/api/novel/event/generateEvents", route28);
app.use("/api/novel/event/getEvent", route29);
app.use("/api/novel/getNovel", route30);
app.use("/api/novel/updateNovel", route31);
app.use("/api/other/deleteAllData", route32);
app.use("/api/other/getCaptcha", route33);
app.use("/api/production/editStoryboard/generateStoryboardImage", route34);
app.use("/api/production/editStoryboard/getStoryboardFlow", route35);
app.use("/api/production/editStoryboard/saveStoryboardFlow", route36);
app.use("/api/production/editStoryboard/updateStoryboardFlow", route37);
app.use("/api/production/exportImage", route38);
app.use("/api/production/getFlowData", route39);
app.use("/api/production/getProductionData", route40);
app.use("/api/production/getStoryboardData", route41);
app.use("/api/production/saveFlowData", route42);
app.use("/api/production/workbench/confirmSelection", route43);
app.use("/api/production/workbench/delVideo", route44);
app.use("/api/production/workbench/generateVideo", route45);
app.use("/api/production/workbench/getVideoModelDetail", route46);
app.use("/api/production/workbench/videoPolling", route47);
app.use("/api/project/addProject", route48);
app.use("/api/project/delProject", route49);
app.use("/api/project/editProject", route50);
app.use("/api/project/getProject", route51);
app.use("/api/script/addScript", route52);
app.use("/api/script/delScript", route53);
app.use("/api/script/exportScript", route54);
app.use("/api/script/getScrptApi", route55);
app.use("/api/script/updateScript", route56);
app.use("/api/setting/agentDeploy/deployAgentModel", route57);
app.use("/api/setting/agentDeploy/getAgentDeploy", route58);
app.use("/api/setting/agentDeploy/updateKey", route59);
app.use("/api/setting/dbConfig/clearData", route60);
app.use("/api/setting/getTextModel", route61);
app.use("/api/setting/loginConfig/getUser", route62);
app.use("/api/setting/loginConfig/updateUserPwd", route63);
app.use("/api/setting/memoryConfig/getMemory", route64);
app.use("/api/setting/memoryConfig/sureMemory", route65);
app.use("/api/setting/vendorConfig/addVendor", route66);
app.use("/api/setting/vendorConfig/deleteVendor", route67);
app.use("/api/setting/vendorConfig/getVendorList", route68);
app.use("/api/setting/vendorConfig/modelTest", route69);
app.use("/api/setting/vendorConfig/updateVendor", route70);
app.use("/api/task/getTaskApi", route71);
app.use("/api/task/getTaskCategories", route72);
app.use("/api/task/taskDetails", route73);
app.use("/api/test/test", route74);
app.use("/api/novel/getNovelEventState", route31);
app.use("/api/novel/getNovelIndex", route32);
app.use("/api/novel/updateNovel", route33);
app.use("/api/other/deleteAllData", route34);
app.use("/api/other/getCaptcha", route35);
app.use("/api/production/assets/getAssetsData", route36);
app.use("/api/production/editStoryboard/generateStoryboardImage", route37);
app.use("/api/production/editStoryboard/getStoryboardFlow", route38);
app.use("/api/production/editStoryboard/saveStoryboardFlow", route39);
app.use("/api/production/editStoryboard/updateStoryboardFlow", route40);
app.use("/api/production/getFlowData", route41);
app.use("/api/production/getProductionData", route42);
app.use("/api/production/getStoryboardData", route43);
app.use("/api/production/saveFlowData", route44);
app.use("/api/production/workbench/confirmSelection", route45);
app.use("/api/production/workbench/delVideo", route46);
app.use("/api/production/workbench/generateVideo", route47);
app.use("/api/production/workbench/getVideoModelDetail", route48);
app.use("/api/production/workbench/videoPolling", route49);
app.use("/api/project/addProject", route50);
app.use("/api/project/delProject", route51);
app.use("/api/project/editProject", route52);
app.use("/api/project/getProject", route53);
app.use("/api/script/addScript", route54);
app.use("/api/script/delScript", route55);
app.use("/api/script/exportScript", route56);
app.use("/api/script/getScrptApi", route57);
app.use("/api/script/updateScript", route58);
app.use("/api/setting/agentDeploy/deployAgentModel", route59);
app.use("/api/setting/agentDeploy/getAgentDeploy", route60);
app.use("/api/setting/agentDeploy/updateKey", route61);
app.use("/api/setting/dbConfig/clearData", route62);
app.use("/api/setting/getTextModel", route63);
app.use("/api/setting/loginConfig/getUser", route64);
app.use("/api/setting/loginConfig/updateUserPwd", route65);
app.use("/api/setting/memoryConfig/getMemory", route66);
app.use("/api/setting/memoryConfig/sureMemory", route67);
app.use("/api/setting/vendorConfig/addVendor", route68);
app.use("/api/setting/vendorConfig/deleteVendor", route69);
app.use("/api/setting/vendorConfig/getVendorList", route70);
app.use("/api/setting/vendorConfig/modelTest", route71);
app.use("/api/setting/vendorConfig/updateVendor", route72);
app.use("/api/task/getTaskApi", route73);
app.use("/api/task/getTaskCategories", route74);
app.use("/api/task/taskDetails", route75);
app.use("/api/test/test", route76);
}

View File

@ -16,23 +16,35 @@ export default router.post(
reel: z.string(),
chapter: z.string(),
chapterData: z.string(),
})
}),
),
}),
async (req, res) => {
const { projectId, data } = req.body;
const totalNovelId = [];
for (const item of data) {
await u.db("o_novel").insert({
const [id] = await u.db("o_novel").insert({
projectId,
chapterIndex: item.index,
reel: item.reel,
chapter: item.chapter,
chapterData: item.chapterData,
createTime: Date.now(),
eventState: 0,
});
totalNovelId.push(id);
}
const chapterAllList = await u.db("o_novel").where("projectId", projectId).whereIn("id", totalNovelId);
const novelClass = new u.cleanNovel();
novelClass.emitter.on("item", async (item) => {
if (item.event)
await u
.db("o_novel")
.where("id", item.id)
.update({ event: item.event, eventState: item.event ? 1 : -1 });
});
novelClass.start(chapterAllList, projectId);
res.status(200).send(success({ message: "新增原文成功" }));
}
},
);

View File

@ -6,84 +6,31 @@ import { validateFields } from "@/middleware/middleware";
const router = express.Router();
// 解析章节字符串,支持逗号分隔的多段(如 "1-3,5,7-9"
function parseChapters(str: string): number[] {
const result: number[] = [];
// 逗号和空格之间加以划分
const segments = str
.split(",")
.map((s) => s.replace(/[^\d\-]/g, "").trim())
.filter(Boolean);
for (const seg of segments) {
// 匹配区间
if (/^\d+\-\d+$/.test(seg)) {
const [start, end] = seg.split("-").map(Number);
if (start <= end) {
for (let i = start; i <= end; i++) result.push(i);
}
} else if (/^\d+$/.test(seg)) {
result.push(Number(seg));
}
// 其它格式自动忽略
}
return result;
}
parseChapters("7-8章");
// 清洗小说原文,生成事件列表
export default router.post(
"/",
validateFields({
projectId: z.number(),
windowSize: z.number().optional().default(5), // 每组数量,默认 5
overlap: z.number().optional().default(1), // 交叠数量,默认 1
novelIds: z.array(z.number()),
}),
async (req, res) => {
const { projectId, windowSize, overlap } = req.body;
//删除之前的事件
const { projectId, novelIds } = req.body;
const [allChapters, novel] = await Promise.all([
u.db("o_novel").where("projectId", projectId),
Promise.resolve(new u.cleanNovel(windowSize, overlap)),
u.db("o_novel").where("projectId", projectId).whereIn("id", novelIds),
Promise.resolve(new u.cleanNovel()),
]);
const novelIds = allChapters.map((i) => i.id);
await u
.db("o_eventChapter")
.whereIn("novelId", novelIds as number[])
.delete();
const eventIds = await u.db("o_eventChapter").whereIn("novelId", novelIds).select("eventId").pluck("eventId");
await u.db("o_novel").where("projectId", projectId).update({ eventState: 0, event: null });
novel.emitter.on("item", async (item) => {
if (item.event)
await u
.db("o_novel")
.where("id", item.id)
.update({ event: item.event, eventState: item.event ? 1 : -1 });
});
novel.start(allChapters, projectId);
await u
.db("o_event")
.whereIn("id", eventIds as number[])
.delete();
const data = await novel.start(allChapters, projectId);
const chapterMap = new Map(allChapters.map((c) => [c.chapterIndex, c]));
const novelEvent: { eventId: number; novelId: number }[] = [];
const now = Date.now();
for (const item of data) {
const [id] = await u.db("o_event").insert({
name: item.name,
detail: item.detail,
createTime: now,
});
parseChapters(item.chapter).forEach((chapterIndex) => {
const chapter = chapterMap.get(chapterIndex);
if (chapter) {
novelEvent.push({ eventId: id, novelId: chapter.id! });
}
});
}
if (novelEvent.length > 0) {
await u.db("o_eventChapter").insert(novelEvent);
}
return res.status(200).send(success(data));
return res.status(200).send(success("生成事件成功"));
},
);

View File

@ -6,10 +6,6 @@ import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
// CREATE TABLE `o_event` (`id` integer not null, `name` varchar(255), `detail` varchar(255), `createTime` integer, primary key (`id`));
// CREATE TABLE `o_eventChapter` (`id` integer not null, `eventId` integer, `novelId` integer, foreign key(`eventId`) references `o_event`(`id`), foreign key(`novelId`) references `o_novel`(`id`), primary key (`id`));
// CREATE TABLE `o_novel` (`id` integer not null, `chapterIndex` integer, `reel` text, `chapter` text, `chapterData` text, `projectId` integer, `createTime` integer, primary key (`id`));
export default router.post(
"/",
validateFields({
@ -43,13 +39,7 @@ export default router.post(
// 分页查询:每个事件对应多个 chapterIndex用 GROUP_CONCAT 聚合
const rows = await baseQuery
.clone()
.select(
"e.id",
"e.name as eventName",
"e.detail",
"e.createTime",
db.raw("GROUP_CONCAT(n.chapterIndex) as chapterIndexes"),
)
.select("e.id", "e.name as eventName", "e.detail", "e.createTime", db.raw("GROUP_CONCAT(n.chapterIndex) as chapterIndexes"))
.groupBy("e.id")
.limit(limit)
.offset(offset);

View File

@ -13,7 +13,6 @@ export default router.post(
page: z.number(),
limit: z.number(),
search: z.string().optional(),
}),
async (req, res) => {
const { projectId, page, limit, search } = req.body;
@ -21,7 +20,7 @@ export default router.post(
const data = await u
.db("o_novel")
.where("projectId", projectId)
.select("id", "chapterIndex as index", "reel", "chapter", "chapterData")
.select("id", "chapterIndex as index", "reel", "chapter", "chapterData", "event", "eventState")
.andWhere((qb) => {
if (search) {
qb.where("chapter", "like", `%${search}%`);
@ -30,6 +29,7 @@ export default router.post(
.orderBy("chapterIndex", "asc")
.limit(limit)
.offset(offset);
// 统计总数
const totalQuery = (await u
.db("o_novel")
@ -43,5 +43,5 @@ export default router.post(
.first()) as any;
res.status(200).send(success({ data, total: totalQuery.total }));
}
},
);

View File

@ -0,0 +1,19 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
// 获取原文数据
export default router.post(
"/",
validateFields({
ids: z.array(z.number()),
}),
async (req, res) => {
const { ids } = req.body;
const data = await u.db("o_novel").whereIn("id", ids).whereNot("eventState", 0).select("id", "event", "eventState");
res.status(200).send(success(data));
},
);

View File

@ -0,0 +1,19 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post(
"/",
validateFields({
projectId: z.number(),
}),
async (req, res) => {
const { projectId } = req.body;
const data = await u.db("o_novel").where("projectId", projectId).select("id", "chapterIndex as index", "chapter").orderBy("chapterIndex", "asc");
res.status(200).send(success(data));
},
);

View File

@ -14,15 +14,17 @@ export default router.post(
reel: z.string(),
chapter: z.string(),
chapterData: z.string(),
event: z.string(),
}),
async (req, res) => {
const { id, index, reel, chapter, chapterData } = req.body;
const { id, index, reel, chapter, chapterData, event } = req.body;
await u.db("o_novel").where("id", id).update({
chapterIndex: index,
reel,
chapter,
chapterData,
event: event,
});
res.status(200).send(success({ message: "更新原文成功" }));

View File

@ -0,0 +1,60 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
import { o_assets } from "@/types/database";
const router = express.Router();
export default router.post(
"/",
validateFields({
projectId: z.number(),
}),
async (req, res) => {
const { projectId } = req.body;
const parentAssetsData = await u.db("o_assets").where("projectId", projectId).whereNotNull("sonId");
const parentIds = parentAssetsData.map((i) => i.id);
const parnetIdsMap: Record<number, number> = {};
const sonAssetsData = await u.db("o_assets").whereIn("sonId", parentIds);
const sonAssetsMap: Record<number, o_assets[]> = {};
const imageIds = [...parentAssetsData.map((i) => i.imageId).concat(sonAssetsData.map((i) => i.imageId))].filter(Boolean);
const imagePaths = await u
.db("o_image")
.whereIn("id", imageIds as unknown as string[])
.select("id", "filePath");
const imageSignUrls = await Promise.all(
imagePaths.map(async (i) => {
return { id: i.id, src: i.filePath ? await u.oss.getFileUrl(i.filePath) : null };
}),
);
const imageUrlMap: Record<number, string | null> = {};
imageSignUrls.forEach((i, index) => {
imageUrlMap[i.id!] = i.src;
});
sonAssetsData.forEach((i) => {
if (!sonAssetsMap[i.sonId!]) {
sonAssetsMap[i.sonId!] = [];
}
const obj = {
assetsId: i.id,
name: i.name,
desc: i.describe,
src: imageUrlMap[i.imageId!] ?? null,
derive: sonAssetsMap[i.id!] ?? [],
};
sonAssetsMap[i.sonId!].push(obj);
});
const returnData = parentAssetsData.map((i) => {
return {
assetsId: i.id,
name: i.name,
desc: i.describe,
src: imageUrlMap[i.imageId!] ?? null,
derive: sonAssetsMap[i.id!] ?? [],
};
});
res.status(200).send(success(returnData));
},
);

View File

@ -1,40 +1,13 @@
import * as z from "zod";
import { ModelMessage, Output } from "ai";
import { EventEmitter } from "events";
import { o_novel } from "@/types/database";
import ai from "@/utils/ai";
import u from "@/utils";
export interface EventType {
name: string;
detail: string;
chapter: string;
}
export interface Novel {
event: EventType[];
}
// 章节拆分
function getChapterGroups<T>(chapters: T[], windowSize: number = 5, overlap: number = 1): T[][] {
const res: T[][] = [];
if (windowSize < 1 || overlap < 0) return res;
let i = 0;
const length = chapters.length;
while (i < length) {
if (res.length === 0) {
// 第一组,直接取 windowSize 个
res.push(chapters.slice(i, i + windowSize));
i += windowSize;
} else {
// 取上一组最后 overlap 个,加上新的 windowSize 个
const prevGroup = res[res.length - 1];
const overlapItems = prevGroup.slice(-overlap);
const newItems = chapters.slice(i, i + windowSize);
if (newItems.length === 0) break; // 已经取完,跳出
res.push([...overlapItems, ...newItems]);
i += windowSize;
}
}
return res;
id: number;
event: string;
}
/*
@ -45,42 +18,18 @@ function getChapterGroups<T>(chapters: T[], windowSize: number = 5, overlap: num
*/
class CleanNovel {
windowSize: number;
overlap: number;
constructor(windowSize: number = 5, overlap: number = 1) {
this.windowSize = windowSize;
this.overlap = overlap;
emitter: EventEmitter;
constructor() {
this.emitter = new EventEmitter();
}
async start(allChapters: o_novel[], projectId: number): Promise<EventType[]> {
const groups = getChapterGroups(allChapters!, this.windowSize, this.overlap);
let preData: Novel | null = null;
//所有事件
let totalEvent: EventType[] = [];
const intansce = u.Ai.Text("eventExtractAi");
try {
for (let gi = 0; gi < groups.length; gi++) {
const group = groups[gi];
// 第一批没有交叠章节,后续批次前 overlap 个是交叠章节(仅作上下文,不输出事件)
const overlapCount = gi === 0 ? 0 : this.overlap;
const overlapChapterIndexes = group.slice(0, overlapCount).map((i) => i.chapterIndex);
const cleanText = group
.map((i, index: number) => {
const isOverlap = overlapChapterIndexes.includes(i.chapterIndex);
return {
role: "user",
content: isOverlap
? `【上文衔接章节,仅供上下文参考,禁止为本章生成情节单元】\n第${i.chapterIndex}章:\n\n${i.chapterData}`
: `${i.chapterIndex}章:\n\n${i.chapterData}`,
} as ModelMessage;
})
.filter(Boolean);
const taskRecord = await u.task(projectId, "事件提取", "gpt-4.1", {
describe: "根据小说原文,提取情节单元",
content: cleanText,
});
for (let gi = 0; gi < allChapters.length; gi++) {
const novel = allChapters[gi];
let resData;
try {
resData = await intansce.invoke({
@ -88,67 +37,31 @@ class CleanNovel {
{
role: "system",
content: `
- 1
- detail 100200
- chapter"1-3章"
- name使"XXX踏上征程""命运转折"
- detail
1.
2. 使
🚫
-
-
-
****
##
-
-
- 100-150
- "发生了什么"
---
`,
},
...cleanText,
{
role: "user",
content: novel.chapterData!,
},
],
output: Output.object({
schema: z.object({
event: z.array(
z
.object({
chapter: z
.string()
.describe(
"事件覆盖的章节如1-3章、4-6章章节划分必须连续每个章节范围只能属于一个事件。事件分割不可过细——避免只描述琐碎、日常细节的微小事件。",
),
name: z.string().describe("事件名称"),
detail: z.string().describe("事件过程详情(包括起因、经过、结果、场景、人物等)"),
})
.describe("事件必须在100-200字说明起因经过结果不可将单一章节或细小场景独立成事件"),
),
}),
}),
});
const preData = resData.text;
this.emitter.emit("item", { id: novel.id, event: preData });
totalEvent.push({ id: novel.id!, event: preData });
} catch (e) {
taskRecord(-1, u.error(e).message);
throw e;
this.emitter.emit("item", { id: novel.id, event: null });
}
taskRecord(1);
preData = JSON.parse(resData.text);
const newEvents = preData?.event || [];
newEvents.forEach((newItem) => {
totalEvent.push({ ...newItem });
});
}
} catch (e) {
console.error(e);