# All files / services/llm mock.provider.ts

0% Statements 0/127
100% Branches 1/1
100% Functions 1/1
0% Lines 0/127

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
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154

     /**
     * Mock LLM Provider（不调外部API，返回固定/随机内容）
     * 用于测试完整生成链路，不消耗任何 LLM 配额
     */
    import { ILlmProvider, LlmModelConfig } from './provider.interface';
    import { logAiCall } from '../ai-call-logger';

    export class MockLlmProvider implements ILlmProvider {
      readonly name = 'mock-llm';
      readonly vendor = 'mock';
      readonly displayName = 'Mock LLM';
      readonly baseUrl = 'mock://localhost';
      readonly textModels = ['mock-text'];
      readonly modelConfigs = new Map<string, LlmModelConfig>([
        ['mock-text', {
          id: 'mock-text',
          name: 'Mock Text',
          contextWindow: 128000,
          maxTokens: 4096,
          temperature: 0.7,
          supportsToolCall: true,
          enabled: true,
        }],
      ]);

      private _apiKey = 'mock-key';

      get apiKey(): string { return this._apiKey; }
      set apiKey(val: string) { this._apiKey = val; }

      createClient(_modelId: string, _options?: any): any {
        return { invoke: async () => ({ content: '' }) };
      }

      hasModel(modelId: string): boolean {
        return this.modelConfigs.has(modelId);
      }

      getModelConfig(modelId: string): LlmModelConfig | undefined {
        return this.modelConfigs.get(modelId);
      }

      /** 生成符合 deepPlan 节点要求的 JSON */
      static generateFakeDeepPlan(topic: string): string {
        return JSON.stringify({
          goldenThread: `以${topic}的核心机制为主线，构建从认知到实践的完整闭环`,
          narrativeArc: {
            "part1": { theme: `${topic}入门`, chapters: [1], goal: "建立基础认知" },
            "part2": { theme: `${topic}进阶`, chapters: [2], goal: "掌握核心技能" },
          },
          crossReferences: {
            "ch1": { dependsOn: [], usedBy: ["ch2"] },
            "ch2": { dependsOn: ["ch1"], usedBy: [] },
          },
          toneProfile: {
            base: "专业严谨、深入浅出",
            examples: "用实际案例辅助理解",
            codeSnippets: "提供代码示例帮助实践",
            avoidPatterns: ["避免过于学术化", "避免冗长罗列"],
          },
          audienceCalibration: {
            assumedKnowledge: ["基本概念认知"],
            learningStyle: "理论与实践结合",
            difficulty: "beginner",
          },
          writingStyle: "简洁、精准、结果导向",
          genLevel: 1,
          bookType: "短文",
        }, null, 2);
      }

      /** 生成大纲 JSON（匹配 richOutline 解析器期望的格式） */
      static generateFakeOutline(topic: string, genLevel: number): string {
        const node = (title: string, summary: string, words: number, children?: any[]) => ({
          title, summary,
          estimatedWords: words,
          keyPoints: ['核心概念', '关键逻辑', '实践要点'],
          writingInstructions: {
            opening: `从${title}的实际场景切入`,
            structure: '总分总结构',
            mustCover: [summary],
            avoidRepeat: ['避免重复前文已覆盖内容'],
            coreTakeaway: `理解${title}的核心价值`,
          },
          ...(children ? { children } : {}),
        });

        const chapters = [
          node(`${topic}入门基础`, '介绍核心概念与背景知识', genLevel > 1 ? 400 : 1000, genLevel > 1 ? [
            node('基本概念', '定义与分类', 200),
            node('发展历程', '历史演进与趋势', 200),
          ] : undefined),
        ];

        if (genLevel === 1) {
          // 短文模式：只有一章
          chapters[0].estimatedWords = 1000;
        }

        return JSON.stringify({
          title: topic,
          chapters,
          totalEstimatedWords: 1000,
          structureFormat: genLevel > 1 ? '多级结构' : '全文',
        });
      }

      /** 生成一篇看起来像真实文章的 Markdown */
      static generateFakeArticle(topic: string, wordCount: number = 1000): string {
        const paragraphs = [
          `# ${topic}`,
          '',
          `在当今快节奏的世界中，${topic}已经成为越来越多人关注的焦点。无论是初学者还是资深从业者，理解其核心原理都是至关重要的第一步。`,
          '',
          `## 为什么${topic}如此重要`,
          '',
          `首先，${topic}提供了一种系统化的思维方式，帮助我们更好地组织知识和解决问题。研究表明，掌握这一领域基础的人群，在工作效率和创新能力方面都有显著提升。`,
          '',
          `## 核心概念解析`,
          '',
          `深入理解${topic}，需要把握三个关键维度：理论基础、实践应用和持续迭代。理论基础为我们提供了扎实的知识框架；实践应用则将抽象概念转化为具体行动；持续迭代确保我们能够适应不断变化的需求。`,
          '',
          '具体来说，我们可以从以下几个方面入手：',
          '',
          '1. **建立清晰的学习路径**：根据自身基础制定合理的学习计划',
          '2. **注重实践与反馈**：通过项目实践检验所学知识',
          '3. **参与社区交流**：与同行交流经验，汲取他人智慧',
          '4. **保持持续学习**：跟踪最新发展动态，不断更新知识体系',
          '',
          `## 实际案例分析`,
          '',
          `以某知名企业为例，他们将${topic}的核心理念融入日常工作流程后，团队协作效率提升了40%，项目交付周期缩短了30%。这一成功案例充分证明了${topic}的实际价值。`,
          '',
          `## 总结`,
          '',
          `总而言之，${topic}是一项值得深入学习和实践的领域。通过系统化的学习、持续的实践和不断的反思，我们每个人都能从中受益，并在各自的领域取得更大的成就。`,
          '',
          `> 学习${topic}的关键不在于掌握了多少知识，而在于如何将这些知识转化为实际的行动和成果。`,
        ];

        // 调整字数
        const fullText = paragraphs.join('\n');
        if (fullText.length > wordCount) {
          return fullText.substring(0, wordCount);
        }
        return fullText + '\n\n' + '补充内容以填充字数要求。'.repeat(Math.ceil((wordCount - fullText.length) / 15));
      }

      // 健康检查
      async healthCheck(): Promise<boolean> {
        return true;
      }
    }