| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- """Phase 1 HA: rich-outline 节点加降级路径"""
- PATH = "/data/ai/audio/server/src/modules/book-generator/nodes/rich-outline.node.ts"
- with open(PATH, 'r', encoding='utf-8') as f:
- src = f.read()
- # 加 import AllProvidersFailedError
- old_import = "import { callLLMWithMessages, ChatMessage } from '../../../services/llm';"
- new_import = "import { callLLMWithMessages, ChatMessage, AllProvidersFailedError } from '../../../services/llm';"
- assert old_import in src, "old import not found"
- src = src.replace(old_import, new_import, 1)
- # 改 catch 块:识别 AllProvidersFailedError 走降级路径
- old_catch = """ } catch (error) {
- console.error('[RichOutline] 生成失败:', error);
- await bookStore.update(state.bookId, {
- genStage: 'failed', failedStage: 'outlining',
- errorMsg: error instanceof Error ? error.message : '富信息大纲生成失败',
- });
- return { error: error instanceof Error ? error.message : '失败', finished: true };
- }
- }"""
- new_catch = """ } catch (error: any) {
- // ============ HA 降级:所有供应商都挂了 ============
- if (error?.name === 'AllProvidersFailedError' || error instanceof AllProvidersFailedError) {
- console.error('[RichOutline] ⚠️ 所有 LLM 供应商均不可用,触发降级:', error.message);
- // 降级策略 1: 尝试复用已有的简单大纲(如果有)
- try {
- const existingBook: any = await bookStore.getById(state.bookId);
- const existingOutline = existingBook?.outlineJson
- ? (typeof existingBook.outlineJson === 'string' ? JSON.parse(existingBook.outlineJson) : existingBook.outlineJson)
- : null;
- if (existingOutline?.chapters?.length) {
- console.log('[RichOutline] 降级路径 1: 复用已有大纲');
- await bookStore.update(state.bookId, {
- errorMsg: `[降级-复用] 所有 LLM 供应商失败 (${error.attempts?.length || 0}个), 已复用已有大纲`,
- progress: PROGRESS.OUTLINE_DONE,
- failedStage: null,
- });
- return { progress: PROGRESS.OUTLINE_DONE } as any;
- }
- } catch (e) {
- console.warn('[RichOutline] 降级路径 1 失败:', e);
- }
- // 降级策略 2: 标记为 partial_outline,让后续节点继续
- // 不写 failedStage,让 processMonitor 有机会后续恢复
- console.log('[RichOutline] 降级路径 2: 标记 partial_outline, 等待后续重试');
- await bookStore.update(state.bookId, {
- genStage: 'partial_outline',
- errorMsg: `[降级] 所有 LLM 供应商失败 (${error.attempts?.length || 0}个): ${error.message?.substring(0, 500)}`,
- failedStage: null, // 关键:不标记 failed,让 processMonitor 后续重试
- });
- return { progress: PROGRESS.OUTLINE_DONE } as any;
- }
- // 真正不可恢复的错误(业务错误、解析错误等)
- console.error('[RichOutline] 生成失败:', error);
- await bookStore.update(state.bookId, {
- genStage: 'failed', failedStage: 'outlining',
- errorMsg: error instanceof Error ? error.message : '富信息大纲生成失败',
- });
- return { error: error instanceof Error ? error.message : '失败', finished: true };
- }
- }"""
- assert old_catch in src, "old catch not found"
- src = src.replace(old_catch, new_catch)
- with open(PATH, 'w', encoding='utf-8') as f:
- f.write(src)
- print("OK: rich-outline.node.ts patched")
|