Skip to content

[Feature Request]: Add Resume-Aware Email Personalization — Parse Uploaded Resume and Inject Context into Cold Email Prompts #174

Description

@divyanshim27

Summary

Arachnode's email-generator-service already includes a resume_parser.py module and a RESUME_PARSER_EXAMPLES.md demonstrating before/after email personalization. However, based on the README roadmap, integrating the resume parser into the live email generation pipeline is still marked as a completed checkbox ([x]) but the actual /api/generate endpoint does not appear to accept a resume as an input parameter — it only accepts job_id, contact_id, and template. This means the personalization described in the examples is not triggered in the default workflow.

Problem

  • The resume_parser.py module exists but the /api/generate route's documented interface (job_id, contact_id, template) does not include a mechanism to pass resume content or a parsed resume object.
  • Cold emails generated without resume context use generic Jinja2 templates, producing the "before" examples in RESUME_PARSER_EXAMPLES.md rather than the personalized "after" versions.
  • Users who have a resume available cannot easily feed it into the generation pipeline — the API reference in the README only shows candidate_skills, candidate_role, candidate_experience as optional string parameters, but there is no PDF upload or stored-resume retrieval path documented.

Impact

  • The highest-value feature of Arachnode — genuinely personalized cold emails — is non-functional for the majority of users who don't manually provide candidate_skills as a raw string in the API payload.
  • Users interacting via the dashboard cannot upload their resume and have it persist for all future email generations.

Proposed Solution

I would like to implement a persistent resume store with automatic injection into the email generation pipeline:

Step 1 — Resume upload endpoint:

# In gateway/main.py
@app.post("/api/resume/upload")
async def upload_resume(file: UploadFile = File(...)):
    if file.content_type not in ["application/pdf", "text/plain"]:
        raise HTTPException(400, "Only PDF and .txt resumes are supported.")
    content = await file.read()
    # Save to local filesystem or S3 equivalent
    resume_path = f"data/resumes/{uuid4()}.pdf"
    with open(resume_path, "wb") as f:
        f.write(content)
    # Parse immediately and cache result
    parsed = parse_resume(resume_path)
    return {"resume_id": resume_path, "parsed_summary": parsed}

Step 2 — Persist parsed resume in Postgres:

ALTER TABLE emails ADD COLUMN candidate_context JSONB;
CREATE TABLE resume_cache (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  file_path TEXT,
  parsed_skills TEXT[],
  parsed_experience TEXT,
  parsed_role TEXT,
  created_at TIMESTAMPTZ DEFAULT now()
);

Step 3 — Inject resume context automatically in /api/generate:

# email-generator-service/generator.py
async def generate_email(job: dict, contact: dict, template: str, resume_id: str = None):
    candidate_context = {}
    if resume_id:
        cached = await db.fetchrow("SELECT * FROM resume_cache WHERE id = $1", resume_id)
        candidate_context = {
            "skills": cached["parsed_skills"],
            "experience": cached["parsed_experience"],
            "role": cached["parsed_role"]
        }
    prompt = build_prompt(job, contact, template, candidate_context)
    return await ollama_client.generate(prompt)

Step 4 — Dashboard UI:

  • "Upload Resume" button in settings sidebar.
  • Parsed skill chips displayed after upload for verification.
  • All future email generations automatically use the stored resume.

Deliverables

  • POST /api/resume/upload — resume upload + parse + cache.
  • resume_cache Postgres table migration in scripts/.
  • generator.py updated to auto-inject resume context.
  • Gateway proxy route for resume upload.
  • Dashboard "Resume" settings section.
  • Unit tests for the resume parser covering PDF and plain text inputs.

Labels: enhancement, feature, backend, GSSoC 2026

Could you assign this issue to me?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions