Skip to content
ahsan876 edited this page Apr 17, 2026 · 1 revision

Job descriptions

How reveilio loads, parses, and structures a job description.


The JobDescription class

A JobDescription holds the raw text of a JD and a lazily-computed structured parse. The LLM is only called the first time you access .parsed. After that, the result is cached on the object.

Each instance is fully independent. You can create multiple JobDescription objects for different open roles and reuse them across any number of resumes.


Three ways to create one

1. From a file on disk

Supports .pdf, .docx, .doc, and .txt files.

jd = reveilio.JobDescription.from_file("roles/senior_python.pdf")

Reveilio extracts the plain text from the file, stores it in jd.text, and sets jd.source to the file path.

2. From free text

Paste a JD directly from an email, database row, or API response.

jd = reveilio.JobDescription.from_text("""
Senior Python Engineer, 5+ years experience.
Must know FastAPI, PostgreSQL, and AWS.
Experience with CI/CD pipelines required.
""")

3. From in-memory bytes

Useful when integrating with web frameworks where uploaded files arrive as bytes.

jd = reveilio.JobDescription.from_bytes(
    uploaded_file.read(),
    filename="senior_python.pdf",  # extension determines the parser
)

What gets extracted

When you access jd.parsed, the LLM extracts a structured dictionary containing:

Field Description
position_title The role title (e.g. "Senior Full Stack Developer").
company The hiring company name.
location Work location.
work_mode Remote, hybrid, or on-site.
required_skills List of must-have technical skills.
preferred_skills List of nice-to-have skills.
soft_skills Communication, leadership, etc.
required_experience Minimum years of experience.
preferred_experience Preferred years of experience.
education_requirements List of required degrees.
certifications Required or preferred certifications.
tools_and_technologies Specific tools mentioned.
programming_languages Languages required.
frameworks Frameworks required (React, Django, etc.).
databases Database systems mentioned.
cloud_platforms AWS, Azure, GCP, etc.
methodologies Agile, Scrum, etc.
responsibilities List of job responsibilities.

Lazy parsing and caching

The structured parse is computed only on first access to jd.parsed. Creating a JobDescription object is instant. The LLM call only happens when you actually need the parsed data — typically when you call analyze_resume().

Once computed, the result is cached. If you score 500 resumes against the same JD, the JD parsing LLM call happens exactly once.

jd = reveilio.JobDescription.from_file("jd.pdf")  # no LLM call yet
print(jd.parsed["position_title"])               # LLM call happens here
print(jd.parsed["required_skills"])              # cached, no second call

Managing multiple JDs

Each JobDescription is an independent object with its own cache. Keep a dictionary of them for multi-role screening:

roles = {
    "backend":  reveilio.JobDescription.from_file("roles/backend.pdf"),
    "frontend": reveilio.JobDescription.from_file("roles/frontend.txt"),
    "devops":   reveilio.JobDescription.from_text(devops_jd_text),
}

# Score one candidate against all open roles
for role_name, jd in roles.items():
    result = reveilio.analyze_resume("resumes/alice.pdf", jd)
    print(f"{role_name}: {result.overall_score}%")

Inspecting the raw text

Extracted text is always available via jd.text. Useful for debugging or feeding into your own pipeline.

print(jd.text[:500])     # first 500 chars of extracted text
print(jd.source)         # file path or "text"

📝 Note: if the LLM cannot parse the JD (e.g. text is too garbled), jd.parsed returns a safe fallback dictionary with "position_title": "N/A" and empty lists for skills and requirements.


Continue to Resume parsing.

Clone this wiki locally