sebit-mcp-public
Version: 
> 한국어 설명은 아래 링크에서 확인할 수 있습니다. > 👉 [README.ko.md](./README.ko.md)
719 lines (690 loc) • 34.5 kB
JavaScript
;
// =============================
// FILE: /src/pdf-generator.ts
// 한글 지원 PDF 생성기
// HTML to PDF 방식으로 한글 깨짐 문제 해결
// =============================
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiLanguagePDFGenerator = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const dayjs_1 = __importDefault(require("dayjs"));
const logger_1 = require("./logger");
// 다국어 텍스트 정의
const i18n = {
    ko: {
        reportTitle: 'SEBIT MCP 세션 분석 보고서',
        executiveSummary: '실행 요약',
        detailedAnalysis: '모델별 상세 분석',
        strategicInsights: '전략적 인사이트',
        recommendations: '권장 사항',
        risks: '리스크 요인',
        opportunities: '기회 요소',
        totalExecutions: '총 실행 횟수',
        successRate: '성공률',
        avgExecutionTime: '평균 실행 시간',
        mostUsedModels: '가장 많이 사용된 모델',
        reportGenerated: '보고서 생성일시',
        modelDescriptions: {
        // 기존 한국어 설명들...
        },
        standardRecommendations: [
            '정기적인 모델 성능 모니터링 및 최적화',
            '입력 데이터 품질 검증 프로세스 강화',
            '오류 발생 패턴 분석을 통한 예방적 조치 수립',
            '자주 사용되는 모델의 성능 튜닝 고려'
        ]
    },
    en: {
        reportTitle: 'SEBIT MCP Session Analysis Report',
        executiveSummary: 'Executive Summary',
        detailedAnalysis: 'Detailed Model Analysis',
        strategicInsights: 'Strategic Insights',
        recommendations: 'Recommendations',
        risks: 'Risk Factors',
        opportunities: 'Opportunities',
        totalExecutions: 'Total Executions',
        successRate: 'Success Rate',
        avgExecutionTime: 'Average Execution Time',
        mostUsedModels: 'Most Used Models',
        reportGenerated: 'Report Generated',
        modelDescriptions: {
        // 영어 설명들을 추가...
        },
        standardRecommendations: [
            'Regular monitoring and optimization of model performance',
            'Strengthen input data quality validation processes',
            'Establish preventive measures through error pattern analysis',
            'Consider performance tuning for frequently used models'
        ]
    }
};
// 다국어 모델 설명
const modelDescriptions = {
    ko: {
        dda: {
            description: "Dynamic Depreciation Analysis - 동적 감가상각 분석",
            purpose: "자산의 시간에 따른 가치 감소를 동적으로 계산하여 정확한 감가상각 비용 산출",
            insights: "감가상각 방식의 최적화를 통해 세무 효율성을 높이고, 정확한 자산 가치 평가가 가능합니다."
        },
        lam: {
            description: "Lease Asset Model - 리스 자산 모델",
            purpose: "리스 계약에 따른 자산과 부채의 초기 인식 및 후속 측정을 위한 회계 처리",
            insights: "IFRS 16 기준에 따른 리스 회계 처리로 재무상태표의 투명성을 제고할 수 있습니다."
        },
        rvm: {
            description: "Resource Valuation Model - 자원 가치 평가 모델",
            purpose: "기업이 보유한 다양한 자원의 공정가치 평가 및 가치 변동 분석",
            insights: "자원의 정확한 가치 평가를 통해 투자 의사결정과 자원 배분 최적화가 가능합니다."
        },
        ceem: {
            description: "Consumable Expense Model - 소모성 비용 모델",
            purpose: "소모성 자산의 사용 패턴 분석 및 비용 배분의 최적화",
            insights: "소모성 자산의 효율적 관리로 운영 비용을 절감하고 예산 계획의 정확성을 높일 수 있습니다."
        },
        bdm: {
            description: "Bond Effective Interest Model - 채권 유효이자율 모델",
            purpose: "채권의 유효이자율법에 따른 이자비용 계산 및 장부가액 조정",
            insights: "정확한 이자비용 인식으로 재무성과의 신뢰성을 높이고, 채권 관리 전략 수립이 가능합니다."
        },
        belm: {
            description: "Bank Expected Loss Model - 은행 기대손실 모델",
            purpose: "IFRS 9에 따른 금융자산의 기대신용손실 측정 및 충당금 설정",
            insights: "선제적 손실 인식을 통해 리스크 관리를 강화하고, 건전성 지표를 개선할 수 있습니다."
        },
        cprm: {
            description: "Convertible Bond Risk Model - 전환사채 위험 모델",
            purpose: "전환사채의 전환 옵션 가치 평가 및 리스크 헤지 전략 수립",
            insights: "전환사채의 복합금융상품 특성을 반영한 정확한 가치평가로 투자 리스크를 최소화할 수 있습니다."
        },
        ocim: {
            description: "OCI Compounded Increase Model - 기타포괄손익 복리증가 모델",
            purpose: "기타포괄손익 항목의 복리 효과를 고려한 누적 변동액 계산",
            insights: "기타포괄손익의 장기적 영향을 정확히 파악하여 자본 관리 전략을 수립할 수 있습니다."
        },
        farex: {
            description: "Foreign Exchange Adjustment Model - 외환 조정 모델",
            purpose: "외화표시 자산·부채의 환율 변동에 따른 환산차이 계산 및 헤지 효과 분석",
            insights: "환율 리스크 관리를 통해 외환 변동성으로 인한 손실을 최소화하고 안정적인 수익성을 확보할 수 있습니다."
        },
        tctbeam: {
            description: "Trigonometric Breakeven Analysis Model - 삼각함수 손익분기점 모델",
            purpose: "주기적 변동을 고려한 손익분기점 분석 및 최적 운영점 도출",
            insights: "계절성이나 주기적 변동이 있는 사업의 경우, 보다 정확한 손익분기점 분석으로 운영 효율성을 극대화할 수 있습니다."
        },
        cpmrv: {
            description: "Crypto Real Value Model - 암호화폐 실질가치 모델",
            purpose: "암호화폐 자산의 실질 가치 평가 및 변동성 리스크 분석",
            insights: "암호화폐의 높은 변동성을 고려한 실질 가치 평가로 디지털 자산 투자 전략을 수립할 수 있습니다."
        },
        dcbpra: {
            description: "Beta-Adjusted Return Analysis Model - 베타 조정 수익률 분석 모델",
            purpose: "시장 베타를 조정한 위험조정수익률 계산 및 투자성과 평가",
            insights: "시장 리스크를 고려한 정확한 성과 평가로 포트폴리오 최적화 및 투자 전략 개선이 가능합니다."
        },
        journal: {
            description: "Journalizing Model - 분개 및 분개장 생성",
            purpose: "회계 거래의 분개 처리 및 분개장 자동 생성",
            insights: "회계 실무를 위한 도구로서 분석 보고서 대상에서 제외됩니다."
        }
    },
    en: {
        dda: {
            description: "Dynamic Depreciation Analysis",
            purpose: "Dynamic calculation of asset value decline over time for accurate depreciation expense calculation",
            insights: "Optimize depreciation methods to enhance tax efficiency and enable accurate asset valuation."
        },
        lam: {
            description: "Lease Asset Model",
            purpose: "Initial recognition and subsequent measurement of lease assets and liabilities under accounting standards",
            insights: "Enhance financial statement transparency through IFRS 16 compliant lease accounting treatment."
        },
        rvm: {
            description: "Resource Valuation Model",
            purpose: "Fair value assessment and valuation change analysis of various enterprise resources",
            insights: "Enable investment decision-making and resource allocation optimization through accurate resource valuation."
        },
        ceem: {
            description: "Consumable Expense Model",
            purpose: "Usage pattern analysis and cost allocation optimization for consumable assets",
            insights: "Reduce operational costs and improve budget planning accuracy through efficient consumable asset management."
        },
        bdm: {
            description: "Bond Effective Interest Model",
            purpose: "Interest expense calculation and book value adjustment using effective interest method for bonds",
            insights: "Enhance financial performance reliability through accurate interest expense recognition and enable bond management strategy development."
        },
        belm: {
            description: "Bank Expected Loss Model",
            purpose: "Expected credit loss measurement and provision setting for financial assets under IFRS 9",
            insights: "Strengthen risk management and improve soundness indicators through proactive loss recognition."
        },
        cprm: {
            description: "Convertible Bond Risk Model",
            purpose: "Conversion option valuation and risk hedging strategy development for convertible bonds",
            insights: "Minimize investment risk through accurate valuation reflecting the hybrid financial instrument characteristics of convertible bonds."
        },
        ocim: {
            description: "Operational Cost Impact Model",
            purpose: "Analysis of cost impact on operational efficiency and optimization strategy development",
            insights: "Improve operational efficiency and cost structure optimization through systematic cost impact analysis."
        },
        farex: {
            description: "Foreign Exchange Adjustment Model",
            purpose: "Calculation of translation differences from exchange rate fluctuations and hedge effect analysis for foreign currency assets/liabilities",
            insights: "Minimize losses from exchange rate volatility and secure stable profitability through exchange rate risk management."
        },
        tctbeam: {
            description: "Trigonometric Breakeven Analysis Model",
            purpose: "Breakeven analysis considering periodic fluctuations and optimal operating point derivation",
            insights: "Maximize operational efficiency through more accurate breakeven analysis for businesses with seasonality or periodic variations."
        },
        cpmrv: {
            description: "Crypto Real Value Model",
            purpose: "Real value assessment and volatility risk analysis for cryptocurrency assets",
            insights: "Develop digital asset investment strategies through real value evaluation considering high volatility of cryptocurrencies."
        },
        dcbpra: {
            description: "Beta-Adjusted Return Analysis Model",
            purpose: "Risk-adjusted return calculation and investment performance evaluation with market beta adjustment",
            insights: "Enable portfolio optimization and investment strategy improvement through accurate performance evaluation considering market risk."
        },
        journal: {
            description: "Journalizing Model",
            purpose: "Journal entry processing and automatic journal generation for accounting transactions",
            insights: "Excluded from analysis reports as a practical accounting tool."
        }
    }
};
class MultiLanguagePDFGenerator {
    // 기본 경로를 강제로 고정 (환경변수에 의존하지 않음)
    static DEFAULT_SAVE_PATH = 'C:\\Users\\user\\Documents\\SEBIT-MCP-Reports';
    constructor() {
        this.ensureDirectoryExists(MultiLanguagePDFGenerator.DEFAULT_SAVE_PATH);
    }
    async ensureDirectoryExists(dirPath) {
        try {
            await fs_extra_1.default.ensureDir(dirPath);
            logger_1.Logger.debug(`Directory ensured: ${dirPath}`);
        }
        catch (error) {
            logger_1.Logger.error(`Failed to create directory: ${dirPath}`, error);
        }
    }
    // 고급 분석 수행 (클로드 수준의 상세 분석)
    analyzeSession(sessionData) {
        // journal 모델을 제외한 실행 기록만 분석 대상으로 사용
        const analysisExecutions = sessionData.executions.filter(exec => exec.modelName !== 'journal');
        const allExecutions = sessionData.executions; // 전체 통계용
        const totalExecutions = allExecutions.length;
        const successfulExecutions = allExecutions.filter(e => e.success).length;
        const successRate = totalExecutions > 0 ? (successfulExecutions / totalExecutions) * 100 : 0;
        // 모델 사용 빈도 계산 (journal 제외)
        const modelCounts = new Map();
        analysisExecutions.forEach(exec => {
            const count = modelCounts.get(exec.modelName) || 0;
            modelCounts.set(exec.modelName, count + 1);
        });
        const mostUsedModels = Array.from(modelCounts.entries())
            .map(([model, count]) => ({ model, count }))
            .sort((a, b) => b.count - a.count)
            .slice(0, 5);
        // 평균 실행 시간 (전체 포함)
        const avgExecutionTime = totalExecutions > 0
            ? allExecutions.reduce((sum, exec) => sum + exec.executionTime, 0) / totalExecutions
            : 0;
        // 시간 범위 (전체 포함)
        const timestamps = allExecutions.map(e => e.timestamp).sort();
        const timeRange = {
            start: timestamps.length > 0 ? timestamps[0] : sessionData.startTime,
            end: timestamps.length > 0 ? timestamps[timestamps.length - 1] : sessionData.startTime
        };
        // 오류 요약 (전체 포함, journal은 제외하지 않음)
        const errorSummary = allExecutions
            .filter(e => !e.success && e.error)
            .map(e => `${e.modelName}: ${e.error}`)
            .slice(0, 5); // 최대 5개만
        return {
            totalExecutions,
            successRate,
            mostUsedModels,
            avgExecutionTime,
            timeRange,
            errorSummary
        };
    }
    // 전략적 인사이트 생성 (클로드 스타일)
    generateStrategicInsights(sessionData, analysis) {
        const { mostUsedModels, successRate, totalExecutions } = analysis;
        const insights = [];
        // 사용 패턴 분석
        if (mostUsedModels.length > 0) {
            const topModel = mostUsedModels[0];
            const modelCategory = this.categorizeModel(topModel.model);
            insights.push(`**주요 분석 영역**: ${modelCategory.category}에 집중하여 ${topModel.count}회 실행하셨습니다. ${modelCategory.strategicImplication}`);
        }
        // 다양성 분석
        const uniqueModels = new Set(sessionData.executions.map(e => e.modelName)).size;
        if (uniqueModels >= 5) {
            insights.push(`**분석 범위의 다양성**: ${uniqueModels}개의 서로 다른 모델을 활용하여 다각도 분석을 수행하셨습니다. 이는 종합적인 리스크 관리 접근법을 보여줍니다.`);
        }
        else if (uniqueModels <= 2) {
            insights.push(`**전문화된 분석**: ${uniqueModels}개의 특정 모델에 집중하여 심층 분석을 수행하셨습니다. 해당 영역의 전문성을 높이는 접근법입니다.`);
        }
        // 성과 분석
        if (successRate >= 95) {
            insights.push(`**실행 안정성**: ${successRate.toFixed(1)}%의 높은 성공률을 달성하여 데이터 품질과 모델 활용 숙련도가 우수합니다.`);
        }
        else if (successRate < 80) {
            insights.push(`**개선 기회**: ${successRate.toFixed(1)}%의 성공률로 입력 데이터 검증이나 모델 파라미터 조정이 필요해 보입니다.`);
        }
        // 시간대 분석
        const executions = sessionData.executions;
        if (executions.length > 0) {
            const timeSpan = new Date(analysis.timeRange.end).getTime() - new Date(analysis.timeRange.start).getTime();
            const minutes = timeSpan / (1000 * 60);
            if (minutes < 30) {
                insights.push(`**집중적 분석**: ${minutes.toFixed(0)}분 내에 ${totalExecutions}회 실행하여 신속한 의사결정을 위한 집중적 분석을 수행하셨습니다.`);
            }
            else if (minutes > 120) {
                insights.push(`**심층 연구**: ${(minutes / 60).toFixed(1)}시간에 걸친 체계적 분석으로 신중한 검토 과정을 거치셨습니다.`);
            }
        }
        return insights.join('\n\n');
    }
    // 모델 카테고리 분류
    categorizeModel(modelName) {
        const categories = {
            dda: {
                category: "자산 관리",
                strategicImplication: "자산의 생명주기 관리와 최적 감가상각 전략 수립에 중점을 두고 계시네요."
            },
            lam: {
                category: "리스 회계",
                strategicImplication: "IFRS 16 도입에 따른 리스 자산·부채 관리의 정확성을 높이고 계십니다."
            },
            rvm: {
                category: "가치 평가",
                strategicImplication: "자원의 공정가치 산정을 통한 투자 의사결정 지원에 활용하고 계시네요."
            },
            ceem: {
                category: "비용 관리",
                strategicImplication: "소모성 자산의 효율적 관리를 통한 운영 비용 최적화를 추구하고 계십니다."
            },
            bdm: {
                category: "채권 관리",
                strategicImplication: "채권 포트폴리오의 이자 리스크 관리와 수익성 분석에 집중하고 계시네요."
            },
            belm: {
                category: "신용 리스크",
                strategicImplication: "IFRS 9 기준의 선제적 손실 인식으로 건전성 관리를 강화하고 계십니다."
            },
            cprm: {
                category: "복합 상품",
                strategicImplication: "전환사채의 옵션 가치와 리스크를 정밀하게 분석하여 투자 전략을 수립하고 계시네요."
            },
            ocim: {
                category: "자본 관리",
                strategicImplication: "기타포괄손익의 장기적 영향을 고려한 자본 전략 수립에 활용하고 계십니다."
            },
            farex: {
                category: "환율 리스크",
                strategicImplication: "외환 노출 관리와 헤지 전략을 통한 안정적 수익성 확보에 중점을 두고 계시네요."
            },
            tctbeam: {
                category: "손익분기 분석",
                strategicImplication: "삼각함수를 활용한 고도화된 손익분기점 분석으로 운영 효율성을 극대화하고 계십니다."
            },
            cpmrv: {
                category: "디지털 자산",
                strategicImplication: "암호화폐의 변동성을 고려한 실질 가치 평가로 신흥 자산군 투자 전략을 구축하고 계시네요."
            },
            dcbpra: {
                category: "성과 평가",
                strategicImplication: "시장 베타 조정을 통한 정확한 위험조정수익률 산출로 포트폴리오 최적화를 추구하고 계십니다."
            },
            journal: {
                category: "회계 실무",
                strategicImplication: "정확한 분개 처리로 회계 시스템의 신뢰성을 확보하고 계십니다."
            }
        };
        return categories[modelName];
    }
    // 리스크 및 기회 분석
    analyzeRisksAndOpportunities(sessionData, analysis) {
        const risks = [];
        const opportunities = [];
        // 모델 조합 분석
        const modelTypes = analysis.mostUsedModels.map((m) => this.categorizeModel(m.model).category);
        const uniqueCategories = new Set(modelTypes);
        if (uniqueCategories.has("신용 리스크") && uniqueCategories.has("채권 관리")) {
            opportunities.push("신용리스크와 채권관리 모델의 조합으로 통합적 채권 포트폴리오 리스크 관리 체계 구축 가능");
        }
        if (uniqueCategories.has("환율 리스크") && uniqueCategories.has("디지털 자산")) {
            risks.push("외환과 암호화폐의 이중 변동성 노출로 인한 복합 리스크 발생 가능성");
            opportunities.push("다양한 자산군 간 상관관계 분석을 통한 리스크 분산 효과 극대화 가능");
        }
        // 성과 기반 분석
        if (analysis.successRate < 80) {
            risks.push("모델 실행 실패율이 높아 의사결정 신뢰성에 영향을 줄 수 있음");
        }
        if (analysis.totalExecutions >= 10) {
            opportunities.push("충분한 분석 데이터 축적으로 패턴 인식 및 예측 정확도 향상 가능");
        }
        return { risks, opportunities };
    }
    // HTML 생성 (한글 지원)
    generateHTML(sessionData, customAnalysis, claudeAnalysis, language = 'ko') {
        const analysis = this.analyzeSession(sessionData);
        const strategicInsights = this.generateStrategicInsights(sessionData, analysis);
        const risksAndOpportunities = this.analyzeRisksAndOpportunities(sessionData, analysis);
        const texts = i18n[language];
        const models = modelDescriptions[language];
        // 기본 분석 의견
        let opinion = '';
        if (analysis.successRate >= 90) {
            opinion = '우수한 성능: 모델 실행이 매우 안정적으로 수행되었습니다. 현재 설정을 유지하면서 추가적인 최적화를 고려해볼 수 있습니다.';
        }
        else if (analysis.successRate >= 70) {
            opinion = '양호한 성능: 대부분의 모델이 정상적으로 실행되었으나, 일부 오류 케이스에 대한 검토가 필요합니다.';
        }
        else {
            opinion = '주의 필요: 실행 실패율이 높아 입력 데이터 검증 및 모델 안정성 개선이 필요합니다.';
        }
        // 사용자 정의 분석이 있는 경우 추가
        if (customAnalysis) {
            opinion += `\n\n추가 분석: ${customAnalysis}`;
        }
        // 권장 사항
        const recommendations = [
            '정기적인 모델 성능 모니터링 및 최적화',
            '입력 데이터 품질 검증 프로세스 강화',
            '오류 발생 패턴 분석을 통한 예방적 조치 수립',
            '자주 사용되는 모델의 성능 튜닝 고려'
        ];
        const journalCount = sessionData.executions.filter(e => e.modelName === 'journal').length;
        const analysisCount = analysis.totalExecutions - journalCount;
        return `
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SEBIT MCP 세션 분석 보고서</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap');
        body {
            font-family: 'Noto Sans KR', sans-serif;
            line-height: 1.6;
            color: #333;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #fff;
        }
        .header {
            text-align: center;
            border-bottom: 3px solid #4ECDC4;
            padding-bottom: 20px;
            margin-bottom: 30px;
        }
        .header h1 {
            color: #2C3E50;
            font-size: 24px;
            font-weight: 700;
            margin: 0;
        }
        .header .subtitle {
            color: #7F8C8D;
            font-size: 14px;
            margin-top: 10px;
        }
        .section {
            margin-bottom: 30px;
            padding: 20px;
            border-left: 4px solid #4ECDC4;
            background-color: #F8F9FA;
        }
        .section h2 {
            color: #2C3E50;
            font-size: 18px;
            font-weight: 600;
            margin-top: 0;
            margin-bottom: 15px;
        }
        .stats-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            margin-bottom: 20px;
        }
        .stat-item {
            background: white;
            padding: 15px;
            border-radius: 8px;
            border: 1px solid #E0E6ED;
        }
        .stat-label {
            font-size: 12px;
            color: #7F8C8D;
            margin-bottom: 5px;
        }
        .stat-value {
            font-size: 16px;
            font-weight: 600;
            color: #2C3E50;
        }
        .model-item {
            background: white;
            padding: 15px;
            margin-bottom: 15px;
            border-radius: 8px;
            border: 1px solid #E0E6ED;
        }
        .model-title {
            font-weight: 600;
            color: #2C3E50;
            margin-bottom: 8px;
        }
        .model-purpose {
            font-size: 13px;
            color: #5D6D7E;
            margin-bottom: 8px;
        }
        .model-insights {
            font-size: 13px;
            color: #34495E;
            background: #EBF5FF;
            padding: 10px;
            border-radius: 5px;
            border-left: 3px solid #3498DB;
        }
        .error-item {
            background: #FFF5F5;
            border: 1px solid #FED7D7;
            border-radius: 5px;
            padding: 10px;
            margin-bottom: 8px;
            font-size: 13px;
            color: #C53030;
        }
        .recommendation {
            background: #F0FFF4;
            border: 1px solid #C6F6D5;
            border-radius: 5px;
            padding: 10px;
            margin-bottom: 8px;
            font-size: 13px;
            color: #2F855A;
        }
        .opinion-text {
            background: white;
            padding: 15px;
            border-radius: 8px;
            border: 1px solid #E0E6ED;
            line-height: 1.7;
            white-space: pre-line;
        }
        .page-break {
            page-break-before: always;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>SEBIT MCP 세션 분석 보고서</h1>
        <div class="subtitle">
            생성일시: ${(0, dayjs_1.default)().format('YYYY년 MM월 DD일 HH:mm:ss')}<br>
            세션 ID: ${sessionData.sessionId}
        </div>
    </div>
    <div class="section">
        <h2>📊 세션 요약</h2>
        <div class="stats-grid">
            <div class="stat-item">
                <div class="stat-label">총 실행 모델 수</div>
                <div class="stat-value">${analysis.totalExecutions}개</div>
            </div>
            <div class="stat-item">
                <div class="stat-label">성공률</div>
                <div class="stat-value">${analysis.successRate.toFixed(1)}%</div>
            </div>
            <div class="stat-item">
                <div class="stat-label">평균 실행 시간</div>
                <div class="stat-value">${analysis.avgExecutionTime.toFixed(2)}ms</div>
            </div>
            <div class="stat-item">
                <div class="stat-label">세션 기간</div>
                <div class="stat-value">${(0, dayjs_1.default)(analysis.timeRange.start).format('HH:mm:ss')} ~ ${(0, dayjs_1.default)(analysis.timeRange.end).format('HH:mm:ss')}</div>
            </div>
        </div>
        <div style="font-size: 13px; color: #7F8C8D;">
            - 분석 모델: ${analysisCount}개, 분개 처리: ${journalCount}개
        </div>
    </div>
    ${analysis.mostUsedModels.length > 0 ? `
    <div class="section">
        <h2>🔍 주요 사용 모델</h2>
        ${analysis.mostUsedModels.map(({ model, count }) => {
            const desc = models[model];
            return `<div style="margin-bottom: 10px; padding: 8px; background: white; border-radius: 5px;">
            <strong>${count}회</strong> - ${desc.description}
          </div>`;
        }).join('')}
    </div>
    ` : ''}
    ${analysis.mostUsedModels.filter(({ model }) => model !== 'journal').length > 0 ? `
    <div class="section page-break">
        <h2>📈 상세 분석 및 인사이트</h2>
        ${analysis.mostUsedModels.filter(({ model }) => model !== 'journal').slice(0, 3).map(({ model, count }) => {
            const desc = models[model];
            return `
          <div class="model-item">
            <div class="model-title">${desc.description} (${count}회 실행)</div>
            <div class="model-purpose"><strong>용도:</strong> ${desc.purpose}</div>
            <div class="model-insights"><strong>인사이트:</strong> ${desc.insights}</div>
          </div>
          `;
        }).join('')}
    </div>
    ` : ''}
    ${claudeAnalysis ? `
    <div class="section">
        <h2>🤖 클로드 분석 보고서</h2>
        <div class="opinion-text" style="white-space: pre-line; line-height: 1.8;">${claudeAnalysis}</div>
    </div>
    ` : `
    <div class="section">
        <h2>🧠 전략적 분석</h2>
        <div class="opinion-text">${strategicInsights}</div>
    </div>
    `}
    ${risksAndOpportunities.risks.length > 0 || risksAndOpportunities.opportunities.length > 0 ? `
    <div class="section">
        <h2>⚠️ 리스크 및 기회 분석</h2>
        ${risksAndOpportunities.risks.length > 0 ? `
        <h3 style="color: #E74C3C; margin-bottom: 10px;">🚨 주요 리스크</h3>
        ${risksAndOpportunities.risks.map(risk => `<div class="error-item" style="background: #FADBD8; border: 1px solid #E74C3C; color: #A93226;">• ${risk}</div>`).join('')}
        ` : ''}
        ${risksAndOpportunities.opportunities.length > 0 ? `
        <h3 style="color: #27AE60; margin-bottom: 10px; margin-top: 20px;">🌟 발견된 기회</h3>
        ${risksAndOpportunities.opportunities.map(opportunity => `<div class="recommendation" style="background: #D5F4E6; border: 1px solid #27AE60; color: #1E8449;">• ${opportunity}</div>`).join('')}
        ` : ''}
    </div>
    ` : ''}
    ${analysis.errorSummary.length > 0 ? `
    <div class="section">
        <h2>⚠️ 오류 분석</h2>
        ${analysis.errorSummary.map(error => `<div class="error-item">• ${error}</div>`).join('')}
    </div>
    ` : ''}
    <div class="section page-break">
        <h2>💡 종합 의견 및 개선 방안</h2>
        <div class="opinion-text">${opinion}</div>
        <h3 style="margin-top: 25px; margin-bottom: 15px; color: #2C3E50;">권장 사항:</h3>
        ${recommendations.map((rec, index) => `<div class="recommendation">${index + 1}. ${rec}</div>`).join('')}
    </div>
    <div style="text-align: center; margin-top: 40px; padding-top: 20px; border-top: 1px solid #E0E6ED; color: #7F8C8D; font-size: 12px;">
        SEBIT MCP 세션 분석 보고서 | 생성 시간: ${(0, dayjs_1.default)().format('YYYY-MM-DD HH:mm:ss')}
    </div>
</body>
</html>
    `;
    }
    // HTML을 PDF로 변환 (한글 지원)
    async generateSessionReport(sessionData, savePath, customAnalysis, claudeAnalysis, language = 'ko') {
        try {
            const htmlContent = this.generateHTML(sessionData, customAnalysis, claudeAnalysis, language);
            // Puppeteer를 사용하여 PDF 생성
            const puppeteer = require('puppeteer');
            const browser = await puppeteer.launch({
                headless: true,
                args: ['--no-sandbox', '--disable-setuid-sandbox']
            });
            const page = await browser.newPage();
            await page.setContent(htmlContent, { waitUntil: 'networkidle0' });
            // PDF 옵션
            const pdfBuffer = await page.pdf({
                format: 'A4',
                printBackground: true,
                margin: {
                    top: '1cm',
                    right: '1cm',
                    bottom: '1cm',
                    left: '1cm'
                }
            });
            await browser.close();
            // 파일 저장 (기본 경로 강제 적용)
            let finalSavePath;
            if (savePath && savePath.trim() !== '') {
                // 사용자가 명시적으로 경로를 지정한 경우만 사용
                finalSavePath = savePath;
                logger_1.Logger.info(`Using user-specified path: ${finalSavePath}`);
            }
            else {
                // 연도/월/일 폴더 구조로 정리
                const now = (0, dayjs_1.default)();
                const year = now.format('YYYY');
                const month = now.format('MM');
                const day = now.format('DD');
                finalSavePath = path_1.default.join(MultiLanguagePDFGenerator.DEFAULT_SAVE_PATH, year, month, day);
                logger_1.Logger.info(`Using date-structured path: ${finalSavePath}`);
            }
            await this.ensureDirectoryExists(finalSavePath);
            const fileName = `SEBIT-MCP-Report_${(0, dayjs_1.default)().format('YYYY-MM-DD_HH-mm-ss')}.pdf`;
            const fullPath = path_1.default.join(finalSavePath, fileName);
            await fs_extra_1.default.writeFile(fullPath, pdfBuffer);
            logger_1.Logger.info(`Korean session report generated successfully: ${fullPath}`);
            return fullPath;
        }
        catch (error) {
            logger_1.Logger.error('Failed to generate Korean PDF report', error);
            throw error;
        }
    }
}
exports.MultiLanguagePDFGenerator = MultiLanguagePDFGenerator;