Scoring & analysis

How reveilio scores resumes against job descriptions and what the result contains.

How scoring works

Reveilio performs resume extraction and scoring in a single LLM call. The prompt instructs the model to:

  1. Phase 1: Extract structured data from the resume (name, skills, experience, education, certifications, career gaps).
  2. Phase 2: Score the candidate against the JD using weighted criteria.

The model returns a single JSON document with both the extracted data and the analysis. This is faster and cheaper than making two separate calls, and produces more coherent results because the model reasons about the raw text and the scoring criteria simultaneously.

The seven scoring dimensions

Each dimension receives a score from 0 to 100, plus a written reasoning explaining the score. The weights are configurable via configure(weights=...).

DimensionDefault weightWhat it measures
skills20%Direct keyword match between JD required skills and resume skills.
semantic_skills20%Conceptual overlap. A candidate who knows Flask may score well for a Django role because the underlying concepts are similar.
experience25%Years of relevant experience, role progression, seniority alignment.
education15%Degree relevance, institution prestige, academic achievements.
certifications10%Professional certifications that match JD requirements.
soft_skills5%Communication, leadership, teamwork, and other interpersonal skills.
domain_relevance5%Industry-specific experience. A fintech role benefits from finance experience.

The AnalysisResult object

Every call to analyze_resume() or score() returns an AnalysisResult with these fields:

Core scores

FieldTypeDescription
overall_scorefloat0 to 100 weighted composite score.
confidence_levelstring"High", "Medium", or "Low". Reflects how confident the model is in its assessment.
recommendationstring"Shortlist", "Needs Review", or "Not Suitable".
detailed_scoresdictPer-dimension breakdown. Each key maps to {"score": 85, "reasoning": "..."}.

Qualitative analysis

FieldTypeDescription
ai_summarystringA concise executive critique, approximately 120 words. Written as an objective assessment.
strengthslistWhat the candidate does well relative to the JD. Concrete and specific.
weaknesseslistGaps between the candidate and the JD requirements.
career_flagslistPotential concerns such as frequent job changes, unexplained gaps, or misaligned career trajectory.
reasoninglistStep-by-step logic behind the overall score.
experience_analysislistDeep dive into how the candidate's work history aligns with the role.

Advanced metrics

FieldTypeDescription
kpislistKey performance indicators derived from the resume (e.g. "Led a team of 12", "Reduced latency by 40%").
relevancy_metricslistMetrics such as "Average Tenure per Company", with value, relevancy level (high/medium/low), reasoning, and criteria definitions.
suggested_roleslistAlternative roles the candidate might be a better fit for, each with a match score.
suggested_questionslist3 to 5 role-aligned interview questions. Only populated when recommendation is "Shortlist". Empty for "Needs Review" and "Not Suitable".

Extracted candidate data

FieldDescription
candidate_data.nameCandidate full name.
candidate_data.emailEmail address.
candidate_data.skillsList of extracted skills.
candidate_data.experienceList of positions with title, company, duration, description, location.
candidate_data.educationList of degrees with institution, year, location.
candidate_data.total_experienceCalculated total years of experience.
candidate_data.career_gapsDetected employment gaps.
candidate_data.filenameName of the source file.

Single resume analysis

result = reveilio.analyze_resume("resumes/alice.pdf", jd)

print(result.overall_score)                           # 82.0
print(result.recommendation)                          # "Shortlist"
print(result.detailed_scores["skills"]["score"])      # 90
print(result.detailed_scores["skills"]["reasoning"])  # "Strong match..."
print(result.ai_summary)                              # 120-word critique
print(result.suggested_questions)                      # interview Qs

Batch folder analysis

analyze_folder() processes every supported file in a directory, scores them in parallel using threads, sorts results by overall_score descending, and assigns a 1-based rank.

results = reveilio.analyze_folder(
    "./applicants",
    jd,
    extensions=(".pdf", ".docx"),  # optional filter
    max_workers=4,                    # parallel LLM calls
    recursive=True,                  # include subfolders
)

for r in results:
    print(f"#{r.rank} {r.candidate_data.name} {r.overall_score}%")

Error handling

If the LLM call fails for a specific resume (network error, malformed response, etc.), the scorer catches the exception and returns a safe fallback result with:

This means a single bad resume in a 500-resume batch will not crash the entire run. You can detect error results by checking the summary:

errors = [r for r in results if "Error" in (r.ai_summary or "")]
print(f"{len(errors)} resume(s) failed analysis")

Customizing weights

Pass a custom weights dictionary to configure() to change what the scorer optimizes for. The weights are embedded directly into the LLM prompt.

reveilio.configure(
    provider="openai",
    api_key="sk-...",
    weights={
        "skills": 0.35,            # heavy emphasis on skills
        "semantic_skills": 0.15,
        "experience": 0.25,
        "education": 0.05,          # de-emphasize education
        "certifications": 0.10,
        "soft_skills": 0.05,
        "domain_relevance": 0.05,
    },
)

Continue to PDF reports.