import { z } from 'zod';
import { createLogger } from '../utils/logger.js';
import { insightEngine } from './insight-engine.js';
import { predictiveAnalytics } from './predictive-analytics.js';
/**
* Recommendation Engine Service
*
* Generates personalized, actionable recommendations using ML-driven insights,
* historical patterns, and contextual understanding.
*/
// Recommendation schemas
export const RecommendationSchema = z.object({
id: z.string(),
type: z.enum(['strategic', 'tactical', 'operational', 'risk_mitigation', 'opportunity']),
priority: z.enum(['critical', 'high', 'medium', 'low']),
title: z.string(),
description: z.string(),
rationale: z.string(),
expected_impact: z.object({
metric: z.string(),
change: z.string(),
confidence: z.number().min(0).max(1)
}),
implementation: z.object({
complexity: z.enum(['low', 'medium', 'high']),
timeline: z.string(),
prerequisites: z.array(z.string()),
resources_required: z.array(z.string())
}),
alternatives: z.array(z.object({
title: z.string(),
tradeoff: z.string()
})).optional(),
success_criteria: z.array(z.string()),
related_insights: z.array(z.string()).optional()
});
export const PersonalizedRecommendationsSchema = z.object({
recommendations: z.array(RecommendationSchema),
strategy_narrative: z.string(),
decision_framework: z.object({
criteria: z.array(z.string()),
weights: z.record(z.number()),
scoring_method: z.string()
}),
implementation_roadmap: z.array(z.object({
phase: z.string(),
duration: z.string(),
key_activities: z.array(z.string()),
milestones: z.array(z.string()),
dependencies: z.array(z.string()).optional()
})),
risk_considerations: z.array(z.object({
risk: z.string(),
mitigation: z.string(),
contingency: z.string().optional()
}))
});
export const NextBestActionSchema = z.object({
action: z.string(),
reasoning: z.string(),
expected_outcome: z.string(),
confidence: z.number().min(0).max(1),
prerequisites_met: z.boolean(),
missing_prerequisites: z.array(z.string()).optional(),
estimated_effort: z.object({
hours: z.number(),
complexity: z.enum(['trivial', 'simple', 'moderate', 'complex', 'very_complex'])
}),
tools_needed: z.array(z.string())
});
export type Recommendation = z.infer<typeof RecommendationSchema>;
export type PersonalizedRecommendations = z.infer<typeof PersonalizedRecommendationsSchema>;
export type NextBestAction = z.infer<typeof NextBestActionSchema>;
export class RecommendationEngine {
private logger = createLogger({ component: 'RecommendationEngine' });
// Recommendation templates and patterns
private readonly RECOMMENDATION_PATTERNS = {
high_roi_quick_payback: {
condition: (data: any) => data.roi > 150 && data.payback < 12,
recommendations: [
{
type: 'strategic',
priority: 'critical',
title: 'Accelerate Implementation Timeline',
template: 'Given {roi}% ROI and {payback}-month payback, accelerating implementation can capture value sooner'
},
{
type: 'tactical',
priority: 'high',
title: 'Scale Successful Patterns',
template: 'High-performing use cases should be replicated across similar processes'
}
]
},
high_complexity_project: {
condition: (data: any) => data.use_case_count > 7 || data.complexity_score > 0.7,
recommendations: [
{
type: 'risk_mitigation',
priority: 'high',
title: 'Implement Phased Rollout',
template: 'Complex project with {use_case_count} use cases requires phased approach'
},
{
type: 'operational',
priority: 'high',
title: 'Establish PMO Structure',
template: 'Project complexity necessitates dedicated project management office'
}
]
}
};
/**
* Generate personalized recommendations for a project
*/
async generateRecommendations(
projectData: any,
context?: any
): Promise<PersonalizedRecommendations> {
this.logger.debug('Generating personalized recommendations');
// Analyze project with multiple engines
const [insights, predictions] = await Promise.all([
insightEngine.generateROIInsights(
projectData.summary,
projectData.use_cases,
projectData.financial_metrics,
context?.benchmarks
),
predictiveAnalytics.predictProjectSuccess(projectData)
]);
// Generate recommendations based on patterns
const recommendations = this.createRecommendations(
projectData,
insights,
predictions,
context
);
// Create strategy narrative
const strategyNarrative = this.generateStrategyNarrative(
recommendations,
projectData,
predictions
);
// Build decision framework
const decisionFramework = this.createDecisionFramework(projectData, context);
// Create implementation roadmap
const roadmap = this.generateImplementationRoadmap(
recommendations,
projectData,
predictions
);
// Identify risks and mitigations
const riskConsiderations = this.identifyRiskConsiderations(
insights.risks,
predictions,
projectData
);
return {
recommendations,
strategy_narrative: strategyNarrative,
decision_framework: decisionFramework,
implementation_roadmap: roadmap,
risk_considerations: riskConsiderations
};
}
/**
* Determine next best action based on current state
*/
async getNextBestAction(
currentState: any,
availableActions: string[],
context?: any
): Promise<NextBestAction> {
this.logger.debug('Determining next best action');
// Score each available action
const scoredActions = await Promise.all(
availableActions.map(action => this.scoreAction(action, currentState, context))
);
// Select best action
const bestAction = scoredActions.reduce((best, current) =>
current.score > best.score ? current : best
);
// Check prerequisites
const prerequisites = this.checkPrerequisites(bestAction.action, currentState);
// Estimate effort
const effort = this.estimateEffort(bestAction.action, currentState);
// Identify required tools
const toolsNeeded = this.identifyRequiredTools(bestAction.action);
return {
action: bestAction.action,
reasoning: bestAction.reasoning,
expected_outcome: bestAction.expected_outcome,
confidence: bestAction.confidence,
prerequisites_met: prerequisites.allMet,
missing_prerequisites: prerequisites.missing.length > 0 ? prerequisites.missing : undefined,
estimated_effort: effort,
tools_needed: toolsNeeded
};
}
/**
* Generate industry-specific recommendations
*/
async getIndustryRecommendations(
industry: string,
projectData: any
): Promise<Recommendation[]> {
this.logger.debug('Generating industry-specific recommendations', { industry });
const industryPatterns = this.getIndustryPatterns(industry);
const recommendations: Recommendation[] = [];
// Apply industry-specific patterns
industryPatterns.forEach(pattern => {
if (pattern.condition(projectData)) {
const recs = pattern.recommendations.map((rec: any) =>
this.instantiateRecommendation(rec, projectData, industry)
);
recommendations.push(...recs);
}
});
// Add regulatory compliance if needed
if (this.requiresRegulatoryCompliance(industry)) {
recommendations.push(this.createRegulatoryRecommendation(industry, projectData));
}
// Add industry best practices
const bestPractices = this.getIndustryBestPractices(industry, projectData);
recommendations.push(...bestPractices);
return this.prioritizeRecommendations(recommendations);
}
/**
* Generate recommendations for project portfolio
*/
async getPortfolioRecommendations(
projects: any[],
constraints?: {
budget?: number;
timeline?: number;
resources?: any;
}
): Promise<{
portfolio_strategy: string;
project_priorities: Array<{
project_id: string;
priority: number;
rationale: string;
}>;
synergy_opportunities: Array<{
projects: string[];
synergy_type: string;
value_add: string;
}>;
resource_optimization: Recommendation[];
}> {
this.logger.debug('Generating portfolio recommendations', {
project_count: projects.length
});
// Analyze portfolio characteristics
const portfolioAnalysis = this.analyzePortfolio(projects);
// Determine optimal strategy
const strategy = this.determinePortfolioStrategy(portfolioAnalysis, constraints);
// Prioritize projects
const priorities = this.prioritizeProjects(projects, strategy, constraints);
// Identify synergies
const synergies = this.identifySynergies(projects);
// Generate resource optimization recommendations
const resourceOptimization = this.optimizeResourceAllocation(
projects,
priorities,
constraints
);
return {
portfolio_strategy: strategy,
project_priorities: priorities,
synergy_opportunities: synergies,
resource_optimization: resourceOptimization
};
}
// Private helper methods
private createRecommendations(
projectData: any,
insights: any,
predictions: any,
context?: any
): Recommendation[] {
const recommendations: Recommendation[] = [];
// Pattern-based recommendations
Object.values(this.RECOMMENDATION_PATTERNS).forEach(pattern => {
if (pattern.condition(this.extractMetrics(projectData))) {
pattern.recommendations.forEach(recTemplate => {
recommendations.push(
this.instantiateRecommendation(recTemplate, projectData)
);
});
}
});
// Insight-driven recommendations
insights.opportunities.forEach((opp: any) => {
recommendations.push(this.createOpportunityRecommendation(opp, projectData));
});
// Risk-based recommendations
insights.risks.forEach((risk: any) => {
recommendations.push(this.createRiskRecommendation(risk, projectData));
});
// Success probability recommendations
if (predictions.overall < 0.6) {
recommendations.push(this.createSuccessImprovementRecommendation(predictions));
}
return this.prioritizeRecommendations(recommendations);
}
private extractMetrics(projectData: any): any {
return {
roi: projectData.summary?.expected_roi || 0,
payback: projectData.summary?.payback_period_months || 24,
use_case_count: projectData.use_cases?.length || 0,
complexity_score: this.calculateComplexityScore(projectData),
total_investment: projectData.summary?.total_investment || 0
};
}
private calculateComplexityScore(projectData: any): number {
const factors = {
use_case_count: Math.min(projectData.use_cases?.length || 0, 10) / 10,
investment_size: Math.min(projectData.summary?.total_investment || 0, 1000000) / 1000000,
timeline: Math.min(projectData.timeline_months || 12, 24) / 24
};
return (factors.use_case_count + factors.investment_size + factors.timeline) / 3;
}
private instantiateRecommendation(
template: any,
projectData: any,
industry?: string
): Recommendation {
const metrics = this.extractMetrics(projectData);
return {
id: this.generateRecommendationId(),
type: template.type,
priority: template.priority,
title: template.title,
description: this.fillTemplate(template.template || template.description, metrics),
rationale: this.generateRationale(template, projectData, industry),
expected_impact: {
metric: this.identifyImpactMetric(template),
change: this.estimateImpactChange(template, projectData),
confidence: 0.75
},
implementation: {
complexity: this.assessImplementationComplexity(template, projectData),
timeline: this.estimateTimeline(template, projectData),
prerequisites: this.identifyPrerequisites(template, projectData),
resources_required: this.identifyResources(template)
},
success_criteria: this.defineSuccessCriteria(template, projectData)
};
}
private fillTemplate(template: string, metrics: any): string {
return template.replace(/{(\w+)}/g, (match, key) => {
return metrics[key]?.toString() || match;
});
}
private generateRationale(template: any, projectData: any, industry?: string): string {
const baseRationale = `This recommendation is based on `;
const factors = [];
if (template.type === 'strategic') {
factors.push('strategic alignment with high-value outcomes');
}
if (template.priority === 'critical') {
factors.push('critical impact on project success');
}
if (industry) {
factors.push(`${industry} industry best practices`);
}
return baseRationale + factors.join(', ');
}
private createOpportunityRecommendation(opportunity: any, projectData: any): Recommendation {
return {
id: this.generateRecommendationId(),
type: 'opportunity',
priority: opportunity.potentialValue > 100000 ? 'high' : 'medium',
title: `Pursue ${opportunity.type} opportunity`,
description: opportunity.description,
rationale: `Opportunity to capture additional value of $${(opportunity.potentialValue / 1000).toFixed(0)}K`,
expected_impact: {
metric: 'Additional ROI',
change: `+${((opportunity.potentialValue / projectData.summary.total_investment) * 100).toFixed(0)}%`,
confidence: 0.7
},
implementation: {
complexity: opportunity.type === 'quick_win' ? 'low' : 'medium',
timeline: opportunity.timeToRealize,
prerequisites: opportunity.requirements || [],
resources_required: this.inferResourcesFromOpportunity(opportunity)
},
success_criteria: [
`Realize ${opportunity.potentialValue * 0.7} in value`,
`Complete implementation within ${opportunity.timeToRealize}`,
'Achieve positive stakeholder feedback'
]
};
}
private createRiskRecommendation(risk: any, projectData: any): Recommendation {
return {
id: this.generateRecommendationId(),
type: 'risk_mitigation',
priority: risk.impact === 'high' ? 'high' : 'medium',
title: `Mitigate ${risk.factor}`,
description: risk.mitigation,
rationale: `Risk probability of ${(risk.probability * 100).toFixed(0)}% with ${risk.impact} impact requires proactive mitigation`,
expected_impact: {
metric: 'Risk Reduction',
change: `-${(risk.probability * 0.6 * 100).toFixed(0)}% probability`,
confidence: 0.8
},
implementation: {
complexity: 'medium',
timeline: '30-60 days',
prerequisites: ['Risk assessment complete', 'Stakeholder alignment'],
resources_required: ['Risk management team', 'Mitigation budget']
},
success_criteria: risk.earlyWarnings || ['Risk indicators remain within acceptable range']
};
}
private createSuccessImprovementRecommendation(predictions: any): Recommendation {
const topFactors = predictions.factors
.filter((f: any) => f.impact === 'negative')
.slice(0, 2);
return {
id: this.generateRecommendationId(),
type: 'strategic',
priority: 'high',
title: 'Improve Project Success Probability',
description: `Current success probability of ${(predictions.overall * 100).toFixed(0)}% can be improved by addressing key factors`,
rationale: `Addressing ${topFactors.map((f: any) => f.name).join(' and ')} can significantly improve outcomes`,
expected_impact: {
metric: 'Success Probability',
change: `+${((0.8 - predictions.overall) * 100).toFixed(0)}%`,
confidence: 0.7
},
implementation: {
complexity: 'high',
timeline: '60-90 days',
prerequisites: ['Executive alignment', 'Resource commitment'],
resources_required: ['Change management team', 'Additional budget']
},
success_criteria: [
'Success probability increases to >70%',
'Key risk factors addressed',
'Stakeholder confidence improved'
]
};
}
private generateStrategyNarrative(
recommendations: Recommendation[],
projectData: any,
predictions: any
): string {
const strategic = recommendations.filter(r => r.type === 'strategic');
const critical = recommendations.filter(r => r.priority === 'critical');
let narrative = `Based on comprehensive analysis, this ${projectData.summary.expected_roi}% ROI opportunity `;
narrative += `with ${(predictions.overall * 100).toFixed(0)}% success probability `;
narrative += `requires a focused strategy. `;
if (critical.length > 0) {
narrative += `Critical priorities include ${critical.map(r => r.title.toLowerCase()).join(' and ')}. `;
}
if (strategic.length > 0) {
narrative += `Strategic initiatives should focus on ${strategic[0].title.toLowerCase()} `;
narrative += `to maximize value capture. `;
}
narrative += `The recommended approach balances quick wins with long-term value creation `;
narrative += `while maintaining acceptable risk levels.`;
return narrative;
}
private createDecisionFramework(projectData: any, context?: any): any {
const criteria = [
'ROI Impact',
'Implementation Complexity',
'Time to Value',
'Risk Level',
'Strategic Alignment'
];
// Dynamic weights based on context
const weights: Record<string, number> = {
'ROI Impact': context?.focus === 'returns' ? 0.35 : 0.25,
'Implementation Complexity': 0.2,
'Time to Value': projectData.summary.payback_period_months > 18 ? 0.25 : 0.15,
'Risk Level': 0.2,
'Strategic Alignment': context?.strategic_priority ? 0.3 : 0.15
};
// Normalize weights
const totalWeight = Object.values(weights).reduce((sum, w) => sum + w, 0);
Object.keys(weights).forEach(key => {
weights[key] = weights[key] / totalWeight;
});
return {
criteria,
weights,
scoring_method: 'Weighted multi-criteria analysis with 0-100 scale per criterion'
};
}
private generateImplementationRoadmap(
recommendations: Recommendation[],
projectData: any,
predictions: any
): any[] {
const roadmap = [];
// Phase 1: Foundation (Critical items)
const criticalRecs = recommendations.filter(r => r.priority === 'critical');
if (criticalRecs.length > 0) {
roadmap.push({
phase: 'Foundation',
duration: '0-30 days',
key_activities: criticalRecs.map(r => r.title),
milestones: [
'Critical risks addressed',
'Core team established',
'Success metrics defined'
]
});
}
// Phase 2: Quick Wins
const quickWins = recommendations.filter(r =>
r.implementation.complexity === 'low' && r.type === 'tactical'
);
roadmap.push({
phase: 'Quick Wins',
duration: '30-90 days',
key_activities: quickWins.map(r => r.title).slice(0, 3),
milestones: [
'First value delivered',
'Stakeholder buy-in secured',
'Momentum established'
],
dependencies: criticalRecs.length > 0 ? ['Foundation phase complete'] : undefined
});
// Phase 3: Scale
const strategic = recommendations.filter(r => r.type === 'strategic');
roadmap.push({
phase: 'Scale & Optimize',
duration: '90-180 days',
key_activities: strategic.map(r => r.title),
milestones: [
'Full implementation',
'Target ROI achieved',
'Continuous improvement established'
],
dependencies: ['Quick Wins phase complete']
});
return roadmap;
}
private identifyRiskConsiderations(
risks: any[],
predictions: any,
projectData: any
): any[] {
return risks.map(risk => ({
risk: risk.factor || risk,
mitigation: risk.mitigation || this.generateMitigation(risk),
contingency: this.generateContingency(risk, projectData)
}));
}
private generateMitigation(risk: any): string {
const mitigations: Record<string, string> = {
'Implementation Complexity': 'Phase implementation and increase technical resources',
'User Adoption': 'Comprehensive change management and training program',
'Technology Maturity': 'Partner with proven vendors and pilot thoroughly',
'Budget Overrun': 'Implement strict cost controls and regular reviews'
};
return mitigations[risk.factor || risk] || 'Develop specific mitigation plan';
}
private generateContingency(risk: any, projectData: any): string {
if (risk.impact === 'high' || risk.probability > 0.5) {
return 'Prepare fallback plan and allocate contingency budget';
}
return 'Monitor and reassess periodically';
}
private async scoreAction(
action: string,
currentState: any,
context?: any
): Promise<any> {
// Simplified scoring logic
const scores: Record<string, number> = {
'analyze_in_detail': currentState.analysis_complete ? 0.2 : 0.8,
'compare_alternatives': currentState.alternatives_available ? 0.9 : 0.3,
'create_implementation_plan': currentState.decision_made ? 0.85 : 0.4,
'gather_more_data': currentState.data_quality < 0.7 ? 0.7 : 0.2
};
const score = scores[action] || 0.5;
const reasoning = this.generateActionReasoning(action, currentState);
const expectedOutcome = this.predictActionOutcome(action, currentState);
return {
action,
score,
reasoning,
expected_outcome: expectedOutcome,
confidence: Math.min(0.9, score + 0.1)
};
}
private generateActionReasoning(action: string, state: any): string {
const reasoningMap: Record<string, string> = {
'analyze_in_detail': 'Detailed analysis will provide deeper insights for decision-making',
'compare_alternatives': 'Comparing options ensures optimal choice selection',
'create_implementation_plan': 'Planning ensures smooth execution and risk mitigation',
'gather_more_data': 'Additional data will improve confidence in projections'
};
return reasoningMap[action] || 'Action will progress toward project goals';
}
private predictActionOutcome(action: string, state: any): string {
const outcomeMap: Record<string, string> = {
'analyze_in_detail': 'Comprehensive understanding of opportunities and risks',
'compare_alternatives': 'Clear ranking of options with trade-off analysis',
'create_implementation_plan': 'Actionable roadmap with timelines and milestones',
'gather_more_data': 'Improved accuracy and confidence in recommendations'
};
return outcomeMap[action] || 'Progress toward decision';
}
private checkPrerequisites(action: string, state: any): {
allMet: boolean;
missing: string[];
} {
const prerequisites: Record<string, string[]> = {
'create_implementation_plan': ['Decision made', 'Resources identified', 'Stakeholder alignment'],
'compare_alternatives': ['Multiple options available', 'Evaluation criteria defined'],
'analyze_in_detail': ['Basic data available', 'Objectives clear']
};
const required = prerequisites[action] || [];
const missing = required.filter(prereq => !this.checkPrerequisite(prereq, state));
return {
allMet: missing.length === 0,
missing
};
}
private checkPrerequisite(prereq: string, state: any): boolean {
// Simplified prerequisite checking
const checks: Record<string, boolean> = {
'Decision made': state.decision_made === true,
'Resources identified': state.resources_identified === true,
'Multiple options available': (state.options?.length || 0) > 1,
'Basic data available': state.data_quality > 0.5
};
return checks[prereq] || false;
}
private estimateEffort(action: string, state: any): NextBestAction['estimated_effort'] {
const effortMap: Record<string, { hours: number; complexity: any }> = {
'analyze_in_detail': { hours: 8, complexity: 'moderate' },
'compare_alternatives': { hours: 4, complexity: 'simple' },
'create_implementation_plan': { hours: 16, complexity: 'complex' },
'gather_more_data': { hours: 6, complexity: 'simple' }
};
return effortMap[action] || { hours: 4, complexity: 'moderate' };
}
private identifyRequiredTools(action: string): string[] {
const toolMap: Record<string, string[]> = {
'analyze_in_detail': ['predict_roi'],
'compare_alternatives': ['compare_projects'],
'create_implementation_plan': ['predict_roi'],
'gather_more_data': ['predict_roi']
};
return toolMap[action] || [];
}
private getIndustryPatterns(industry: string): any[] {
const patterns: Record<string, any[]> = {
financial_services: [
{
condition: (data: any) => data.use_cases?.some((uc: any) => uc.category === 'fraud_detection'),
recommendations: [{
type: 'strategic',
priority: 'critical',
title: 'Implement Real-time Fraud Detection',
template: 'Financial services require real-time fraud capabilities for regulatory compliance'
}]
}
],
healthcare: [
{
condition: (data: any) => true,
recommendations: [{
type: 'risk_mitigation',
priority: 'critical',
title: 'Ensure HIPAA Compliance',
template: 'Healthcare AI must maintain strict patient data privacy'
}]
}
]
};
return patterns[industry] || [];
}
private requiresRegulatoryCompliance(industry: string): boolean {
return ['financial_services', 'healthcare', 'government'].includes(industry);
}
private createRegulatoryRecommendation(industry: string, projectData: any): Recommendation {
const regulations: Record<string, string> = {
financial_services: 'SOX, GDPR, and Basel III',
healthcare: 'HIPAA and HITECH',
government: 'FedRAMP and FISMA'
};
return {
id: this.generateRecommendationId(),
type: 'risk_mitigation',
priority: 'critical',
title: 'Ensure Regulatory Compliance',
description: `Implement comprehensive compliance framework for ${regulations[industry]}`,
rationale: `${industry} requires strict adherence to regulatory requirements`,
expected_impact: {
metric: 'Compliance Risk',
change: 'Eliminate non-compliance risk',
confidence: 0.95
},
implementation: {
complexity: 'high',
timeline: 'Ongoing',
prerequisites: ['Legal review', 'Compliance team'],
resources_required: ['Compliance officer', 'Audit tools', 'Training program']
},
success_criteria: [
'Pass regulatory audits',
'Zero compliance violations',
'Documented compliance processes'
]
};
}
private getIndustryBestPractices(industry: string, projectData: any): Recommendation[] {
// Simplified - would have comprehensive industry knowledge base
const practices: Record<string, Recommendation[]> = {
technology: [{
id: this.generateRecommendationId(),
type: 'operational',
priority: 'medium',
title: 'Implement CI/CD Pipeline',
description: 'Continuous integration and deployment for AI models',
rationale: 'Technology industry standard for rapid iteration',
expected_impact: {
metric: 'Deployment Speed',
change: '10x faster releases',
confidence: 0.85
},
implementation: {
complexity: 'medium',
timeline: '30 days',
prerequisites: ['DevOps team'],
resources_required: ['CI/CD tools', 'Cloud infrastructure']
},
success_criteria: ['Automated deployments', 'Reduced deployment errors']
}]
};
return practices[industry] || [];
}
private prioritizeRecommendations(recommendations: Recommendation[]): Recommendation[] {
return recommendations.sort((a, b) => {
const priorityScore: Record<string, number> = {
critical: 4,
high: 3,
medium: 2,
low: 1
};
return priorityScore[b.priority] - priorityScore[a.priority];
});
}
private analyzePortfolio(projects: any[]): any {
const totalInvestment = projects.reduce((sum, p) => sum + (p.summary?.total_investment || 0), 0);
const avgROI = projects.reduce((sum, p) => sum + (p.summary?.expected_roi || 0), 0) / projects.length;
const riskProfile = this.calculatePortfolioRisk(projects);
return {
total_investment: totalInvestment,
average_roi: avgROI,
risk_profile: riskProfile,
project_count: projects.length,
timeline_spread: this.calculateTimelineSpread(projects)
};
}
private calculatePortfolioRisk(projects: any[]): string {
const highRiskCount = projects.filter(p =>
p.risk_score > 0.6 || p.summary?.payback_period_months > 24
).length;
const riskRatio = highRiskCount / projects.length;
if (riskRatio > 0.5) return 'high';
if (riskRatio > 0.25) return 'medium';
return 'low';
}
private calculateTimelineSpread(projects: any[]): any {
const timelines = projects.map(p => p.timeline_months || 12);
return {
min: Math.min(...timelines),
max: Math.max(...timelines),
average: timelines.reduce((a, b) => a + b, 0) / timelines.length
};
}
private determinePortfolioStrategy(analysis: any, constraints?: any): string {
if (constraints?.budget && analysis.total_investment > constraints.budget) {
return 'Selective high-ROI focus with phased investment approach';
}
if (analysis.risk_profile === 'high') {
return 'Risk-balanced portfolio with mix of safe and innovative projects';
}
if (analysis.average_roi > 150) {
return 'Aggressive growth strategy with parallel implementation';
}
return 'Balanced portfolio optimization for sustainable value creation';
}
private prioritizeProjects(projects: any[], strategy: string, constraints?: any): any[] {
return projects
.map(project => ({
project_id: project.project_id,
score: this.scoreProject(project, strategy, constraints),
metrics: {
roi: project.summary?.expected_roi || 0,
payback: project.summary?.payback_period_months || 24,
risk: project.risk_score || 0.5
}
}))
.sort((a, b) => b.score - a.score)
.map((item, index) => ({
project_id: item.project_id,
priority: index + 1,
rationale: this.generatePriorityRationale(item, strategy)
}));
}
private scoreProject(project: any, strategy: string, constraints?: any): number {
let score = 0;
// ROI component
score += (project.summary?.expected_roi || 0) / 200 * 0.3;
// Payback component (inverse - faster is better)
score += (1 - Math.min(project.summary?.payback_period_months || 24, 36) / 36) * 0.3;
// Risk component (inverse - lower is better)
score += (1 - (project.risk_score || 0.5)) * 0.2;
// Strategic alignment
if (strategy.includes('high-ROI')) {
score += (project.summary?.expected_roi || 0) > 150 ? 0.2 : 0;
}
// Constraint compliance
if (constraints?.budget) {
score += (project.summary?.total_investment || 0) <= constraints.budget / 3 ? 0.1 : -0.1;
}
return Math.max(0, Math.min(1, score));
}
private generatePriorityRationale(item: any, strategy: string): string {
const factors = [];
if (item.metrics.roi > 150) {
factors.push(`exceptional ROI of ${item.metrics.roi}%`);
}
if (item.metrics.payback < 12) {
factors.push(`rapid ${item.metrics.payback}-month payback`);
}
if (item.metrics.risk < 0.3) {
factors.push('low risk profile');
}
return `Selected due to ${factors.join(', ')} aligning with ${strategy}`;
}
private identifySynergies(projects: any[]): any[] {
const synergies = [];
// Technology synergies
for (let i = 0; i < projects.length - 1; i++) {
for (let j = i + 1; j < projects.length; j++) {
const commonTech = this.findCommonTechnologies(projects[i], projects[j]);
if (commonTech.length > 0) {
synergies.push({
projects: [projects[i].project_id, projects[j].project_id],
synergy_type: 'technology',
value_add: `Shared ${commonTech.join(', ')} reduces implementation cost by 20%`
});
}
}
}
// Use case synergies
const useCaseGroups = this.groupByUseCase(projects);
Object.entries(useCaseGroups).forEach(([category, projectList]) => {
if (projectList.length > 1) {
synergies.push({
projects: projectList,
synergy_type: 'use_case',
value_add: `Common ${category} use cases enable shared learning and best practices`
});
}
});
return synergies;
}
private findCommonTechnologies(project1: any, project2: any): string[] {
// Simplified - would analyze actual technology stack
const tech1 = this.inferTechnologies(project1);
const tech2 = this.inferTechnologies(project2);
return tech1.filter(t => tech2.includes(t));
}
private inferTechnologies(project: any): string[] {
const technologies = [];
if (project.use_cases?.some((uc: any) => uc.category === 'analytics')) {
technologies.push('ML Platform');
}
if (project.use_cases?.some((uc: any) => uc.category === 'automation')) {
technologies.push('RPA Platform');
}
if (project.use_cases?.some((uc: any) => uc.category === 'customer_service')) {
technologies.push('Conversational AI');
}
return technologies;
}
private groupByUseCase(projects: any[]): Record<string, string[]> {
const groups: Record<string, string[]> = {};
projects.forEach(project => {
project.use_cases?.forEach((uc: any) => {
if (!groups[uc.category]) {
groups[uc.category] = [];
}
groups[uc.category].push(project.project_id);
});
});
return groups;
}
private optimizeResourceAllocation(
projects: any[],
priorities: any[],
constraints?: any
): Recommendation[] {
const recommendations = [];
// Resource pooling recommendation
if (projects.length > 3) {
recommendations.push({
id: this.generateRecommendationId(),
type: 'operational' as const,
priority: 'high' as const,
title: 'Create Shared AI Center of Excellence',
description: 'Centralize AI expertise to serve all projects efficiently',
rationale: 'Resource pooling reduces overall cost by 30% and improves quality',
expected_impact: {
metric: 'Resource Efficiency',
change: '+30% utilization',
confidence: 0.8
},
implementation: {
complexity: 'medium' as const,
timeline: '60 days',
prerequisites: ['Executive sponsorship', 'Budget allocation'],
resources_required: ['CoE lead', 'Core team of 5-7 experts']
},
success_criteria: [
'CoE operational within 60 days',
'All projects leveraging shared resources',
'Measurable efficiency gains'
]
});
}
// Phased implementation based on priorities
recommendations.push({
id: this.generateRecommendationId(),
type: 'tactical' as const,
priority: 'high' as const,
title: 'Implement Phased Resource Deployment',
description: `Start with top ${Math.min(2, priorities.length)} priority projects, then scale`,
rationale: 'Phased approach reduces risk and allows for learning integration',
expected_impact: {
metric: 'Implementation Success',
change: '+25% success rate',
confidence: 0.75
},
implementation: {
complexity: 'low' as const,
timeline: 'Immediate',
prerequisites: ['Priority alignment'],
resources_required: ['Project management']
},
success_criteria: [
'Phase 1 projects launched successfully',
'Lessons learned documented',
'Resource reallocation plan in place'
]
});
return recommendations;
}
private generateRecommendationId(): string {
return `rec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private inferResourcesFromOpportunity(opportunity: any): string[] {
const resources = ['Project team'];
if (opportunity.type === 'strategic') {
resources.push('Executive sponsor', 'Strategy consultant');
}
if (opportunity.type === 'efficiency') {
resources.push('Process analyst', 'Automation engineer');
}
if (opportunity.potentialValue > 500000) {
resources.push('Dedicated PMO');
}
return resources;
}
private identifyImpactMetric(template: any): string {
const metricMap: Record<string, string> = {
strategic: 'Strategic Value',
tactical: 'Operational Efficiency',
operational: 'Process Performance',
risk_mitigation: 'Risk Reduction',
opportunity: 'Value Creation'
};
return metricMap[template.type] || 'Business Impact';
}
private estimateImpactChange(template: any, projectData: any): string {
// Simplified impact estimation
if (template.priority === 'critical') {
return '+20-30% improvement';
} else if (template.priority === 'high') {
return '+10-20% improvement';
}
return '+5-10% improvement';
}
private assessImplementationComplexity(template: any, projectData: any): 'low' | 'medium' | 'high' {
const complexityFactors = {
use_case_count: projectData.use_cases?.length || 0,
investment_size: projectData.summary?.total_investment || 0,
timeline: projectData.timeline_months || 12
};
if (template.type === 'strategic' || complexityFactors.use_case_count > 5) {
return 'high';
} else if (template.type === 'tactical' || complexityFactors.investment_size > 500000) {
return 'medium';
}
return 'low';
}
private estimateTimeline(template: any, projectData: any): string {
const timelineMap: Record<string, string> = {
critical: '0-30 days',
high: '30-60 days',
medium: '60-90 days',
low: '90-120 days'
};
return timelineMap[template.priority] || '60-90 days';
}
private identifyPrerequisites(template: any, projectData: any): string[] {
const prerequisites = ['Stakeholder alignment'];
if (template.type === 'strategic') {
prerequisites.push('Executive sponsorship', 'Strategic plan approval');
}
if (template.priority === 'critical') {
prerequisites.push('Immediate resource allocation', 'Risk assessment complete');
}
if (projectData.summary?.total_investment > 1000000) {
prerequisites.push('Board approval', 'Detailed business case');
}
return prerequisites;
}
private identifyResources(template: any): string[] {
const resourceMap: Record<string, string[]> = {
strategic: ['Executive sponsor', 'Strategy team', 'Change management'],
tactical: ['Project manager', 'Implementation team', 'Subject matter experts'],
operational: ['Operations team', 'Process analysts', 'Training resources'],
risk_mitigation: ['Risk manager', 'Compliance team', 'Audit resources'],
opportunity: ['Innovation team', 'Business analysts', 'Technology experts']
};
return resourceMap[template.type] || ['Project team'];
}
private defineSuccessCriteria(template: any, projectData: any): string[] {
const criteria = [];
// Universal criteria
criteria.push('Measurable improvement in target metrics');
// Type-specific criteria
if (template.type === 'strategic') {
criteria.push('Strategic objectives achieved', 'Long-term value creation demonstrated');
} else if (template.type === 'risk_mitigation') {
criteria.push('Risk indicators within acceptable range', 'No materialized risks');
}
// Priority-specific criteria
if (template.priority === 'critical') {
criteria.push('Completed within aggressive timeline', 'Zero critical issues');
}
return criteria.slice(0, 3);
}
}
// Export singleton instance
export const recommendationEngine = new RecommendationEngine();