# Procyon — shared pipeline. One prepare path for both the web UI and the autopilot. import os import db import tailor import audit import scraper import resume_pdf BASE = os.path.dirname(os.path.abspath(__file__)) def prepare(job): """Score -> tailor -> draft -> PDF -> self-audit. Returns app_id. NO sending.""" score, opinion = tailor.score_job(job) db.update_job_score(job['id'], score, opinion) tracks, _master = tailor.build_master(job) structured = tailor.structured_resume(job) text = tailor.structured_to_text(structured) subject = tailor.make_subject(job) research = scraper.research_company(job) body = tailor.draft_email(job, text, research=research) # scrape a contact email (best-effort, for auto-send on approve) — only runs for # the handful of jobs that get prepared, not the bulk discover. if not (job.get('contact_email') or '').strip(): try: contact = scraper.scrape_contact_email(job) if contact: db.set_job_contact_email(job['id'], contact) except Exception: pass aid = db.create_application(job['id'], subject=subject, body=body) # one-page PDF pdf = '' try: out = os.path.join(BASE, 'data', 'resumes', f'app_{aid}.pdf') os.makedirs(os.path.dirname(out), exist_ok=True) resume_pdf.render(structured, out_path=out) if os.path.exists(out): pdf = out except Exception as e: print(f'pdf render failed: {e}') # text version for display rdir = os.path.join(BASE, 'data', 'tailored') os.makedirs(rdir, exist_ok=True) tpath = os.path.join(rdir, f'app_{aid}_resume.txt') with open(tpath, 'w', encoding='utf-8') as f: f.write(text) db.update_application(aid, resume_path=tpath, tailored_pdf=pdf, status='tailored', notes=f'tracks: {",".join(tracks)}') # self-audit (now includes ATS keyword coverage) checks = audit.run_audit(aid, job, subject, body, text) ok = audit.all_pass(checks) db.update_application(aid, status='audited', audit_json=str(checks)) db.set_job_status(job['id'], 'audited') return aid