feat: implement YAML-based configuration, .env support, and customizable prompt templates for AI analysis
This commit is contained in:
+45
-19
@@ -21,27 +21,36 @@ import (
|
||||
)
|
||||
|
||||
type WorkerPool struct {
|
||||
db *db.DB
|
||||
analyzer analyzer.LLMAnalyzer
|
||||
filterPipe *filter.FilterPipeline
|
||||
isRunning atomic.Bool
|
||||
workerCount int
|
||||
wg sync.WaitGroup
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
db *db.DB
|
||||
analyzer analyzer.LLMAnalyzer
|
||||
filterPipe *filter.FilterPipeline
|
||||
analysisThreshold float64
|
||||
isRunning atomic.Bool
|
||||
workerCount int
|
||||
wg sync.WaitGroup
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewWorkerPool(database *db.DB, analyzer analyzer.LLMAnalyzer, numWorkers int, filterCfg *config.FilterConfig) *WorkerPool {
|
||||
func NewWorkerPool(database *db.DB, analyzer analyzer.LLMAnalyzer, numWorkers int, threshold float64, filterCfg *config.FilterConfig) *WorkerPool {
|
||||
filterPipe := filter.NewPipeline(
|
||||
filter.NewHardKeywordFilter(filterCfg.HardKeywords),
|
||||
filter.NewScoringFilter(filterCfg.ScoringWeights),
|
||||
)
|
||||
|
||||
if threshold <= 0 {
|
||||
threshold = filterCfg.AnalysisThreshold
|
||||
}
|
||||
if threshold <= 0 {
|
||||
threshold = 25.0
|
||||
}
|
||||
|
||||
return &WorkerPool{
|
||||
db: database,
|
||||
analyzer: analyzer,
|
||||
filterPipe: filterPipe,
|
||||
workerCount: numWorkers,
|
||||
db: database,
|
||||
analyzer: analyzer,
|
||||
filterPipe: filterPipe,
|
||||
analysisThreshold: threshold,
|
||||
workerCount: numWorkers,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,15 +264,22 @@ func (p *WorkerPool) handleProcess(ctx context.Context, task *db.Task) error {
|
||||
|
||||
keep, score, reason := p.filterPipe.Execute(ctx, &job.RawJob)
|
||||
if !keep {
|
||||
// Create a rejected JobAnalysis record. Store reason in missing_highlights JSON array
|
||||
// Disqualified by blacklist: create a rejected record
|
||||
reasonJSON, _ := json.Marshal([]string{reason})
|
||||
_ = p.db.CreateJobAnalysisFull(payload.RawJobID, score, false, "[]", string(reasonJSON), "[]", "PARSED")
|
||||
_ = p.db.CreateJobAnalysisFull(payload.RawJobID, 0.0, 0.0, false, "Disqualified: "+reason, "[]", string(reasonJSON), "[]", "REJECTED")
|
||||
return nil
|
||||
}
|
||||
|
||||
// It's qualified for analysis. Create the base record and enqueue it.
|
||||
_ = p.db.CreateJobAnalysis(payload.RawJobID, score, true, "PENDING")
|
||||
|
||||
// Gating threshold check
|
||||
if score < p.analysisThreshold {
|
||||
summary := fmt.Sprintf("Keyword fit (%.0f) below threshold (%.0f)", score, p.analysisThreshold)
|
||||
_ = p.db.CreateJobAnalysisFull(payload.RawJobID, score, score, false, summary, "[]", "[]", "[]", "FILTERED_OUT")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Qualified for deep LLM analysis. Create the pending record and enqueue ANALYZE task.
|
||||
_ = p.db.CreateJobAnalysis(payload.RawJobID, score, score, true, "PENDING")
|
||||
|
||||
analyzePayload := AnalyzePayload(payload)
|
||||
_ = p.db.EnqueueTask("ANALYZE", analyzePayload)
|
||||
|
||||
@@ -281,9 +297,16 @@ func (p *WorkerPool) handleAnalyze(ctx context.Context, task *db.Task) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use empty matched/missing keywords for now, or pass from filter if stored
|
||||
result, err := p.analyzer.AnalyzeJD(ctx, job.Title, job.RawContent)
|
||||
if err != nil {
|
||||
logger.Log.Errorw("LLM analysis failed", "component", "Worker", "raw_job_id", payload.RawJobID, "error", err)
|
||||
filterScore := 0.0
|
||||
isQual := false
|
||||
if job.Analysis != nil {
|
||||
filterScore = job.Analysis.FilterScore
|
||||
isQual = job.Analysis.IsQualified
|
||||
}
|
||||
_ = p.db.UpdateJobAnalysisFull(payload.RawJobID, filterScore, filterScore, isQual, "Analysis error: "+err.Error(), "[]", "[]", "[]", "FAILED")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -293,6 +316,9 @@ func (p *WorkerPool) handleAnalyze(ctx context.Context, task *db.Task) error {
|
||||
|
||||
err = p.db.UpdateJobAnalysisLLM(
|
||||
payload.RawJobID,
|
||||
result.AIScore,
|
||||
result.IsQualified,
|
||||
result.Summary,
|
||||
string(matchedStr),
|
||||
string(missingStr),
|
||||
string(tailoringStr),
|
||||
|
||||
Reference in New Issue
Block a user