T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/lavocat.ca/public_html/src/lib/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/public_html/src/lib/ai-assignment-engine.ts
import { prisma } from './prisma';

interface CaseComplexity {
  score: number;
  factors: string[];
  urgency: 'low' | 'medium' | 'high' | 'critical';
  estimatedHours: number;
}

interface LawyerCapacity {
  userId: string;
  currentCaseload: number;
  specializations: string[];
  successRate: number;
  availableHours: number;
  preferredCaseTypes: string[];
}

interface AssignmentRecommendation {
  userId: string;
  confidence: number;
  reasoning: string[];
  role: 'primary_lawyer' | 'assistant_lawyer' | 'secretary';
  estimatedStartDate: Date;
}

export class AIAssignmentEngine {
  
  /**
   * Analyze case complexity using AI factors
   */
  static analyzeCaseComplexity(registration: any): CaseComplexity {
    let score = 0;
    const factors: string[] = [];
    
    // Urgency indicators
    const urgentKeywords = ['urgent', 'court date', 'deadline', 'appeal', 'bail', 'hearing'];
    const hasUrgency = urgentKeywords.some(keyword => 
      registration.urgentNeeds?.toLowerCase().includes(keyword) ||
      registration.message?.toLowerCase().includes(keyword)
    );
    
    if (hasUrgency) {
      score += 30;
      factors.push('Time-sensitive case requiring immediate attention');
    }
    
    // Case type complexity
    const complexCaseTypes = ['wrongful conviction', 'appeal', 'class action', 'federal'];
    const isComplex = complexCaseTypes.some(type =>
      registration.message?.toLowerCase().includes(type) ||
      registration.reasonForJoining?.toLowerCase().includes(type)
    );
    
    if (isComplex) {
      score += 40;
      factors.push('Complex legal matter requiring specialized expertise');
    }
    
    // Document volume
    const documentCount = registration.documents?.length || 0;
    if (documentCount > 5) {
      score += 20;
      factors.push('High document volume requiring thorough review');
    }
    
    // Facility type (some are more challenging)
    const challengingFacilities = ['bordeaux', 'leclerc']; // Federal facilities
    if (challengingFacilities.includes(registration.detaineeInfo?.facility)) {
      score += 15;
      factors.push('High-security facility with additional procedural requirements');
    }
    
    // Language requirements
    if (registration.preferredLanguage !== 'French') {
      score += 10;
      factors.push('Bilingual communication requirements');
    }
    
    // Determine urgency and hours
    let urgency: 'low' | 'medium' | 'high' | 'critical' = 'low';
    let estimatedHours = 20; // Base hours
    
    if (score >= 70) {
      urgency = 'critical';
      estimatedHours = 80;
    } else if (score >= 50) {
      urgency = 'high';
      estimatedHours = 60;
    } else if (score >= 30) {
      urgency = 'medium';
      estimatedHours = 40;
    }
    
    return {
      score,
      factors,
      urgency,
      estimatedHours
    };
  }
  
  /**
   * Calculate lawyer capacity and expertise
   */
  static async calculateLawyerCapacity(userId: string): Promise<LawyerCapacity> {
    const user = await prisma.user.findUnique({
      where: { id: userId },
      include: {
        caseAssignments: {
          where: { isActive: true },
          include: {
            registration: true
          }
        }
      }
    });
    
    if (!user) throw new Error('User not found');
    
    const currentCaseload = user.caseAssignments.length;
    
    // Calculate success rate based on completed cases
    const completedCases = await prisma.caseAssignment.count({
      where: {
        userId,
        isActive: false,
        registration: {
          status: 'APPROVED'
        }
      }
    });
    
    const totalCases = await prisma.caseAssignment.count({
      where: { userId }
    });
    
    const successRate = totalCases > 0 ? (completedCases / totalCases) * 100 : 50;
    
    // Estimate available hours (max 40 hours per week, 20 hours per complex case)
    const maxWeeklyHours = 40;
    const estimatedCurrentHours = currentCaseload * 20;
    const availableHours = Math.max(0, maxWeeklyHours - estimatedCurrentHours);
    
    return {
      userId,
      currentCaseload,
      specializations: user.specialization ? [user.specialization] : [],
      successRate,
      availableHours,
      preferredCaseTypes: [] // Could be enhanced with user preferences
    };
  }
  
  /**
   * Generate AI-powered assignment recommendations
   */
  static async generateRecommendations(
    registrationId: string
  ): Promise<AssignmentRecommendation[]> {
    const registration = await prisma.registration.findUnique({
      where: { id: registrationId },
      include: {
        documents: true,
        detaineeInfo: true
      }
    });
    
    if (!registration) throw new Error('Registration not found');
    
    // Analyze case complexity
    const complexity = this.analyzeCaseComplexity(registration);
    
    // Get all eligible lawyers
    const lawyers = await prisma.user.findMany({
      where: {
        role: { in: ['LAWYER', 'ADMIN', 'SUPERADMIN', 'SUPERADMIN'] }
      }
    });
    
    const recommendations: AssignmentRecommendation[] = [];
    
    for (const lawyer of lawyers) {
      const capacity = await this.calculateLawyerCapacity(lawyer.id);
      
      // Calculate confidence score
      let confidence = 50; // Base confidence
      const reasoning: string[] = [];
      
      // Availability factor
      if (capacity.availableHours >= complexity.estimatedHours) {
        confidence += 30;
        reasoning.push(`Has ${capacity.availableHours} available hours for ${complexity.estimatedHours}h case`);
      } else if (capacity.availableHours > 0) {
        confidence += 10;
        reasoning.push(`Limited availability: ${capacity.availableHours}h available`);
      } else {
        confidence -= 20;
        reasoning.push('Currently at capacity with existing caseload');
      }
      
      // Experience factor
      if (capacity.successRate > 80) {
        confidence += 20;
        reasoning.push(`High success rate: ${capacity.successRate.toFixed(1)}%`);
      } else if (capacity.successRate > 60) {
        confidence += 10;
        reasoning.push(`Good success rate: ${capacity.successRate.toFixed(1)}%`);
      }
      
      // Specialization match
      const hasRelevantSpecialization = capacity.specializations.some(spec =>
        registration.message?.toLowerCase().includes(spec.toLowerCase()) ||
        registration.reasonForJoining?.toLowerCase().includes(spec.toLowerCase())
      );
      
      if (hasRelevantSpecialization) {
        confidence += 25;
        reasoning.push('Specialization matches case requirements');
      }
      
      // Workload balance
      if (capacity.currentCaseload <= 3) {
        confidence += 15;
        reasoning.push('Optimal caseload for quality attention');
      } else if (capacity.currentCaseload <= 5) {
        confidence += 5;
        reasoning.push('Manageable caseload');
      } else {
        confidence -= 10;
        reasoning.push('Heavy caseload may impact attention');
      }
      
      // Language compatibility
      if (lawyer.name && registration.preferredLanguage === 'French') {
        // Assume French names indicate French speakers (could be enhanced)
        const frenchNames = ['marie', 'jean', 'pierre', 'sophie', 'isabelle'];
        const isFrenchSpeaker = frenchNames.some(name => 
          lawyer.name!.toLowerCase().includes(name)
        );
        if (isFrenchSpeaker) {
          confidence += 10;
          reasoning.push('Language compatibility with client preference');
        }
      }
      
      // Urgency handling
      if (complexity.urgency === 'critical' && capacity.availableHours > 20) {
        confidence += 15;
        reasoning.push('Available for urgent case handling');
      }
      
      // Determine role recommendation
      let role: 'primary_lawyer' | 'assistant_lawyer' | 'secretary' = 'primary_lawyer';
      if (capacity.currentCaseload > 5 || complexity.score < 30) {
        role = 'assistant_lawyer';
        reasoning.push('Recommended as supporting attorney');
      }
      
      // Estimate start date
      const estimatedStartDate = new Date();
      if (capacity.availableHours < 10) {
        estimatedStartDate.setDate(estimatedStartDate.getDate() + 7); // Next week
      }
      
      recommendations.push({
        userId: lawyer.id,
        confidence: Math.min(100, Math.max(0, confidence)),
        reasoning,
        role,
        estimatedStartDate
      });
    }
    
    // Sort by confidence score
    return recommendations.sort((a, b) => b.confidence - a.confidence);
  }
  
  /**
   * Auto-assign optimal team based on AI recommendations
   */
  static async autoAssignOptimalTeam(
    registrationId: string,
    assignedBy: string
  ): Promise<any[]> {
    const recommendations = await this.generateRecommendations(registrationId);
    const complexity = await this.analyzeCaseComplexity(
      await prisma.registration.findUnique({
        where: { id: registrationId },
        include: { documents: true, detaineeInfo: true }
      })
    );
    
    const assignments = [];
    
    // Assign primary lawyer (highest confidence)
    if (recommendations.length > 0) {
      const primaryLawyer = recommendations[0];
      assignments.push(
        await prisma.caseAssignment.create({
          data: {
            registrationId,
            userId: primaryLawyer.userId,
            role: 'primary_lawyer',
            assignedBy
          }
        })
      );
    }
    
    // For complex cases, assign assistant
    if (complexity.score >= 50 && recommendations.length > 1) {
      const assistantLawyer = recommendations[1];
      assignments.push(
        await prisma.caseAssignment.create({
          data: {
            registrationId,
            userId: assistantLawyer.userId,
            role: 'assistant_lawyer',
            assignedBy
          }
        })
      );
    }
    
    // For very complex cases, assign secretary
    if (complexity.score >= 70) {
      const secretaries = await prisma.user.findMany({
        where: { role: { in: ['SECRETARY', 'ASSISTANT'] } }
      });
      
      if (secretaries.length > 0) {
        assignments.push(
          await prisma.caseAssignment.create({
            data: {
              registrationId,
              userId: secretaries[0].id,
              role: 'secretary',
              assignedBy
            }
          })
        );
      }
    }
    
    return assignments;
  }
} 

CasperSecurity Mini