All files / modules/book-generator/strategies base.ts

0% Statements 0/54
0% Branches 0/1
0% Functions 0/1
0% Lines 0/54

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81                                                                                                                                                                 
/**
 * 基础策略 - 共享的 graph 执行、进度监控、错误处理逻辑
 */
 
import { StateGraph, END } from '@langchain/langgraph';
import { GraphState } from '../graph';
import { bookStore } from '../book-generator.store';
import { startProgressMonitor } from '../fault-tolerance';
 
/** 基础策略选项 */
export interface BaseStrategyOptions {
  name: string;
  description: string;
  buildGraph: () => ReturnType<typeof buildAndCompile>;
}
 
function buildAndCompile() {
  const workflow = new StateGraph(GraphState);
  return { workflow, addEdge: workflow.addEdge.bind(workflow) };
}
 
/**
 * 运行一个 LangGraph 工作流并处理结果
 * 所有策略的 graph 执行逻辑相同,只是 graph 结构不同
 */
export async function runGraphWorkflow(
  bookId: string,
  initialState: typeof GraphState.State,
  workflow: StateGraph<typeof GraphState.State, any, any, any, any>
): Promise<void> {
  await bookStore.update(bookId, { genStage: 'outlining', progress: 0 });
 
  const stopMonitor = startProgressMonitor(bookId);
 
  try {
    const graph = workflow.compile();
    const stream = await graph.stream(initialState);
    for await (const step of stream) {
      const stepName = Object.keys(step).join(',');
      if (stepName !== 'progress') {
        console.log(`[Graph] Step:`, stepName);
      }
    }
 
    // 检查最终状态
    const finalBook = await bookStore.getById(bookId);
    if (finalBook && finalBook.genStage !== 'failed') {
      const finalStage = finalBook.genStage || 'content_completed';
      const stageUpdate: any = { progress: 100 };
      if (['content_completed', 'audio_generating', 'audio_completed'].includes(finalStage)) {
        stageUpdate.genStage = finalStage;
      }
      await bookStore.update(bookId, stageUpdate);
      // 只有最终态 video_completed 才自动发布
      if (finalStage === 'video_completed') {
        await bookStore.publishAlbum(bookId);
      }
      console.log(`[Strategy] 生成完成,genStage: ${finalStage}`);
    } else {
      console.log('[Strategy] 生成失败,保持 failed 状态');
    }
  } catch (error) {
    console.error('[Strategy] 生成失败:', error);
    // 尝试从数据库获取当前真实阶段,作为 failedStage
    let failedStage = 'outlining';
    try {
      const currentBook = await bookStore.getById(bookId);
      if (currentBook?.genStage) {
        failedStage = currentBook.genStage;
      }
    } catch { /* 取不到就用默认值 */ }
    await bookStore.update(bookId, {
      genStage: 'failed',
      failedStage,
      errorMsg: error instanceof Error ? error.message : '生成失败',
    });
  } finally {
    stopMonitor();
  }
}