#!/usr/bin/env dotnet-script #r "nuget: Microsoft.EntityFrameworkCore.SqlServer, 8.0.0" #r "nuget: Microsoft.Extensions.Configuration.Json, 8.0.0" #r "nuget: Microsoft.Extensions.DependencyInjection, 8.0.0" #r "nuget: Microsoft.Extensions.Logging.Console, 8.0.0" #r "../src/RealCV.Application/bin/Debug/net8.0/RealCV.Application.dll" #r "../src/RealCV.Infrastructure/bin/Debug/net8.0/RealCV.Infrastructure.dll" #r "../src/RealCV.Domain/bin/Debug/net8.0/RealCV.Domain.dll" // This is a dotnet-script file. Run with: dotnet script batch-test-cvs.cs -- /path/to/cvs // Install dotnet-script: dotnet tool install -g dotnet-script using System; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Collections.Generic; using System.Text.Json; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using RealCV.Application.Interfaces; using RealCV.Application.Models; using RealCV.Infrastructure.Data; using RealCV.Infrastructure.Services; using RealCV.Infrastructure.ExternalApis; using RealCV.Infrastructure.Configuration; var folderPath = Args.FirstOrDefault() ?? "/tmp/test-cvs"; if (!Directory.Exists(folderPath)) { Console.WriteLine($"Error: Folder not found: {folderPath}"); Console.WriteLine("Usage: dotnet script batch-test-cvs.cs -- /path/to/cvs"); return 1; } Console.WriteLine($"Processing CVs from: {folderPath}"); Console.WriteLine(new string('=', 80)); // Setup DI var services = new ServiceCollection(); var configuration = new ConfigurationBuilder() .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../src/RealCV.Web")) .AddJsonFile("appsettings.json", optional: true) .AddJsonFile("appsettings.Development.json", optional: true) .Build(); services.AddLogging(b => b.AddConsole().SetMinimumLevel(LogLevel.Warning)); services.AddDbContextFactory(options => options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))); services.Configure(configuration.GetSection("CompaniesHouse")); services.Configure(configuration.GetSection("Anthropic")); services.AddHttpClient(); services.AddHttpClient(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); var provider = services.BuildServiceProvider(); var cvFiles = Directory.GetFiles(folderPath, "*.*") .Where(f => f.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".docx", StringComparison.OrdinalIgnoreCase)) .ToList(); Console.WriteLine($"Found {cvFiles.Count} CV files\n"); var allUnverifiedEmployers = new List(); var allUnverifiedInstitutions = new List(); var totalEmployers = 0; var verifiedEmployers = 0; var totalEducation = 0; var verifiedEducation = 0; foreach (var cvFile in cvFiles) { Console.WriteLine($"\n{'=',-80}"); Console.WriteLine($"FILE: {Path.GetFileName(cvFile)}"); Console.WriteLine($"{'=',-80}"); try { using var scope = provider.CreateScope(); var parser = scope.ServiceProvider.GetRequiredService(); var companyVerifier = scope.ServiceProvider.GetRequiredService(); var eduVerifier = scope.ServiceProvider.GetRequiredService(); await using var stream = File.OpenRead(cvFile); var cv = await parser.ParseAsync(stream, Path.GetFileName(cvFile)); Console.WriteLine($"Candidate: {cv.PersonalInfo?.FullName ?? "Unknown"}"); // Employers if (cv.Employment?.Count > 0) { Console.WriteLine($"\nEMPLOYERS ({cv.Employment.Count}):"); foreach (var emp in cv.Employment) { totalEmployers++; var result = await companyVerifier.VerifyCompanyAsync( emp.CompanyName, emp.StartDate, emp.EndDate, emp.JobTitle); var icon = result.IsVerified ? "✓" : "✗"; Console.WriteLine($" {icon} {emp.CompanyName}"); if (result.IsVerified) { verifiedEmployers++; Console.WriteLine($" → {result.MatchedCompanyName} ({result.MatchScore}%)"); if (!string.IsNullOrEmpty(result.VerificationNotes)) Console.WriteLine($" Note: {result.VerificationNotes}"); } else { allUnverifiedEmployers.Add(emp.CompanyName); Console.WriteLine($" Note: {result.VerificationNotes ?? "Not found"}"); } } } // Education if (cv.Education?.Count > 0) { Console.WriteLine($"\nEDUCATION ({cv.Education.Count}):"); var eduEntries = cv.Education.Select(e => new EducationEntry { Institution = e.Institution, Qualification = e.Qualification, Subject = e.Subject, StartDate = e.StartDate, EndDate = e.EndDate }).ToList(); var eduResults = eduVerifier.VerifyAll(eduEntries); foreach (var result in eduResults) { totalEducation++; var icon = result.IsVerified ? "✓" : "✗"; Console.WriteLine($" {icon} {result.ClaimedInstitution}"); Console.WriteLine($" {result.ClaimedQualification}"); if (result.IsVerified) { verifiedEducation++; if (result.MatchedInstitution != null && result.MatchedInstitution != result.ClaimedInstitution) Console.WriteLine($" → {result.MatchedInstitution}"); } else { allUnverifiedInstitutions.Add(result.ClaimedInstitution ?? "Unknown"); Console.WriteLine($" Status: {result.Status}"); if (!string.IsNullOrEmpty(result.VerificationNotes)) Console.WriteLine($" Note: {result.VerificationNotes}"); } } } } catch (Exception ex) { Console.WriteLine($"ERROR: {ex.Message}"); } } // Summary Console.WriteLine($"\n\n{'=',-80}"); Console.WriteLine("SUMMARY"); Console.WriteLine($"{'=',-80}"); Console.WriteLine($"CVs Processed: {cvFiles.Count}"); Console.WriteLine($"Employers: {verifiedEmployers}/{totalEmployers} verified ({(totalEmployers > 0 ? verifiedEmployers * 100 / totalEmployers : 0)}%)"); Console.WriteLine($"Education: {verifiedEducation}/{totalEducation} verified ({(totalEducation > 0 ? verifiedEducation * 100 / totalEducation : 0)}%)"); var uniqueUnverifiedEmployers = allUnverifiedEmployers.Distinct().OrderBy(x => x).ToList(); if (uniqueUnverifiedEmployers.Count > 0) { Console.WriteLine($"\nUNVERIFIED EMPLOYERS ({uniqueUnverifiedEmployers.Count}):"); foreach (var emp in uniqueUnverifiedEmployers) Console.WriteLine($" - {emp}"); } var uniqueUnverifiedInstitutions = allUnverifiedInstitutions.Distinct().OrderBy(x => x).ToList(); if (uniqueUnverifiedInstitutions.Count > 0) { Console.WriteLine($"\nUNVERIFIED INSTITUTIONS ({uniqueUnverifiedInstitutions.Count}):"); foreach (var inst in uniqueUnverifiedInstitutions) Console.WriteLine($" - {inst}"); } return 0;