diff --git a/backend/src/services/optimizedAgenticRAGProcessor.ts b/backend/src/services/optimizedAgenticRAGProcessor.ts index c202faf..60518f1 100644 --- a/backend/src/services/optimizedAgenticRAGProcessor.ts +++ b/backend/src/services/optimizedAgenticRAGProcessor.ts @@ -499,35 +499,11 @@ export class OptimizedAgenticRAGProcessor { if (analysisData.dealOverview.geography) { summary += `**Geography:** ${analysisData.dealOverview.geography}\n\n`; } - } - - // Add financial summary - if (analysisData.financialSummary?.financials) { - summary += `## Financial Summary\n\n`; - const financials = analysisData.financialSummary.financials; - - if (financials.fy3) { - summary += `### FY3 (Latest)\n\n`; - if (financials.fy3.revenue) summary += `- **Revenue:** ${financials.fy3.revenue}\n`; - if (financials.fy3.ebitda) summary += `- **EBITDA:** ${financials.fy3.ebitda}\n`; - if (financials.fy3.ebitdaMargin) summary += `- **EBITDA Margin:** ${financials.fy3.ebitdaMargin}\n`; - if (financials.fy3.revenueGrowth) summary += `- **Revenue Growth:** ${financials.fy3.revenueGrowth}\n\n`; + if (analysisData.dealOverview.dealSource) { + summary += `**Deal Source:** ${analysisData.dealOverview.dealSource}\n\n`; } - - if (financials.fy2) { - summary += `### FY2\n\n`; - if (financials.fy2.revenue) summary += `- **Revenue:** ${financials.fy2.revenue}\n`; - if (financials.fy2.ebitda) summary += `- **EBITDA:** ${financials.fy2.ebitda}\n`; - if (financials.fy2.ebitdaMargin) summary += `- **EBITDA Margin:** ${financials.fy2.ebitdaMargin}\n`; - if (financials.fy2.revenueGrowth) summary += `- **Revenue Growth:** ${financials.fy2.revenueGrowth}\n\n`; - } - - if (financials.fy1) { - summary += `### FY1\n\n`; - if (financials.fy1.revenue) summary += `- **Revenue:** ${financials.fy1.revenue}\n`; - if (financials.fy1.ebitda) summary += `- **EBITDA:** ${financials.fy1.ebitda}\n`; - if (financials.fy1.ebitdaMargin) summary += `- **EBITDA Margin:** ${financials.fy1.ebitdaMargin}\n`; - if (financials.fy1.revenueGrowth) summary += `- **Revenue Growth:** ${financials.fy1.revenueGrowth}\n\n`; + if (analysisData.dealOverview.statedReasonForSale) { + summary += `**Reason for Sale:** ${analysisData.dealOverview.statedReasonForSale}\n\n`; } } @@ -542,15 +518,153 @@ export class OptimizedAgenticRAGProcessor { if (analysisData.businessDescription.uniqueValueProposition) { summary += `**Unique Value Proposition:** ${analysisData.businessDescription.uniqueValueProposition}\n\n`; } + + // Add customer base overview + if (analysisData.businessDescription.customerBaseOverview) { + summary += `### Customer Base Overview\n\n`; + if (analysisData.businessDescription.customerBaseOverview.keyCustomerSegments) { + summary += `**Key Customer Segments:** ${analysisData.businessDescription.customerBaseOverview.keyCustomerSegments}\n\n`; + } + if (analysisData.businessDescription.customerBaseOverview.customerConcentrationRisk) { + summary += `**Customer Concentration Risk:** ${analysisData.businessDescription.customerBaseOverview.customerConcentrationRisk}\n\n`; + } + if (analysisData.businessDescription.customerBaseOverview.typicalContractLength) { + summary += `**Typical Contract Length:** ${analysisData.businessDescription.customerBaseOverview.typicalContractLength}\n\n`; + } + } + + // Add supplier overview + if (analysisData.businessDescription.keySupplierOverview?.dependenceConcentrationRisk) { + summary += `**Supplier Dependence Risk:** ${analysisData.businessDescription.keySupplierOverview.dependenceConcentrationRisk}\n\n`; + } } - // Add key questions and next steps - if (analysisData.keyQuestionsNextSteps?.criticalQuestions) { - summary += `## Key Questions & Next Steps\n\n`; - summary += `**Critical Questions:** ${analysisData.keyQuestionsNextSteps.criticalQuestions}\n\n`; + // Add market analysis + if (analysisData.marketIndustryAnalysis?.estimatedMarketSize) { + summary += `## Market & Industry Analysis\n\n`; + summary += `**Market Size:** ${analysisData.marketIndustryAnalysis.estimatedMarketSize}\n\n`; - if (analysisData.keyQuestionsNextSteps.preliminaryRecommendation) { - summary += `**Preliminary Recommendation:** ${analysisData.keyQuestionsNextSteps.preliminaryRecommendation}\n\n`; + if (analysisData.marketIndustryAnalysis.estimatedMarketGrowthRate) { + summary += `**Market Growth Rate:** ${analysisData.marketIndustryAnalysis.estimatedMarketGrowthRate}\n\n`; + } + if (analysisData.marketIndustryAnalysis.keyIndustryTrends) { + summary += `**Industry Trends:** ${analysisData.marketIndustryAnalysis.keyIndustryTrends}\n\n`; + } + if (analysisData.marketIndustryAnalysis.barriersToEntry) { + summary += `**Barriers to Entry:** ${analysisData.marketIndustryAnalysis.barriersToEntry}\n\n`; + } + + // Add competitive landscape + if (analysisData.marketIndustryAnalysis.competitiveLandscape) { + summary += `### Competitive Landscape\n\n`; + if (analysisData.marketIndustryAnalysis.competitiveLandscape.keyCompetitors) { + summary += `**Key Competitors:** ${analysisData.marketIndustryAnalysis.competitiveLandscape.keyCompetitors}\n\n`; + } + if (analysisData.marketIndustryAnalysis.competitiveLandscape.targetMarketPosition) { + summary += `**Market Position:** ${analysisData.marketIndustryAnalysis.competitiveLandscape.targetMarketPosition}\n\n`; + } + if (analysisData.marketIndustryAnalysis.competitiveLandscape.basisOfCompetition) { + summary += `**Basis of Competition:** ${analysisData.marketIndustryAnalysis.competitiveLandscape.basisOfCompetition}\n\n`; + } + } + } + + // Add financial summary + if (analysisData.financialSummary?.financials) { + summary += `## Financial Summary\n\n`; + const financials = analysisData.financialSummary.financials; + + // Create financial table + summary += `\n`; + summary += `\n\n\n`; + + const periods = []; + if (financials.fy1) periods.push('FY1'); + if (financials.fy2) periods.push('FY2'); + if (financials.fy3) periods.push('FY3'); + if (financials.ltm) periods.push('LTM'); + + periods.forEach(period => { + summary += `\n`; + }); + summary += `\n\n\n`; + + // Revenue row + if (financials.fy1?.revenue || financials.fy2?.revenue || financials.fy3?.revenue || financials.ltm?.revenue) { + summary += `\n\n`; + periods.forEach(period => { + let value = '-'; + if (period === 'FY1' && financials.fy1?.revenue) value = financials.fy1.revenue; + else if (period === 'FY2' && financials.fy2?.revenue) value = financials.fy2.revenue; + else if (period === 'FY3' && financials.fy3?.revenue) value = financials.fy3.revenue; + else if (period === 'LTM' && financials.ltm?.revenue) value = financials.ltm.revenue; + summary += `\n`; + }); + summary += `\n`; + } + + // EBITDA row + if (financials.fy1?.ebitda || financials.fy2?.ebitda || financials.fy3?.ebitda || financials.ltm?.ebitda) { + summary += `\n\n`; + periods.forEach(period => { + let value = '-'; + if (period === 'FY1' && financials.fy1?.ebitda) value = financials.fy1.ebitda; + else if (period === 'FY2' && financials.fy2?.ebitda) value = financials.fy2.ebitda; + else if (period === 'FY3' && financials.fy3?.ebitda) value = financials.fy3.ebitda; + else if (period === 'LTM' && financials.ltm?.ebitda) value = financials.ltm.ebitda; + summary += `\n`; + }); + summary += `\n`; + } + + // EBITDA Margin row + if (financials.fy1?.ebitdaMargin || financials.fy2?.ebitdaMargin || financials.fy3?.ebitdaMargin || financials.ltm?.ebitdaMargin) { + summary += `\n\n`; + periods.forEach(period => { + let value = '-'; + if (period === 'FY1' && financials.fy1?.ebitdaMargin) value = financials.fy1.ebitdaMargin; + else if (period === 'FY2' && financials.fy2?.ebitdaMargin) value = financials.fy2.ebitdaMargin; + else if (period === 'FY3' && financials.fy3?.ebitdaMargin) value = financials.fy3.ebitdaMargin; + else if (period === 'LTM' && financials.ltm?.ebitdaMargin) value = financials.ltm.ebitdaMargin; + summary += `\n`; + }); + summary += `\n`; + } + + // Revenue Growth row + if (financials.fy1?.revenueGrowth || financials.fy2?.revenueGrowth || financials.fy3?.revenueGrowth || financials.ltm?.revenueGrowth) { + summary += `\n\n`; + periods.forEach(period => { + let value = '-'; + if (period === 'FY1' && financials.fy1?.revenueGrowth) value = financials.fy1.revenueGrowth; + else if (period === 'FY2' && financials.fy2?.revenueGrowth) value = financials.fy2.revenueGrowth; + else if (period === 'FY3' && financials.fy3?.revenueGrowth) value = financials.fy3.revenueGrowth; + else if (period === 'LTM' && financials.ltm?.revenueGrowth) value = financials.ltm.revenueGrowth; + summary += `\n`; + }); + summary += `\n`; + } + + summary += `\n
Metric${period}
Revenue${value}
EBITDA${value}
EBITDA Margin${value}
Revenue Growth${value}
\n\n`; + + // Add financial notes + if (analysisData.financialSummary.qualityOfEarnings) { + summary += `**Quality of Earnings:** ${analysisData.financialSummary.qualityOfEarnings}\n\n`; + } + if (analysisData.financialSummary.revenueGrowthDrivers) { + summary += `**Revenue Growth Drivers:** ${analysisData.financialSummary.revenueGrowthDrivers}\n\n`; + } + if (analysisData.financialSummary.marginStabilityAnalysis) { + summary += `**Margin Stability:** ${analysisData.financialSummary.marginStabilityAnalysis}\n\n`; + } + if (analysisData.financialSummary.capitalExpenditures) { + summary += `**Capital Expenditures:** ${analysisData.financialSummary.capitalExpenditures}\n\n`; + } + if (analysisData.financialSummary.workingCapitalIntensity) { + summary += `**Working Capital Intensity:** ${analysisData.financialSummary.workingCapitalIntensity}\n\n`; + } + if (analysisData.financialSummary.freeCashFlowQuality) { + summary += `**Free Cash Flow Quality:** ${analysisData.financialSummary.freeCashFlowQuality}\n\n`; } } @@ -562,15 +676,11 @@ export class OptimizedAgenticRAGProcessor { if (analysisData.managementTeamOverview.managementQualityAssessment) { summary += `**Quality Assessment:** ${analysisData.managementTeamOverview.managementQualityAssessment}\n\n`; } - } - - // Add market analysis - if (analysisData.marketIndustryAnalysis?.estimatedMarketSize) { - summary += `## Market & Industry Analysis\n\n`; - summary += `**Market Size:** ${analysisData.marketIndustryAnalysis.estimatedMarketSize}\n\n`; - - if (analysisData.marketIndustryAnalysis.keyIndustryTrends) { - summary += `**Industry Trends:** ${analysisData.marketIndustryAnalysis.keyIndustryTrends}\n\n`; + if (analysisData.managementTeamOverview.postTransactionIntentions) { + summary += `**Post-Transaction Intentions:** ${analysisData.managementTeamOverview.postTransactionIntentions}\n\n`; + } + if (analysisData.managementTeamOverview.organizationalStructure) { + summary += `**Organizational Structure:** ${analysisData.managementTeamOverview.organizationalStructure}\n\n`; } } @@ -582,6 +692,31 @@ export class OptimizedAgenticRAGProcessor { if (analysisData.preliminaryInvestmentThesis.potentialRisks) { summary += `**Potential Risks:** ${analysisData.preliminaryInvestmentThesis.potentialRisks}\n\n`; } + if (analysisData.preliminaryInvestmentThesis.valueCreationLevers) { + summary += `**Value Creation Levers:** ${analysisData.preliminaryInvestmentThesis.valueCreationLevers}\n\n`; + } + if (analysisData.preliminaryInvestmentThesis.alignmentWithFundStrategy) { + summary += `**Alignment with Fund Strategy:** ${analysisData.preliminaryInvestmentThesis.alignmentWithFundStrategy}\n\n`; + } + } + + // Add key questions and next steps + if (analysisData.keyQuestionsNextSteps?.criticalQuestions) { + summary += `## Key Questions & Next Steps\n\n`; + summary += `**Critical Questions:** ${analysisData.keyQuestionsNextSteps.criticalQuestions}\n\n`; + + if (analysisData.keyQuestionsNextSteps.missingInformation) { + summary += `**Missing Information:** ${analysisData.keyQuestionsNextSteps.missingInformation}\n\n`; + } + if (analysisData.keyQuestionsNextSteps.preliminaryRecommendation) { + summary += `**Preliminary Recommendation:** ${analysisData.keyQuestionsNextSteps.preliminaryRecommendation}\n\n`; + } + if (analysisData.keyQuestionsNextSteps.rationaleForRecommendation) { + summary += `**Rationale for Recommendation:** ${analysisData.keyQuestionsNextSteps.rationaleForRecommendation}\n\n`; + } + if (analysisData.keyQuestionsNextSteps.proposedNextSteps) { + summary += `**Proposed Next Steps:** ${analysisData.keyQuestionsNextSteps.proposedNextSteps}\n\n`; + } } return summary; diff --git a/backend/src/services/pdfGenerationService.ts b/backend/src/services/pdfGenerationService.ts index 986e243..8c59041 100644 --- a/backend/src/services/pdfGenerationService.ts +++ b/backend/src/services/pdfGenerationService.ts @@ -74,8 +74,7 @@ class PDFGenerationService { * Convert markdown to HTML */ private markdownToHTML(markdown: string): string { - // Simple markdown to HTML conversion - // In a production environment, you might want to use a proper markdown parser + // Enhanced markdown to HTML conversion with table support let html = markdown // Headers .replace(/^### (.*$)/gim, '

$1

') @@ -87,13 +86,19 @@ class PDFGenerationService { .replace(/\*(.*?)\*/g, '$1') // Lists .replace(/^- (.*$)/gim, '
  • $1
  • ') - // Paragraphs + // Paragraphs (but preserve tables) .replace(/\n\n/g, '

    ') .replace(/^(.+)$/gm, '

    $1

    '); // Wrap lists properly html = html.replace(/
  • (.*?)<\/li>/g, ''); html = html.replace(/<\/ul>\s*