"use strict";
/**
 * 书籍生成服务 - 核心业务逻辑
 * 使用 Prisma 数据库存储
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.bookGeneratorService = exports.BookGeneratorService = void 0;
const axios_1 = __importDefault(require("axios"));
const config_1 = require("../../config");
const models_1 = require("../../models");
const TtsService = __importStar(require("../tts/tts.service"));
const VideoService = __importStar(require("../video-generator/video-generator.service"));
const book_generator_store_1 = require("./book-generator.store");
// ============ 默认配置 ============
const DEFAULT_CONFIG = {
    model: 'qwen3.6-plus',
    temperature: 0.7,
    maxTokens: 4000,
    chapterWordRange: {
        min: 800,
        max: 2000,
    },
    retryPolicy: {
        maxRetries: 3,
        retryDelay: 2000,
    },
};
// ============ 提示词模板 ============
const PROMPT_TEMPLATES = {
    systemPrompt: `你是专业的书籍作者，擅长撰写结构严谨、内容丰富、通俗易懂的作品。`,
    outlinePrompt: `
请为以下书籍生成详细的章节大纲。

## 书籍信息
- 书名：{title}
- 副标题：{subtitle}
- 主题：{description}
- 目标受众：{targetAudience}
- 风格：{style}
- 章节数：{totalChapters}章

## 输出要求
请生成JSON格式的大纲，包含：
1. mainTheme: 本书的核心主题
2. structureLogic: 整体结构逻辑
3. chapters: 章节大纲数组，每个章节包含：
   - number: 章节序号
   - title: 章节标题
   - summary: 章节概述（1-2句话）
   - keyPoints: 核心知识点（3-5个）
   - estimatedWords: 预估字数

请直接输出JSON，不要其他内容：
`,
    chapterPrompt: (chapter, context) => `
请撰写书籍《{bookTitle}》第${chapter.number}章的完整内容。

## 章节信息
- 章节标题：${chapter.title}
- 章节概述：${chapter.summary}
- 核心知识点：
${chapter.keyPoints.map((p, i) => `  ${i + 1}. ${p}`).join('\n')}
- 预估字数：${chapter.estimatedWords}字

## 全书上下文
- 主题主线：${context.mainTheme}
- 结构逻辑：${context.structureLogic}

## 写作要求
1. 语言通俗易懂，适合目标受众
2. 包含引入、正文、总结三个部分
3. 适当使用小标题划分内容
4. 长度控制在${chapter.estimatedWords}字左右
5. 使用markdown格式输出

请直接输出正文内容：
`,
    forewordPrompt: (book) => `
请为书籍《${book.title}》撰写前言。
主题：${book.description}
目标受众：${book.targetAudience}
写作风格：${book.style}
长度：300-500字
请直接输出前言内容：
`,
    afterwordPrompt: (book) => `
请为书籍《${book.title}》撰写后记。
主题：${book.description}
写作风格：${book.style}
长度：300-500字
请直接输出后记内容：
`,
};
// ============ 核心服务类 ============
class BookGeneratorService {
    apiKey = '';
    config;
    constructor(config) {
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    setApiKey(apiKey) {
        this.apiKey = apiKey;
    }
    // ============ 书籍 CRUD ============
    async createBook(request) {
        return book_generator_store_1.bookStore.create({
            title: request.title,
            subtitle: request.subtitle,
            description: request.description,
            targetAudience: request.targetAudience,
            style: request.style,
            totalChapters: request.totalChapters,
        });
    }
    async getBook(id) {
        return book_generator_store_1.bookStore.getById(id);
    }
    async getAllBooks(userId) {
        return book_generator_store_1.bookStore.getAllByUser(userId);
    }
    async deleteBook(id) {
        return book_generator_store_1.bookStore.delete(id);
    }
    // ============ 生成大纲 ============
    async generateOutline(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        await book_generator_store_1.bookStore.update(bookId, { status: 'planning' });
        try {
            const outlinePrompt = this.buildOutlinePrompt(book);
            const outlineJson = await this.callLLM(outlinePrompt);
            const outline = this.parseOutline(outlineJson);
            await book_generator_store_1.bookStore.update(bookId, {
                outlineJson: JSON.stringify(outline),
                estimatedWords: outline.chapters.reduce((sum, c) => sum + c.estimatedWords, 0),
            });
            // 创建章节记录
            await book_generator_store_1.bookStore.createChapters(bookId, outline.chapters.map(c => ({
                number: c.number,
                title: c.title,
                summary: c.summary,
                keyPoints: c.keyPoints,
                estimatedWords: c.estimatedWords,
            })));
            return outline;
        }
        catch (error) {
            await book_generator_store_1.bookStore.update(bookId, { status: 'failed', errorMsg: error instanceof Error ? error.message : '生成失败' });
            throw error;
        }
    }
    // ============ 生成章节 ============
    async generateChapter(bookId, chapterNumber) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        if (!book.outline)
            throw new Error('请先生成大纲');
        const outlineChapter = book.outline.chapters.find((c) => c.number === chapterNumber);
        if (!outlineChapter)
            throw new Error(`第${chapterNumber}章不存在`);
        await book_generator_store_1.bookStore.update(bookId, { status: 'generating' });
        try {
            const chapterPrompt = this.buildChapterPrompt(book, outlineChapter);
            const content = await this.callLLM(chapterPrompt);
            const wordCount = this.countWords(content);
            const chapter = await book_generator_store_1.bookStore.updateChapter(bookId, chapterNumber, {
                content,
                wordCount,
                status: 'completed',
            });
            // 更新进度
            const completedCount = await book_generator_store_1.bookStore.countCompletedChapters(bookId);
            const progress = Math.round((completedCount / book.totalChapters) * 100);
            await book_generator_store_1.bookStore.update(bookId, {
                progress,
                status: progress >= 100 ? 'completed' : 'generating',
            });
            return chapter;
        }
        catch (error) {
            await book_generator_store_1.bookStore.updateChapter(bookId, chapterNumber, {
                status: 'failed',
                errorMsg: error instanceof Error ? error.message : '生成失败',
            });
            throw error;
        }
    }
    async generateAllChapters(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        if (!book.outline)
            throw new Error('请先生成大纲');
        const results = [];
        for (const outlineChapter of book.outline.chapters) {
            const existingChapter = book.chapters.find((c) => c.number === outlineChapter.number);
            if (existingChapter?.status === 'completed') {
                results.push(existingChapter);
                continue;
            }
            try {
                const chapter = await this.generateChapter(bookId, outlineChapter.number);
                results.push(chapter);
            }
            catch (error) {
                console.error(`生成第${outlineChapter.number}章失败:`, error);
            }
        }
        return results;
    }
    // ============ 前言/后记 ============
    async generateForeword(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        try {
            const prompt = PROMPT_TEMPLATES.forewordPrompt(book);
            const foreword = await this.callLLM(prompt);
            await book_generator_store_1.bookStore.update(bookId, { foreword });
            return foreword;
        }
        catch (error) {
            throw new Error(`生成前言失败: ${error instanceof Error ? error.message : error}`);
        }
    }
    async generateAfterword(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        try {
            const prompt = PROMPT_TEMPLATES.afterwordPrompt(book);
            const afterword = await this.callLLM(prompt);
            await book_generator_store_1.bookStore.update(bookId, { afterword });
            return afterword;
        }
        catch (error) {
            throw new Error(`生成后记失败: ${error instanceof Error ? error.message : error}`);
        }
    }
    // ============ 内容获取 ============
    async getFullContent(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        const parts = [];
        parts.push(`# ${book.title}`);
        if (book.subtitle)
            parts.push(`## ${book.subtitle}`);
        if (book.metadata?.foreword) {
            parts.push('\n## 前言\n');
            parts.push(book.metadata.foreword);
        }
        if (book.outline) {
            parts.push('\n## 目录\n');
            book.outline.chapters.forEach((ch) => {
                parts.push(`${ch.number}. ${ch.title}`);
            });
        }
        book.chapters.forEach((ch) => {
            parts.push(`\n## 第${ch.number}章 ${ch.title}\n`);
            parts.push(ch.content);
        });
        if (book.metadata?.afterword) {
            parts.push('\n## 后记\n');
            parts.push(book.metadata.afterword);
        }
        return parts.join('\n');
    }
    async getProgress(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            return null;
        const completedChapters = book.chapters.filter((c) => c.status === 'completed').length;
        return {
            bookId,
            status: book.status,
            progress: book.progress,
            completedChapters,
            totalChapters: book.totalChapters,
        };
    }
    // ============ 一键生成（同步阻塞） ============
    async generateBook(bookId, options) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            return { success: false, completedChapters: 0, failedChapters: 0, errors: ['书籍不存在'] };
        const errors = [];
        try {
            if (!book.outline) {
                await this.generateOutline(bookId);
            }
        }
        catch (error) {
            return { success: false, completedChapters: 0, failedChapters: 0, errors: [`大纲: ${error instanceof Error ? error.message : error}`] };
        }
        const results = [];
        let failedCount = 0;
        for (const outlineChapter of book.outline?.chapters || []) {
            try {
                const chapter = await this.generateChapter(bookId, outlineChapter.number);
                results.push(chapter);
                options?.onProgress?.(Math.round((results.length / book.totalChapters) * 100), outlineChapter.number);
            }
            catch (error) {
                failedCount++;
                errors.push(`第${outlineChapter.number}章: ${error instanceof Error ? error.message : error}`);
            }
        }
        if (options?.generateForeword) {
            try {
                await this.generateForeword(bookId);
            }
            catch (error) {
                errors.push(`前言: ${error instanceof Error ? error.message : error}`);
            }
        }
        if (options?.generateAfterword) {
            try {
                await this.generateAfterword(bookId);
            }
            catch (error) {
                errors.push(`后记: ${error instanceof Error ? error.message : error}`);
            }
        }
        const updatedBook = await book_generator_store_1.bookStore.getById(bookId);
        return {
            success: failedCount === 0 && errors.length === 0,
            book: updatedBook || undefined,
            completedChapters: results.length,
            failedChapters: failedCount,
            errors,
        };
    }
    // ============ 一键生成（异步不阻塞） ============
    async generateBookAsync(bookId, options) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            return;
        try {
            await book_generator_store_1.bookStore.update(bookId, { status: 'generating', progress: 0 });
            if (!book.outline) {
                await this.generateOutline(bookId);
            }
            // 生成章节
            for (const outlineChapter of book.outline?.chapters || []) {
                try {
                    await this.generateChapter(bookId, outlineChapter.number);
                    const updatedBook = await book_generator_store_1.bookStore.getById(bookId);
                    await book_generator_store_1.bookStore.update(bookId, { progress: updatedBook.progress });
                }
                catch (error) {
                    console.error(`生成第${outlineChapter.number}章失败:`, error);
                }
            }
            if (options?.generateForeword) {
                await this.generateForeword(bookId);
            }
            if (options?.generateAfterword) {
                await this.generateAfterword(bookId);
            }
            await book_generator_store_1.bookStore.update(bookId, { status: 'completed', progress: 100 });
        }
        catch (error) {
            await book_generator_store_1.bookStore.update(bookId, { status: 'failed', errorMsg: error instanceof Error ? error.message : '生成失败' });
        }
    }
    // ============ 私有方法 ============
    buildOutlinePrompt(book) {
        return PROMPT_TEMPLATES.outlinePrompt
            .replace('{title}', book.title)
            .replace('{subtitle}', book.subtitle || '无')
            .replace('{description}', book.description)
            .replace('{targetAudience}', book.targetAudience)
            .replace('{style}', book.style)
            .replace('{totalChapters}', String(book.totalChapters));
    }
    buildChapterPrompt(book, chapter) {
        if (!book.outline)
            throw new Error('书籍大纲不存在');
        return PROMPT_TEMPLATES.chapterPrompt(chapter, book.outline).replace('{bookTitle}', book.title);
    }
    parseOutline(jsonStr) {
        try {
            const jsonMatch = jsonStr.match(/\{[\s\S]*\}/);
            if (jsonMatch) {
                return this.validateOutline(JSON.parse(jsonMatch[0]));
            }
        }
        catch {
            console.error('解析大纲 JSON 失败');
        }
        return this.createDefaultOutline();
    }
    validateOutline(data) {
        if (!data.chapters || !Array.isArray(data.chapters)) {
            throw new Error('大纲格式不正确');
        }
        return {
            mainTheme: data.mainTheme || '主题待定',
            structureLogic: data.structureLogic || '由浅入深',
            chapters: data.chapters.map((c, i) => ({
                number: c.number || i + 1,
                title: c.title || `第${i + 1}章`,
                summary: c.summary || '',
                keyPoints: c.keyPoints || [],
                estimatedWords: c.estimatedWords || 1000,
                stories: c.stories || [],
            })),
        };
    }
    createDefaultOutline() {
        return {
            mainTheme: '核心主题',
            structureLogic: '由浅入深',
            chapters: [{ number: 1, title: '概述', summary: '介绍', keyPoints: ['基础概念'], estimatedWords: 1000 }],
        };
    }
    countWords(text) {
        return (text.match(/[\u4e00-\u9fa5]/g) || []).length;
    }
    async callLLM(prompt, retryCount = 0, currentModel) {
        const modelId = currentModel || this.config.model;
        // 从模型配置获取 API Key 和 URL
        const modelConfig = config_1.config.models.getModel(modelId);
        if (!modelConfig?.apiKey || !modelConfig?.baseUrl) {
            throw new Error(`模型 ${modelId} 缺少 API 配置`);
        }
        const { apiKey, baseUrl } = modelConfig;
        try {
            const response = await axios_1.default.post(`${baseUrl}/chat/completions`, {
                model: modelId,
                messages: [{ role: 'user', content: prompt }],
            }, {
                headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
                timeout: 120000,
            });
            const result = response.data?.choices?.[0]?.message?.content || '';
            if (!result)
                throw new Error('API 返回内容为空');
            return result;
        }
        catch (error) {
            const errorMessage = error.response?.data?.message || error.message || 'API 调用失败';
            console.log(`[LLM] 模型 ${modelId} 调用失败: ${errorMessage}`);
            // 检查是否需要切换模型
            if (config_1.config.models.shouldSwitchModel(errorMessage)) {
                const nextModel = config_1.config.models.getNextModel(modelId, 'text');
                if (nextModel) {
                    console.log(`[LLM] 自动切换到模型: ${nextModel}`);
                    return this.callLLM(prompt, 0, nextModel); // 重置 retryCount
                }
            }
            // 重试当前模型
            if (retryCount < this.config.retryPolicy.maxRetries) {
                await this.delay(this.config.retryPolicy.retryDelay);
                return this.callLLM(prompt, retryCount + 1, currentModel);
            }
            throw new Error(errorMessage);
        }
    }
    delay(ms) {
        return new Promise((resolve) => setTimeout(resolve, ms));
    }
    // ============ 音频生成 ============
    /**
     * 生成单个章节音频
     */
    async generateChapterAudio(bookId, chapterNumber, voiceId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        const chapter = book.chapters.find((c) => c.number === chapterNumber);
        if (!chapter)
            throw new Error(`第${chapterNumber}章不存在`);
        if (!chapter.content || chapter.content.trim().length === 0) {
            throw new Error('章节内容为空，请先生成章节内容');
        }
        // 从数据库获取章节记录
        const dbChapter = await models_1.prisma.bookChapter.findFirst({
            where: {
                bookId: parseInt(bookId),
                number: chapterNumber,
            },
        });
        if (!dbChapter)
            throw new Error('章节数据库记录不存在');
        const taskId = `audio_${bookId}_${chapterNumber}_${Date.now()}`;
        // 异步生成音频
        this.processChapterAudio(dbChapter.id, chapter.content, voiceId).catch((err) => {
            console.error(`章节 ${chapterNumber} 音频生成失败:`, err);
        });
        return { taskId, chapterId: String(dbChapter.id) };
    }
    /**
     * 批量生成书籍所有章节音频
     */
    async generateAllChaptersAudio(bookId, voiceId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        const completedChapters = book.chapters.filter((c) => c.status === 'completed' && c.content && c.content.trim().length > 0);
        if (completedChapters.length === 0) {
            throw new Error('没有可生成音频的章节，请先生成章节内容');
        }
        const taskId = `audio_book_${bookId}_${Date.now()}`;
        // 异步批量生成音频
        this.processAllChaptersAudio(bookId, completedChapters, voiceId).catch((err) => {
            console.error(`书籍 ${bookId} 批量音频生成失败:`, err);
        });
        return { taskId, totalChapters: completedChapters.length };
    }
    /**
     * 处理单个章节音频生成
     */
    async processChapterAudio(chapterId, content, voiceId) {
        try {
            console.log(`🎵 开始生成章节 ${chapterId} 音频...`);
            // 清理内容（移除 markdown 格式）
            const cleanContent = content
                .replace(/^#{1,6}\s+/gm, '') // 移除标题标记
                .replace(/\*\*(.*?)\*\*/g, '$1') // 移除粗体
                .replace(/\*(.*?)\*/g, '$1') // 移除斜体
                .replace(/`(.*?)`/g, '$1') // 移除行内代码
                .replace(/^\s*[-*+]\s+/gm, '') // 移除列表标记
                .replace(/^\s*\d+\.\s+/gm, '') // 移除数字列表标记
                .trim();
            // 调用 TTS 服务生成音频
            const result = await TtsService.generateAudio('system', cleanContent, voiceId, { speed: 1.0, pitch: 0, volume: 50 }, async (audioUrl, duration) => {
                // 音频生成完成后更新数据库
                await models_1.prisma.bookChapter.update({
                    where: { id: chapterId },
                    data: {
                        audioUrl,
                        audioDuration: duration,
                    },
                });
                console.log(`✅ 章节 ${chapterId} 音频生成完成: ${audioUrl}`);
            });
            console.log(`🎵 章节 ${chapterId} 音频任务已启动: ${result.audioId}`);
        }
        catch (error) {
            console.error(`❌ 章节 ${chapterId} 音频生成失败:`, error);
            throw error;
        }
    }
    /**
     * 处理批量章节音频生成
     */
    async processAllChaptersAudio(bookId, chapters, voiceId) {
        console.log(`🎵 开始批量生成书籍 ${bookId} 的 ${chapters.length} 个章节音频...`);
        // 从数据库获取所有章节记录
        const dbChapters = await models_1.prisma.bookChapter.findMany({
            where: { bookId: parseInt(bookId) },
        });
        for (const chapter of chapters) {
            const dbChapter = dbChapters.find((c) => c.number === chapter.number);
            if (dbChapter && chapter.content) {
                try {
                    await this.processChapterAudio(dbChapter.id, chapter.content, voiceId);
                    // 每个章节之间稍作延迟，避免请求过于密集
                    await this.delay(1000);
                }
                catch (error) {
                    console.error(`第${chapter.number}章音频生成失败，继续下一个:`, error);
                }
            }
        }
        console.log(`✅ 书籍 ${bookId} 批量音频生成任务完成`);
    }
    // ============ 视频生成 ============
    /**
     * 生成单个章节视频（从音频转视频）
     */
    async generateChapterVideo(bookId, chapterNumber) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        const chapter = book.chapters.find((c) => c.number === chapterNumber);
        if (!chapter)
            throw new Error(`第${chapterNumber}章不存在`);
        if (!chapter.audioUrl) {
            throw new Error('章节音频不存在，请先生成音频');
        }
        // 获取数据库中的章节记录
        const dbChapter = await models_1.prisma.bookChapter.findFirst({
            where: {
                bookId: parseInt(bookId),
                number: chapterNumber,
            },
        });
        if (!dbChapter)
            throw new Error('章节数据库记录不存在');
        // 创建视频项目并生成
        const videoProject = await VideoService.createVideoProjectFromBook(parseInt(bookId), dbChapter.id);
        if (!videoProject) {
            throw new Error('创建视频项目失败');
        }
        // 异步生成视频
        this.processChapterVideo(videoProject.id).catch((err) => {
            console.error(`章节 ${chapterNumber} 视频生成失败:`, err);
        });
        return { projectId: videoProject.id, chapterId: String(dbChapter.id) };
    }
    /**
     * 批量生成书籍所有章节视频
     */
    async generateAllChaptersVideo(bookId) {
        const book = await book_generator_store_1.bookStore.getById(bookId);
        if (!book)
            throw new Error('书籍不存在');
        const chaptersWithAudio = book.chapters.filter((c) => c.status === 'completed' && c.audioUrl);
        if (chaptersWithAudio.length === 0) {
            throw new Error('没有可生成视频的章节（需要先有音频）');
        }
        const taskId = `video_book_${bookId}_${Date.now()}`;
        // 异步批量生成视频
        this.processAllChaptersVideo(bookId, chaptersWithAudio).catch((err) => {
            console.error(`书籍 ${bookId} 批量视频生成失败:`, err);
        });
        return { taskId, totalChapters: chaptersWithAudio.length };
    }
    /**
     * 处理单个章节视频生成
     */
    async processChapterVideo(projectId) {
        try {
            console.log(`🎬 开始生成视频项目 ${projectId}...`);
            const result = await VideoService.generateVideoForProject(projectId);
            if (result.success) {
                console.log(`✅ 视频项目 ${projectId} 生成完成: ${result.outputUrl}`);
            }
            else {
                console.error(`❌ 视频项目 ${projectId} 生成失败: ${result.error}`);
            }
        }
        catch (error) {
            console.error(`❌ 视频项目 ${projectId} 生成失败:`, error);
            throw error;
        }
    }
    /**
     * 处理批量章节视频生成
     */
    async processAllChaptersVideo(bookId, chapters) {
        console.log(`🎬 开始批量生成书籍 ${bookId} 的 ${chapters.length} 个章节视频...`);
        for (const chapter of chapters) {
            try {
                const dbChapter = await models_1.prisma.bookChapter.findFirst({
                    where: {
                        bookId: parseInt(bookId),
                        number: chapter.number,
                    },
                });
                if (!dbChapter || !chapter.audioUrl) {
                    console.warn(`第${chapter.number}章跳过：缺少音频或数据库记录`);
                    continue;
                }
                // 创建视频项目
                const videoProject = await VideoService.createVideoProjectFromBook(parseInt(bookId), dbChapter.id);
                if (videoProject) {
                    // 生成视频
                    await this.processChapterVideo(videoProject.id);
                }
                // 每个视频之间稍作延迟
                await this.delay(2000);
            }
            catch (error) {
                console.error(`第${chapter.number}章视频生成失败，继续下一个:`, error);
            }
        }
        console.log(`✅ 书籍 ${bookId} 批量视频生成任务完成`);
    }
}
exports.BookGeneratorService = BookGeneratorService;
// 导出单例
exports.bookGeneratorService = new BookGeneratorService();
exports.bookGeneratorService.setApiKey(config_1.config.dashscope?.apiKey || '');
