Skip to main content
Winnerr’s AI lead scoring system uses advanced machine learning algorithms to automatically qualify and prioritize leads based on behavioral data, market conditions, and real estate-specific indicators, helping agents focus on the most promising opportunities.

Lead Scoring Capabilities

Predictive Analytics

ML models trained on real estate conversion data to predict deal success

Behavioral Analysis

Real-time scoring based on website activity, email engagement, and interactions

Market Intelligence

Integration with market data and economic indicators for context-aware scoring

Continuous Learning

Models that improve over time with feedback and successful deal outcomes

AI Scoring Architecture

Machine Learning Pipeline

Enhanced Lead Scoring Engine

// lib/ai/enhanced-lead-scoring.ts
export class EnhancedLeadScoringEngine {
  private models: MLModelEnsemble;
  private featureExtractor: FeatureExtractor;
  private marketDataService: MarketDataService;
  
  constructor() {
    this.models = new MLModelEnsemble([
      new XGBoostModel(),
      new RandomForestModel(),
      new NeuralNetworkModel()
    ]);
    this.featureExtractor = new FeatureExtractor();
    this.marketDataService = new MarketDataService();
  }
  
  async calculateEnhancedScore(
    personId: string,
    organizationId: string
  ): Promise<EnhancedLeadScore> {
    try {
      // Gather comprehensive data
      const person = await this.getPersonWithRelations(personId, organizationId);
      const behavioralData = await this.getBehavioralData(personId);
      const marketContext = await this.getMarketContext(person);
      const historicalPerformance = await this.getHistoricalPerformance(organizationId);
      
      // Extract features for ML models
      const features = await this.featureExtractor.extractFeatures({
        person,
        behavioralData,
        marketContext,
        historicalPerformance
      });
      
      // Get predictions from ensemble
      const predictions = await this.models.predict(features);
      
      // Calculate final score with interpretability
      const score = this.calculateWeightedScore(predictions, features);
      
      // Generate insights and recommendations
      const insights = await this.generateInsights(score, features, predictions);
      
      // Store scoring result for feedback loop
      await this.storeScoreResult(personId, score);
      
      return {
        personId,
        totalScore: score.overall,
        subscores: score.components,
        confidence: score.confidence,
        factors: score.factors,
        insights: insights,
        recommendations: score.recommendations,
        lastUpdated: new Date(),
        validUntil: this.calculateValidityPeriod(features)
      };
      
    } catch (error) {
      log.error('Enhanced lead scoring failed', { 
        personId, 
        error: parseError(error) 
      });
      throw error;
    }
  }
  
  private async extractFeatures(data: LeadScoringData): Promise<FeatureVector> {
    const features: FeatureVector = {
      // Demographic Features
      demographic: {
        location_quality: this.calculateLocationQuality(data.person.city, data.person.state),
        property_preference_alignment: this.calculatePropertyAlignment(data.person, data.marketContext),
        timeline_urgency: this.extractTimelineUrgency(data.person.notes, data.behavioralData),
        budget_qualification: this.assessBudgetQualification(data.person, data.marketContext)
      },
      
      // Behavioral Features
      behavioral: {
        email_engagement_rate: this.calculateEmailEngagement(data.behavioralData.emailActivity),
        website_activity_score: this.calculateWebsiteActivity(data.behavioralData.websiteActivity),
        response_rate: this.calculateResponseRate(data.behavioralData.communications),
        property_interest_depth: this.calculatePropertyInterest(data.behavioralData.propertyViews),
        search_frequency: this.calculateSearchFrequency(data.behavioralData.searches),
        content_consumption: this.calculateContentConsumption(data.behavioralData.contentViews)
      },
      
      // Financial Features
      financial: {
        preapproval_status: data.person.preapprovalStatus || 0,
        stated_budget_realism: this.assessBudgetRealism(data.person.budget, data.marketContext),
        financing_readiness: this.assessFinancingReadiness(data.person, data.behavioralData),
        investment_indicators: this.detectInvestmentIndicators(data.person, data.behavioralData)
      },
      
      // Communication Features
      communication: {
        sentiment_trend: this.calculateSentimentTrend(data.behavioralData.communications),
        communication_preference_fit: this.assessCommunicationFit(data.person, data.behavioralData),
        responsiveness_score: this.calculateResponsiveness(data.behavioralData.communications),
        objection_patterns: this.analyzeObjectionPatterns(data.behavioralData.communications)
      },
      
      // Market Context Features
      market: {
        market_momentum: data.marketContext.momentum,
        inventory_pressure: data.marketContext.inventory,
        seasonal_factor: this.calculateSeasonalFactor(new Date()),
        competition_level: data.marketContext.competition,
        price_trend_favorability: data.marketContext.priceTrends
      },
      
      // Source Quality Features
      source: {
        lead_source_quality: this.getSourceQuality(data.person.source, data.historicalPerformance),
        referral_quality: this.assessReferralQuality(data.person),
        attribution_confidence: this.calculateAttributionConfidence(data.person),
        channel_performance: this.getChannelPerformance(data.person.source, data.historicalPerformance)
      },
      
      // Temporal Features
      temporal: {
        recency_score: this.calculateRecencyScore(data.person.lastContactAt),
        momentum_score: this.calculateMomentumScore(data.behavioralData),
        lifecycle_stage: this.determineLifecycleStage(data.person, data.behavioralData),
        decay_factor: this.calculateDecayFactor(data.person.createdAt, data.person.lastContactAt)
      }
    };
    
    return features;
  }
  
  private calculateWeightedScore(
    predictions: ModelPredictions,
    features: FeatureVector
  ): ScoringResult {
    // Ensemble weights based on model performance
    const weights = {
      xgboost: 0.4,      // Best for tabular data
      randomForest: 0.35, // Good for feature importance
      neuralNetwork: 0.25 // Captures complex interactions
    };
    
    // Calculate weighted prediction
    const weightedScore = (
      predictions.xgboost * weights.xgboost +
      predictions.randomForest * weights.randomForest +
      predictions.neuralNetwork * weights.neuralNetwork
    );
    
    // Apply business logic adjustments
    const adjustedScore = this.applyBusinessRules(weightedScore, features);
    
    // Calculate component scores
    const componentScores = {
      behavioral: this.calculateBehavioralScore(features.behavioral),
      demographic: this.calculateDemographicScore(features.demographic),
      financial: this.calculateFinancialScore(features.financial),
      communication: this.calculateCommunicationScore(features.communication),
      market: this.calculateMarketScore(features.market),
      source: this.calculateSourceScore(features.source),
      temporal: this.calculateTemporalScore(features.temporal)
    };
    
    // Calculate confidence based on data quality
    const confidence = this.calculateConfidence(features, predictions);
    
    // Generate factor explanations
    const factors = this.generateFactorExplanations(features, componentScores);
    
    // Generate recommendations
    const recommendations = this.generateRecommendations(adjustedScore, componentScores, features);
    
    return {
      overall: Math.min(100, Math.max(0, adjustedScore)),
      components: componentScores,
      confidence,
      factors,
      recommendations
    };
  }
  
  private applyBusinessRules(score: number, features: FeatureVector): number {
    let adjustedScore = score;
    
    // Boost for high-value indicators
    if (features.financial.stated_budget_realism > 0.8 && features.behavioral.property_interest_depth > 0.7) {
      adjustedScore *= 1.1; // 10% boost for qualified, engaged leads
    }
    
    // Penalty for stale leads
    if (features.temporal.recency_score < 0.3) {
      adjustedScore *= 0.8; // 20% penalty for stale leads
    }
    
    // Boost for referrals from high-performing sources
    if (features.source.referral_quality > 0.8) {
      adjustedScore *= 1.05; // 5% boost for quality referrals
    }
    
    // Market condition adjustments
    if (features.market.market_momentum > 0.7) {
      adjustedScore *= 1.03; // Small boost in hot markets
    }
    
    // Communication quality boost
    if (features.communication.sentiment_trend > 0.6 && features.communication.responsiveness_score > 0.7) {
      adjustedScore *= 1.07; // Boost for positive, responsive leads
    }
    
    return adjustedScore;
  }
  
  private generateInsights(
    score: ScoringResult,
    features: FeatureVector,
    predictions: ModelPredictions
  ): LeadScoringInsight[] {
    const insights: LeadScoringInsight[] = [];
    
    // High-value opportunity detection
    if (score.overall > 80) {
      insights.push({
        type: 'HIGH_VALUE_OPPORTUNITY',
        priority: 'HIGH',
        title: 'High-Value Lead Detected',
        description: 'This lead shows strong conversion potential across multiple indicators.',
        action: 'Prioritize immediate outreach with personalized approach.',
        impact: 'REVENUE'
      });
    }
    
    // Behavioral insights
    if (features.behavioral.website_activity_score > 0.8) {
      insights.push({
        type: 'HIGH_ENGAGEMENT',
        priority: 'MEDIUM',
        title: 'Highly Engaged Prospect',
        description: 'Lead shows high website activity and content consumption.',
        action: 'Share relevant property listings and market insights.',
        impact: 'ENGAGEMENT'
      });
    }
    
    // Financial readiness insights
    if (features.financial.financing_readiness < 0.4) {
      insights.push({
        type: 'FINANCING_CONCERN',
        priority: 'MEDIUM',
        title: 'Potential Financing Issues',
        description: 'Lead may need assistance with financing preparation.',
        action: 'Provide financing resources and lender recommendations.',
        impact: 'QUALIFICATION'
      });
    }
    
    // Communication insights
    if (features.communication.responsiveness_score < 0.3) {
      insights.push({
        type: 'LOW_RESPONSIVENESS',
        priority: 'LOW',
        title: 'Communication Challenge',
        description: 'Lead has been less responsive to outreach attempts.',
        action: 'Try different communication channels or timing.',
        impact: 'COMMUNICATION'
      });
    }
    
    // Market timing insights
    if (features.market.seasonal_factor > 0.8 && features.temporal.momentum_score > 0.7) {
      insights.push({
        type: 'OPTIMAL_TIMING',
        priority: 'HIGH',
        title: 'Optimal Market Timing',
        description: 'Market conditions and lead momentum align for action.',
        action: 'Accelerate deal progression and scheduling.',
        impact: 'TIMING'
      });
    }
    
    return insights;
  }
}

interface EnhancedLeadScore {
  personId: string;
  totalScore: number;
  subscores: ComponentScores;
  confidence: number;
  factors: ScoringFactor[];
  insights: LeadScoringInsight[];
  recommendations: Recommendation[];
  lastUpdated: Date;
  validUntil: Date;
}

interface ComponentScores {
  behavioral: number;
  demographic: number;
  financial: number;
  communication: number;
  market: number;
  source: number;
  temporal: number;
}

interface ScoringFactor {
  category: string;
  factor: string;
  impact: 'POSITIVE' | 'NEGATIVE' | 'NEUTRAL';
  weight: number;
  description: string;
}

interface LeadScoringInsight {
  type: string;
  priority: 'HIGH' | 'MEDIUM' | 'LOW';
  title: string;
  description: string;
  action: string;
  impact: 'REVENUE' | 'ENGAGEMENT' | 'QUALIFICATION' | 'COMMUNICATION' | 'TIMING';
}

Real-time Scoring Updates

Behavioral Tracking System

// lib/ai/behavioral-tracking.ts
export class BehavioralTrackingService {
  private scoringQueue: Queue<ScoringTask>;
  private eventProcessor: EventProcessor;
  
  constructor() {
    this.scoringQueue = new Queue('lead-scoring-updates');
    this.eventProcessor = new EventProcessor();
    this.setupEventListeners();
  }
  
  private setupEventListeners(): void {
    // Website activity tracking
    this.eventProcessor.on('page_view', async (event: PageViewEvent) => {
      await this.processPageView(event);
    });
    
    // Email engagement tracking
    this.eventProcessor.on('email_opened', async (event: EmailEvent) => {
      await this.processEmailEngagement(event, 'OPENED');
    });
    
    this.eventProcessor.on('email_clicked', async (event: EmailEvent) => {
      await this.processEmailEngagement(event, 'CLICKED');
    });
    
    // Communication interactions
    this.eventProcessor.on('call_completed', async (event: CallEvent) => {
      await this.processCallInteraction(event);
    });
    
    this.eventProcessor.on('sms_responded', async (event: SMSEvent) => {
      await this.processSMSResponse(event);
    });
    
    // Property interactions
    this.eventProcessor.on('property_viewed', async (event: PropertyEvent) => {
      await this.processPropertyInteraction(event);
    });
    
    this.eventProcessor.on('property_favorited', async (event: PropertyEvent) => {
      await this.processPropertyFavorite(event);
    });
    
    // Search behavior
    this.eventProcessor.on('search_performed', async (event: SearchEvent) => {
      await this.processSearchBehavior(event);
    });
  }
  
  private async processPageView(event: PageViewEvent): Promise<void> {
    const person = await this.getPersonByEmail(event.email);
    if (!person) return;
    
    // Update behavioral metrics
    await this.updateBehavioralMetric(person.id, 'website_activity', {
      pageType: event.pageType,
      timeOnPage: event.duration,
      timestamp: event.timestamp,
      referrer: event.referrer
    });
    
    // Queue score recalculation if significant activity
    if (this.isSignificantActivity(event)) {
      await this.queueScoreUpdate(person.id, 'BEHAVIORAL_CHANGE');
    }
  }
  
  private async processEmailEngagement(
    event: EmailEvent, 
    action: 'OPENED' | 'CLICKED'
  ): Promise<void> {
    const person = await database.person.findUnique({
      where: { id: event.personId }
    });
    
    if (!person) return;
    
    // Calculate engagement score impact
    const impactWeight = action === 'CLICKED' ? 2.0 : 1.0;
    const timeDecay = this.calculateTimeDecay(event.timestamp);
    const engagementImpact = impactWeight * timeDecay;
    
    // Update engagement metrics
    await this.updateBehavioralMetric(person.id, 'email_engagement', {
      action,
      impactScore: engagementImpact,
      campaignId: event.campaignId,
      timestamp: event.timestamp
    });
    
    // Immediate score boost for email clicks
    if (action === 'CLICKED') {
      await this.applyImmediateScoreBoost(person.id, 5, 'EMAIL_CLICK');
    }
    
    await this.queueScoreUpdate(person.id, 'EMAIL_ENGAGEMENT');
  }
  
  private async processCallInteraction(event: CallEvent): Promise<void> {
    const person = await database.person.findUnique({
      where: { id: event.personId },
      include: { communications: { take: 5, orderBy: { createdAt: 'desc' } } }
    });
    
    if (!person) return;
    
    // Analyze call quality metrics
    const callQualityScore = this.calculateCallQualityScore({
      duration: event.duration,
      sentiment: event.sentiment,
      clientParticipation: event.clientTalkRatio,
      outcome: event.outcome
    });
    
    // Update communication metrics
    await this.updateBehavioralMetric(person.id, 'call_interaction', {
      duration: event.duration,
      qualityScore: callQualityScore,
      sentiment: event.sentiment,
      outcome: event.outcome,
      timestamp: event.timestamp
    });
    
    // Significant score impact for successful calls
    if (callQualityScore > 0.7) {
      await this.applyImmediateScoreBoost(person.id, 10, 'SUCCESSFUL_CALL');
    }
    
    await this.queueScoreUpdate(person.id, 'CALL_INTERACTION');
  }
  
  private async processPropertyInteraction(event: PropertyEvent): Promise<void> {
    const person = await this.getPersonByIdentifier(event.identifier);
    if (!person) return;
    
    // Analyze property interest depth
    const interestDepth = this.calculatePropertyInterestDepth({
      viewDuration: event.duration,
      galleryViews: event.galleryViews,
      documentViews: event.documentViews,
      mapInteraction: event.mapInteraction,
      priceRange: event.property.price,
      propertyType: event.property.type
    });
    
    // Update property interest metrics
    await this.updateBehavioralMetric(person.id, 'property_interest', {
      propertyId: event.propertyId,
      interestDepth,
      pricePoint: event.property.price,
      propertyType: event.property.type,
      timestamp: event.timestamp
    });
    
    // Boost score for properties in their stated price range
    if (this.isInPriceRange(event.property.price, person.budget)) {
      await this.applyImmediateScoreBoost(person.id, 3, 'RELEVANT_PROPERTY_VIEW');
    }
    
    await this.queueScoreUpdate(person.id, 'PROPERTY_INTERACTION');
  }
  
  private async queueScoreUpdate(
    personId: string, 
    trigger: string
  ): Promise<void> {
    await this.scoringQueue.add('update-lead-score', {
      personId,
      trigger,
      timestamp: new Date(),
      priority: this.getUpdatePriority(trigger)
    });
  }
  
  private async applyImmediateScoreBoost(
    personId: string, 
    boost: number, 
    reason: string
  ): Promise<void> {
    await database.person.update({
      where: { id: personId },
      data: {
        leadScore: {
          increment: boost
        },
        lastContactAt: new Date()
      }
    });
    
    // Broadcast real-time update
    await this.broadcastScoreUpdate(personId, boost, reason);
  }
}

Lead Scoring Dashboard

AI Insights Interface

// components/ai-lead-scoring-dashboard.tsx
export function AILeadScoringDashboard() {
  const [scoreFilter, setScoreFilter] = useState<'all' | 'hot' | 'warm' | 'cold'>('all');
  const [sortBy, setSortBy] = useState<'score' | 'activity' | 'potential'>('score');
  
  const { data: scoringData } = useQuery({
    queryKey: ['ai-lead-scoring', scoreFilter, sortBy],
    queryFn: () => fetch(`/api/ai/lead-scoring?filter=${scoreFilter}&sort=${sortBy}`)
      .then(res => res.json())
  });
  
  const { data: modelPerformance } = useQuery({
    queryKey: ['scoring-model-performance'],
    queryFn: () => fetch('/api/ai/scoring-performance').then(res => res.json())
  });
  
  return (
    <div className="space-y-6">
      {/* Model Performance Overview */}
      <Card>
        <CardHeader>
          <CardTitle className="flex items-center space-x-2">
            <Brain className="h-5 w-5" />
            <span>AI Model Performance</span>
          </CardTitle>
        </CardHeader>
        <CardContent>
          <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
            <div className="text-center">
              <p className="text-sm text-gray-500">Accuracy</p>
              <p className="text-2xl font-bold text-green-600">
                {(modelPerformance?.accuracy * 100 || 0).toFixed(1)}%
              </p>
            </div>
            <div className="text-center">
              <p className="text-sm text-gray-500">Precision</p>
              <p className="text-2xl font-bold text-blue-600">
                {(modelPerformance?.precision * 100 || 0).toFixed(1)}%
              </p>
            </div>
            <div className="text-center">
              <p className="text-sm text-gray-500">Recall</p>
              <p className="text-2xl font-bold text-purple-600">
                {(modelPerformance?.recall * 100 || 0).toFixed(1)}%
              </p>
            </div>
            <div className="text-center">
              <p className="text-sm text-gray-500">Leads Scored</p>
              <p className="text-2xl font-bold text-orange-600">
                {modelPerformance?.totalScored?.toLocaleString() || 0}
              </p>
            </div>
          </div>
        </CardContent>
      </Card>
      
      {/* Scoring Controls */}
      <div className="flex items-center justify-between">
        <div className="flex space-x-4">
          <Select value={scoreFilter} onValueChange={(value: unknown) => setScoreFilter(value)}>
            <SelectTrigger className="w-32">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All Leads</SelectItem>
              <SelectItem value="hot">Hot (80-100)</SelectItem>
              <SelectItem value="warm">Warm (60-79)</SelectItem>
              <SelectItem value="cold">Cold (0-59)</SelectItem>
            </SelectContent>
          </Select>
          
          <Select value={sortBy} onValueChange={(value: unknown) => setSortBy(value)}>
            <SelectTrigger className="w-40">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="score">Lead Score</SelectItem>
              <SelectItem value="activity">Recent Activity</SelectItem>
              <SelectItem value="potential">Revenue Potential</SelectItem>
            </SelectContent>
          </Select>
        </div>
        
        <Button onClick={() => window.location.reload()}>
          <RefreshCw className="h-4 w-4 mr-2" />
          Refresh Scores
        </Button>
      </div>
      
      {/* Lead Scoring Grid */}
      <div className="grid grid-cols-1 gap-4">
        {scoringData?.leads?.map((lead: unknown) => (
          <Card key={lead.id} className="hover:shadow-md transition-shadow">
            <CardContent className="pt-4">
              <div className="flex items-start justify-between">
                <div className="flex-grow">
                  <div className="flex items-center space-x-3 mb-3">
                    <Avatar className="h-10 w-10">
                      <AvatarFallback>
                        {lead.firstName?.[0]}{lead.lastName?.[0]}
                      </AvatarFallback>
                    </Avatar>
                    <div>
                      <h3 className="font-semibold">
                        {lead.firstName} {lead.lastName}
                      </h3>
                      <p className="text-sm text-gray-500">
                        {lead.email} • {lead.phone}
                      </p>
                    </div>
                  </div>
                  
                  {/* AI Insights */}
                  {lead.insights?.length > 0 && (
                    <div className="mb-3">
                      <h4 className="text-sm font-medium mb-2">AI Insights</h4>
                      <div className="space-y-1">
                        {lead.insights.slice(0, 2).map((insight: unknown, index: number) => (
                          <div key={index} className="flex items-center text-xs">
                            <div className={`
                              w-2 h-2 rounded-full mr-2
                              ${insight.priority === 'HIGH' 
                                ? 'bg-red-500' 
                                : insight.priority === 'MEDIUM' 
                                  ? 'bg-yellow-500' 
                                  : 'bg-blue-500'
                              }
                            `} />
                            <span className="text-gray-600">{insight.title}</span>
                          </div>
                        ))}
                      </div>
                    </div>
                  )}
                  
                  {/* Score Components */}
                  <div className="grid grid-cols-3 gap-2 text-xs">
                    <div>
                      <p className="text-gray-500">Behavioral</p>
                      <p className="font-medium">{lead.subscores.behavioral}/100</p>
                    </div>
                    <div>
                      <p className="text-gray-500">Financial</p>
                      <p className="font-medium">{lead.subscores.financial}/100</p>
                    </div>
                    <div>
                      <p className="text-gray-500">Market</p>
                      <p className="font-medium">{lead.subscores.market}/100</p>
                    </div>
                  </div>
                </div>
                
                {/* Score Display */}
                <div className="text-center">
                  <div className="relative">
                    <CircularProgressbar
                      value={lead.totalScore}
                      text={`${lead.totalScore}`}
                      styles={buildStyles({
                        textSize: '24px',
                        pathColor: getScoreColor(lead.totalScore),
                        textColor: getScoreColor(lead.totalScore),
                        trailColor: '#e5e7eb'
                      })}
                      className="w-16 h-16"
                    />
                  </div>
                  <p className="text-xs text-gray-500 mt-1">
                    {lead.confidence}% confidence
                  </p>
                  
                  {/* Quick Actions */}
                  <div className="flex space-x-1 mt-2">
                    <Button size="sm" variant="outline" className="text-xs px-2 py-1">
                      <Phone className="h-3 w-3" />
                    </Button>
                    <Button size="sm" variant="outline" className="text-xs px-2 py-1">
                      <Mail className="h-3 w-3" />
                    </Button>
                    <Button size="sm" variant="outline" className="text-xs px-2 py-1">
                      <Calendar className="h-3 w-3" />
                    </Button>
                  </div>
                </div>
              </div>
              
              {/* Recommendations */}
              {lead.recommendations?.length > 0 && (
                <div className="mt-3 pt-3 border-t">
                  <p className="text-xs font-medium text-gray-700 mb-1">
                    💡 Recommended Actions:
                  </p>
                  <p className="text-xs text-gray-600">
                    {lead.recommendations[0].action}
                  </p>
                </div>
              )}
            </CardContent>
          </Card>
        ))}
      </div>
      
      {/* Scoring Analytics */}
      <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
        <Card>
          <CardHeader>
            <CardTitle>Score Distribution</CardTitle>
          </CardHeader>
          <CardContent>
            <ResponsiveContainer width="100%" height={200}>
              <BarChart data={scoringData?.scoreDistribution || []}>
                <CartesianGrid strokeDasharray="3 3" />
                <XAxis dataKey="range" />
                <YAxis />
                <Tooltip />
                <Bar dataKey="count" fill="#3b82f6" />
              </BarChart>
            </ResponsiveContainer>
          </CardContent>
        </Card>
        
        <Card>
          <CardHeader>
            <CardTitle>Feature Importance</CardTitle>
          </CardHeader>
          <CardContent>
            <div className="space-y-3">
              {modelPerformance?.featureImportance?.map((feature: unknown) => (
                <div key={feature.name} className="flex items-center justify-between">
                  <span className="text-sm">{feature.name}</span>
                  <div className="flex items-center space-x-2">
                    <div className="w-20 h-2 bg-gray-200 rounded">
                      <div 
                        className="h-2 bg-blue-500 rounded transition-all"
                        style={{ width: `${feature.importance * 100}%` }}
                      />
                    </div>
                    <span className="text-xs text-gray-500 w-10">
                      {(feature.importance * 100).toFixed(0)}%
                    </span>
                  </div>
                </div>
              ))}
            </div>
          </CardContent>
        </Card>
      </div>
    </div>
  );
}

const getScoreColor = (score: number): string => {
  if (score >= 80) return '#10b981'; // Green
  if (score >= 60) return '#f59e0b'; // Yellow
  return '#ef4444'; // Red
};

Model Training & Optimization

Continuous Learning Pipeline

// lib/ai/model-training.ts
export class ModelTrainingPipeline {
  private trainingScheduler: CronScheduler;
  private dataPreprocessor: DataPreprocessor;
  private modelValidator: ModelValidator;
  
  constructor() {
    this.trainingScheduler = new CronScheduler();
    this.dataPreprocessor = new DataPreprocessor();
    this.modelValidator = new ModelValidator();
    this.setupTrainingSchedule();
  }
  
  private setupTrainingSchedule(): void {
    // Retrain models weekly with new data
    this.trainingScheduler.schedule('0 2 * * 1', async () => {
      await this.performWeeklyRetraining();
    });
    
    // Quick model updates daily
    this.trainingScheduler.schedule('0 1 * * *', async () => {
      await this.performDailyModelUpdate();
    });
    
    // Real-time feedback incorporation
    this.trainingScheduler.schedule('0 */4 * * *', async () => {
      await this.incorporateFeedback();
    });
  }
  
  async performWeeklyRetraining(): Promise<void> {
    try {
      log.info('Starting weekly model retraining');
      
      // Gather new training data
      const trainingData = await this.gatherTrainingData();
      
      // Preprocess and validate data
      const processedData = await this.dataPreprocessor.process(trainingData);
      
      // Train new model versions
      const newModels = await this.trainModelEnsemble(processedData);
      
      // Validate model performance
      const validation = await this.modelValidator.validate(newModels, processedData);
      
      // Deploy if performance improves
      if (validation.performanceImproved) {
        await this.deployNewModels(newModels);
        log.info('New models deployed successfully', { 
          performance: validation.metrics 
        });
      } else {
        log.info('Model performance did not improve, keeping existing models');
      }
      
    } catch (error) {
      log.error('Weekly retraining failed', { error: parseError(error) });
    }
  }
  
  private async gatherTrainingData(): Promise<TrainingDataset> {
    const endDate = new Date();
    const startDate = new Date(endDate.getTime() - 30 * 24 * 60 * 60 * 1000); // Last 30 days
    
    // Gather positive examples (converted leads)
    const convertedLeads = await database.person.findMany({
      where: {
        deals: {
          some: {
            status: 'WON',
            actualCloseDate: {
              gte: startDate,
              lte: endDate
            }
          }
        }
      },
      include: {
        deals: true,
        communications: true,
        activities: true
      }
    });
    
    // Gather negative examples (leads that went cold)
    const coldLeads = await database.person.findMany({
      where: {
        status: 'CLOSED_LOST',
        updatedAt: {
          gte: startDate,
          lte: endDate
        }
      },
      include: {
        deals: true,
        communications: true,
        activities: true
      }
    });
    
    // Gather behavioral data
    const behavioralData = await this.gatherBehavioralData(
      [...convertedLeads, ...coldLeads].map(p => p.id)
    );
    
    return {
      positiveExamples: convertedLeads,
      negativeExamples: coldLeads,
      behavioralData,
      marketData: await this.gatherMarketData(startDate, endDate)
    };
  }
  
  private async incorporateFeedback(): Promise<void> {
    // Get recent agent feedback on scoring accuracy
    const feedback = await database.leadScoringFeedback.findMany({
      where: {
        processed: false,
        createdAt: {
          gte: new Date(Date.now() - 4 * 60 * 60 * 1000) // Last 4 hours
        }
      }
    });
    
    if (feedback.length === 0) return;
    
    // Process feedback for model improvement
    for (const item of feedback) {
      await this.processFeedbackItem(item);
    }
    
    // Mark feedback as processed
    await database.leadScoringFeedback.updateMany({
      where: {
        id: { in: feedback.map(f => f.id) }
      },
      data: { processed: true }
    });
    
    log.info('Incorporated lead scoring feedback', { 
      feedbackItems: feedback.length 
    });
  }
}

Next Steps

AI Assistant

Explore the AI-powered assistant and recommendations

Predictive Models

Learn about market prediction and forecasting models

Contact Management

See how AI scoring integrates with contact management

AI lead scoring transforms lead qualification from guesswork into data-driven science, helping agents focus their time on the most promising opportunities and maximize conversion rates.