package cron import ( "database/sql" "encoding/json" "log" "os" "github.com/jobs-scraper/infrastructure/rabbitmq" "github.com/jobs-scraper/internal/domain" "github.com/jobs-scraper/internal/repo" "github.com/jobs-scraper/internal/services" ) type JobAnalyzer struct { db *sql.DB jobRepo *repo.JobRepository jobDescriptionRepo *repo.JobDescriptionRepository jobAnalysisResultRepo *repo.JobAnalysisResultRepository openRouterService services.OpenRouterService rmq *rabbitmq.RabbitMQClient } func NewJobAnalyzer(db *sql.DB) *JobAnalyzer { apiKey := os.Getenv("OPENROUTER_API_KEY") model := os.Getenv("CV_AI_MODEL") jobRepo := repo.NewJobRepository(db) jobDescriptionRepo := repo.NewJobDescriptionRepository(db) jobAnalysisResultRepo := repo.NewJobAnalysisResultRepository(db) openRouterService := services.NewOpenRouterService(model, apiKey) rmq, err := rabbitmq.NewRabbitMQClient() if err != nil { log.Printf("Warning: Failed to create RabbitMQ client: %v", err) } return &JobAnalyzer{ db: db, jobRepo: jobRepo, jobDescriptionRepo: jobDescriptionRepo, jobAnalysisResultRepo: jobAnalysisResultRepo, openRouterService: openRouterService, rmq: rmq, } } func (ja *JobAnalyzer) AnalyzeJobs() error { // Get jobs that need analysis (status = created) jobs, err := ja.jobRepo.GetJobsByStatus(domain.JobStatusCreated) if err != nil { return err } log.Printf("Found %d jobs to analyze", len(jobs)) // Read CV file cv, err := os.ReadFile("cv.txt") if err != nil { return err } for _, job := range jobs { if err := ja.analyzeJob(job, string(cv)); err != nil { log.Printf("Error analyzing job %d: %v", job.ID, err) // Update job status to error if updateErr := ja.jobRepo.UpdateJobStatus(job.ID, domain.JobStatusError); updateErr != nil { log.Printf("Error updating job status to error: %v", updateErr) } continue } // Update job status to analyzed if err := ja.jobRepo.UpdateJobStatus(job.ID, domain.JobStatusAnalyzed); err != nil { log.Printf("Error updating job status to analyzed: %v", err) } log.Printf("Successfully analyzed job %d", job.ID) } return nil } func (ja *JobAnalyzer) analyzeJob(job domain.Job, cv string) error { // Get job description jobDescription, jobCriteria, err := ja.jobDescriptionRepo.GetJobDescriptionByJobID(job.ID) if err != nil { return err } // Analyze job with CV result, err := ja.openRouterService.AnalyzeJobDescription(cv, domain.JobDescription{ JobID: job.ID, Description: jobDescription, Criteria: jobCriteria, }) if err != nil { return err } log.Printf("Analysis result for job %d: Recommendation=%s, Score=%d", job.ID, result.Recommendation, result.ConfidenceScore) // Save analysis result to database analysisResult := &domain.JobAnalysisResult{ JobID: job.ID, AnalysisResult: result.Summary, MatchScore: &result.ConfidenceScore, KeySkills: result.MatchingSkills, MissingSkills: result.MissingSkills, Recommendations: &result.Recommendation, } if err := ja.jobAnalysisResultRepo.SaveAnalysisResult(analysisResult); err != nil { log.Printf("Warning: Failed to save analysis result to database: %v", err) } else { log.Printf("Successfully saved analysis result for job %d to database", job.ID) } // Publish CV analysis message to RabbitMQ if available if ja.rmq != nil { message := rabbitmq.CvAnalyzeMessage{ JobID: job.ID, } if err := ja.publishCvAnalysisMessage(message); err != nil { log.Printf("Warning: Failed to publish CV analysis message: %v", err) } } return nil } func (ja *JobAnalyzer) publishCvAnalysisMessage(message rabbitmq.CvAnalyzeMessage) error { data, err := json.Marshal(message) if err != nil { return err } return ja.rmq.Publish(rabbitmq.CvAnalyzeQueue, rabbitmq.CvAnalyzeExchange, data) }