book-generator.workflow.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. "use strict";
  2. /**
  3. * 书籍生成工作流引擎
  4. * 参考 LangGraph 思路:状态机 + 条件边 + 节点执行
  5. */
  6. Object.defineProperty(exports, "__esModule", { value: true });
  7. exports.workflowEngine = void 0;
  8. const book_generator_service_1 = require("./book-generator.service");
  9. // ============ 工作流引擎 ============
  10. class BookWorkflowEngine {
  11. workflows = new Map();
  12. /**
  13. * 启动工作流
  14. */
  15. startWorkflow(bookId, totalChapters) {
  16. const state = {
  17. bookId,
  18. currentNode: 'idle',
  19. currentChapter: 0,
  20. totalChapters,
  21. completedChapters: 0,
  22. pendingChapters: Array.from({ length: totalChapters }, (_, i) => i + 1),
  23. failedChapters: [],
  24. phase: 'planning',
  25. startedAt: new Date(),
  26. updatedAt: new Date(),
  27. };
  28. this.workflows.set(bookId, state);
  29. return state;
  30. }
  31. /**
  32. * 获取工作流状态
  33. */
  34. getState(bookId) {
  35. return this.workflows.get(bookId);
  36. }
  37. /**
  38. * 更新工作流状态
  39. */
  40. updateState(bookId, updates) {
  41. const state = this.workflows.get(bookId);
  42. if (!state)
  43. return undefined;
  44. Object.assign(state, updates, { updatedAt: new Date() });
  45. return state;
  46. }
  47. /**
  48. * 执行规划阶段
  49. */
  50. async executePlanningPhase(bookId) {
  51. const state = this.workflows.get(bookId);
  52. if (!state)
  53. return { success: false, error: '工作流不存在' };
  54. this.updateState(bookId, { currentNode: 'planning', phase: 'planning' });
  55. try {
  56. const outline = await book_generator_service_1.bookGeneratorService.generateOutline(bookId);
  57. // 更新工作流状态
  58. this.updateState(bookId, {
  59. currentNode: 'idle',
  60. phase: 'writing',
  61. pendingChapters: outline.chapters.map(c => c.number),
  62. });
  63. return { success: true, outline };
  64. }
  65. catch (error) {
  66. const errorMessage = error instanceof Error ? error.message : '规划失败';
  67. this.updateState(bookId, { currentNode: 'failed', error: errorMessage });
  68. return { success: false, error: errorMessage };
  69. }
  70. }
  71. /**
  72. * 执行章节生成 - 单步
  73. * 返回下一步应该执行什么
  74. */
  75. async executeNextChapter(bookId) {
  76. const state = this.workflows.get(bookId);
  77. if (!state)
  78. return { done: false, error: '工作流不存在' };
  79. if (state.pendingChapters.length === 0) {
  80. return { done: true };
  81. }
  82. // 取下一个待生成的章节
  83. const nextChapterNum = state.pendingChapters[0];
  84. this.updateState(bookId, {
  85. currentNode: 'writing_chapter',
  86. currentChapter: nextChapterNum,
  87. });
  88. try {
  89. const chapter = await book_generator_service_1.bookGeneratorService.generateChapter(bookId, nextChapterNum);
  90. // 更新工作流状态
  91. const newPending = state.pendingChapters.filter(n => n !== nextChapterNum);
  92. this.updateState(bookId, {
  93. currentNode: 'idle',
  94. completedChapters: state.completedChapters + 1,
  95. pendingChapters: newPending,
  96. });
  97. if (newPending.length === 0) {
  98. // 全部章节完成
  99. this.updateState(bookId, { phase: 'supplement' });
  100. return { done: true, chapter };
  101. }
  102. return { done: false, chapter, nextChapter: newPending[0] };
  103. }
  104. catch (error) {
  105. const errorMessage = error instanceof Error ? error.message : '生成失败';
  106. // 标记本章失败,继续下一章
  107. const newPending = state.pendingChapters.filter(n => n !== nextChapterNum);
  108. const newFailed = [...state.failedChapters, nextChapterNum];
  109. this.updateState(bookId, {
  110. currentNode: 'idle',
  111. pendingChapters: newPending,
  112. failedChapters: newFailed,
  113. });
  114. if (newPending.length === 0) {
  115. return { done: true, error: `第${nextChapterNum}章失败` };
  116. }
  117. return { done: false, error: `第${nextChapterNum}章失败: ${errorMessage}` };
  118. }
  119. }
  120. /**
  121. * 执行全部章节生成(自动循环)
  122. */
  123. async executeAllChapters(bookId, onProgress) {
  124. const state = this.workflows.get(bookId);
  125. if (!state)
  126. return { success: false, completedCount: 0, failedCount: 0, errors: ['工作流不存在'] };
  127. const errors = [];
  128. while (true) {
  129. const currentState = this.workflows.get(bookId);
  130. if (!currentState || currentState.pendingChapters.length === 0) {
  131. break;
  132. }
  133. const nextChapter = currentState.pendingChapters[0];
  134. if (onProgress) {
  135. const progress = Math.round((currentState.completedChapters / currentState.totalChapters) * 100);
  136. onProgress(progress, nextChapter);
  137. }
  138. try {
  139. await book_generator_service_1.bookGeneratorService.generateChapter(bookId, nextChapter);
  140. const updated = this.workflows.get(bookId);
  141. if (updated) {
  142. this.updateState(bookId, {
  143. completedChapters: updated.completedChapters + 1,
  144. pendingChapters: updated.pendingChapters.filter(n => n !== nextChapter),
  145. });
  146. }
  147. }
  148. catch (error) {
  149. const errorMessage = error instanceof Error ? error.message : '生成失败';
  150. errors.push(`第${nextChapter}章: ${errorMessage}`);
  151. const updated = this.workflows.get(bookId);
  152. if (updated) {
  153. this.updateState(bookId, {
  154. pendingChapters: updated.pendingChapters.filter(n => n !== nextChapter),
  155. failedChapters: [...updated.failedChapters, nextChapter],
  156. });
  157. }
  158. }
  159. }
  160. this.updateState(bookId, { phase: 'supplement' });
  161. const finalState = this.workflows.get(bookId);
  162. return {
  163. success: errors.length === 0,
  164. completedCount: finalState?.completedChapters || 0,
  165. failedCount: finalState?.failedChapters?.length || 0,
  166. errors,
  167. };
  168. }
  169. /**
  170. * 生成前言
  171. */
  172. async executeForeword(bookId) {
  173. this.updateState(bookId, { currentNode: 'writing_foreword' });
  174. try {
  175. const foreword = await book_generator_service_1.bookGeneratorService.generateForeword(bookId);
  176. this.updateState(bookId, { currentNode: 'idle' });
  177. return { success: true, foreword };
  178. }
  179. catch (error) {
  180. const errorMessage = error instanceof Error ? error.message : '生成前言失败';
  181. return { success: false, error: errorMessage };
  182. }
  183. }
  184. /**
  185. * 生成后记
  186. */
  187. async executeAfterword(bookId) {
  188. this.updateState(bookId, { currentNode: 'writing_afterword' });
  189. try {
  190. const afterword = await book_generator_service_1.bookGeneratorService.generateAfterword(bookId);
  191. this.updateState(bookId, { currentNode: 'idle' });
  192. return { success: true, afterword };
  193. }
  194. catch (error) {
  195. const errorMessage = error instanceof Error ? error.message : '生成后记失败';
  196. return { success: false, error: errorMessage };
  197. }
  198. }
  199. /**
  200. * 完成工作流
  201. */
  202. finishWorkflow(bookId) {
  203. const state = this.workflows.get(bookId);
  204. if (!state)
  205. return undefined;
  206. this.updateState(bookId, { currentNode: 'finished', phase: 'done' });
  207. return this.workflows.get(bookId);
  208. }
  209. /**
  210. * 获取工作流进度
  211. */
  212. getProgress(bookId) {
  213. const state = this.workflows.get(bookId);
  214. if (!state)
  215. return null;
  216. return {
  217. phase: state.phase,
  218. currentNode: state.currentNode,
  219. currentChapter: state.currentChapter,
  220. completedChapters: state.completedChapters,
  221. totalChapters: state.totalChapters,
  222. pendingChapters: state.pendingChapters,
  223. failedChapters: state.failedChapters,
  224. progress: Math.round((state.completedChapters / state.totalChapters) * 100),
  225. };
  226. }
  227. /**
  228. * 取消工作流
  229. */
  230. cancelWorkflow(bookId) {
  231. return this.workflows.delete(bookId);
  232. }
  233. }
  234. // 导出单例
  235. exports.workflowEngine = new BookWorkflowEngine();