| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /**
- * 书籍生成工作流引擎
- * 参考 LangGraph 思路:状态机 + 条件边 + 节点执行
- */
- import { Book, BookOutline, Chapter, GenerateTask } from './book-generator.types';
- import { bookGeneratorService } from './book-generator.service';
- import { bookStore } from './book-generator.store';
- // ============ 工作流状态 ============
- /** 工作流节点类型 */
- export type WorkflowNode = 'idle' | 'planning' | 'writing_chapter' | 'writing_foreword' | 'writing_afterword' | 'finished' | 'failed';
- /** 工作流边类型 */
- export type WorkflowEdge =
- | 'plan_next' // 规划下一步
- | 'write_next_chapter' // 写下一章
- | 'finish_chapter' // 本章写完
- | 'all_chapters_done' // 全部章节写完
- | 'finish_foreword' // 前言写完
- | 'finish_afterword' // 后记写完
- | 'error'; // 发生错误
- /** 工作流状态 */
- export interface WorkflowState {
- bookId: string;
- currentNode: WorkflowNode;
- currentChapter: number; // 当前在写第几章
- totalChapters: number;
- completedChapters: number;
- pendingChapters: number[]; // 待生成的章节列表
- failedChapters: number[]; // 失败的章节列表
- phase: 'planning' | 'writing' | 'supplement' | 'done';
- error?: string;
- startedAt: Date;
- updatedAt: Date;
- }
- // ============ 工作流引擎 ============
- class BookWorkflowEngine {
- private workflows: Map<string, WorkflowState> = new Map();
- /**
- * 启动工作流
- */
- startWorkflow(bookId: string, totalChapters: number): WorkflowState {
- const state: WorkflowState = {
- bookId,
- currentNode: 'idle',
- currentChapter: 0,
- totalChapters,
- completedChapters: 0,
- pendingChapters: Array.from({ length: totalChapters }, (_, i) => i + 1),
- failedChapters: [],
- phase: 'planning',
- startedAt: new Date(),
- updatedAt: new Date(),
- };
- this.workflows.set(bookId, state);
- return state;
- }
- /**
- * 获取工作流状态
- */
- getState(bookId: string): WorkflowState | undefined {
- return this.workflows.get(bookId);
- }
- /**
- * 更新工作流状态
- */
- private updateState(bookId: string, updates: Partial<WorkflowState>): WorkflowState | undefined {
- const state = this.workflows.get(bookId);
- if (!state) return undefined;
- Object.assign(state, updates, { updatedAt: new Date() });
- return state;
- }
- /**
- * 执行规划阶段
- */
- async executePlanningPhase(bookId: string): Promise<{ success: boolean; outline?: BookOutline; error?: string }> {
- const state = this.workflows.get(bookId);
- if (!state) return { success: false, error: '工作流不存在' };
- this.updateState(bookId, { currentNode: 'planning', phase: 'planning' });
- try {
- const outline = await bookGeneratorService.generateOutline(bookId);
- // 更新工作流状态
- this.updateState(bookId, {
- currentNode: 'idle',
- phase: 'writing',
- pendingChapters: outline.chapters.map(c => c.number),
- });
- return { success: true, outline };
- } catch (error) {
- const errorMessage = error instanceof Error ? error.message : '规划失败';
- this.updateState(bookId, { currentNode: 'failed', error: errorMessage });
- return { success: false, error: errorMessage };
- }
- }
- /**
- * 执行章节生成 - 单步
- * 返回下一步应该执行什么
- */
- async executeNextChapter(bookId: string): Promise<{
- done: boolean;
- chapter?: Chapter;
- nextChapter?: number;
- error?: string;
- }> {
- const state = this.workflows.get(bookId);
- if (!state) return { done: false, error: '工作流不存在' };
- if (state.pendingChapters.length === 0) {
- return { done: true };
- }
- // 取下一个待生成的章节
- const nextChapterNum = state.pendingChapters[0];
- this.updateState(bookId, {
- currentNode: 'writing_chapter',
- currentChapter: nextChapterNum,
- });
- try {
- const chapter = await bookGeneratorService.generateChapter(bookId, nextChapterNum);
- // 更新工作流状态
- const newPending = state.pendingChapters.filter(n => n !== nextChapterNum);
- this.updateState(bookId, {
- currentNode: 'idle',
- completedChapters: state.completedChapters + 1,
- pendingChapters: newPending,
- });
- if (newPending.length === 0) {
- // 全部章节完成
- this.updateState(bookId, { phase: 'supplement' });
- return { done: true, chapter };
- }
- return { done: false, chapter, nextChapter: newPending[0] };
- } catch (error) {
- const errorMessage = error instanceof Error ? error.message : '生成失败';
- // 标记本章失败,继续下一章
- const newPending = state.pendingChapters.filter(n => n !== nextChapterNum);
- const newFailed = [...state.failedChapters, nextChapterNum];
- this.updateState(bookId, {
- currentNode: 'idle',
- pendingChapters: newPending,
- failedChapters: newFailed,
- });
- if (newPending.length === 0) {
- return { done: true, error: `第${nextChapterNum}章失败` };
- }
- return { done: false, error: `第${nextChapterNum}章失败: ${errorMessage}` };
- }
- }
- /**
- * 执行全部章节生成(自动循环)
- */
- async executeAllChapters(bookId: string, onProgress?: (progress: number, chapterNum: number) => void): Promise<{
- success: boolean;
- completedCount: number;
- failedCount: number;
- errors: string[];
- }> {
- const state = this.workflows.get(bookId);
- if (!state) return { success: false, completedCount: 0, failedCount: 0, errors: ['工作流不存在'] };
- const errors: string[] = [];
- while (true) {
- const currentState = this.workflows.get(bookId);
- if (!currentState || currentState.pendingChapters.length === 0) {
- break;
- }
- const nextChapter = currentState.pendingChapters[0];
- if (onProgress) {
- const progress = Math.round((currentState.completedChapters / currentState.totalChapters) * 100);
- onProgress(progress, nextChapter);
- }
- try {
- await bookGeneratorService.generateChapter(bookId, nextChapter);
- const updated = this.workflows.get(bookId);
- if (updated) {
- this.updateState(bookId, {
- completedChapters: updated.completedChapters + 1,
- pendingChapters: updated.pendingChapters.filter(n => n !== nextChapter),
- });
- }
- } catch (error) {
- const errorMessage = error instanceof Error ? error.message : '生成失败';
- errors.push(`第${nextChapter}章: ${errorMessage}`);
- const updated = this.workflows.get(bookId);
- if (updated) {
- this.updateState(bookId, {
- pendingChapters: updated.pendingChapters.filter(n => n !== nextChapter),
- failedChapters: [...updated.failedChapters, nextChapter],
- });
- }
- }
- }
- this.updateState(bookId, { phase: 'supplement' });
- const finalState = this.workflows.get(bookId);
- return {
- success: errors.length === 0,
- completedCount: finalState?.completedChapters || 0,
- failedCount: finalState?.failedChapters?.length || 0,
- errors,
- };
- }
- /**
- * 生成前言
- */
- async executeForeword(bookId: string): Promise<{ success: boolean; foreword?: string; error?: string }> {
- this.updateState(bookId, { currentNode: 'writing_foreword' });
- try {
- const foreword = await bookGeneratorService.generateForeword(bookId);
- this.updateState(bookId, { currentNode: 'idle' });
- return { success: true, foreword };
- } catch (error) {
- const errorMessage = error instanceof Error ? error.message : '生成前言失败';
- return { success: false, error: errorMessage };
- }
- }
- /**
- * 生成后记
- */
- async executeAfterword(bookId: string): Promise<{ success: boolean; afterword?: string; error?: string }> {
- this.updateState(bookId, { currentNode: 'writing_afterword' });
- try {
- const afterword = await bookGeneratorService.generateAfterword(bookId);
- this.updateState(bookId, { currentNode: 'idle' });
- return { success: true, afterword };
- } catch (error) {
- const errorMessage = error instanceof Error ? error.message : '生成后记失败';
- return { success: false, error: errorMessage };
- }
- }
- /**
- * 完成工作流
- */
- finishWorkflow(bookId: string): WorkflowState | undefined {
- const state = this.workflows.get(bookId);
- if (!state) return undefined;
- this.updateState(bookId, { currentNode: 'finished', phase: 'done' });
- return this.workflows.get(bookId);
- }
- /**
- * 获取工作流进度
- */
- getProgress(bookId: string): {
- phase: string;
- currentNode: string;
- currentChapter: number;
- completedChapters: number;
- totalChapters: number;
- pendingChapters: number[];
- failedChapters: number[];
- progress: number;
- } | null {
- const state = this.workflows.get(bookId);
- if (!state) return null;
- return {
- phase: state.phase,
- currentNode: state.currentNode,
- currentChapter: state.currentChapter,
- completedChapters: state.completedChapters,
- totalChapters: state.totalChapters,
- pendingChapters: state.pendingChapters,
- failedChapters: state.failedChapters,
- progress: Math.round((state.completedChapters / state.totalChapters) * 100),
- };
- }
- /**
- * 取消工作流
- */
- cancelWorkflow(bookId: string): boolean {
- return this.workflows.delete(bookId);
- }
- }
- // 导出单例
- export const workflowEngine = new BookWorkflowEngine();
|