Files
jobtrackingapp/docs/cv-builder-parser-benchmark.md

6.3 KiB

CV builder, parser, benchmark, and Ollama admin integration

What changed

This branch upgrades the Profile CV flow from a text-only rewrite helper into a template-driven CV builder backed by the server-side renderer/PDF pipeline, strengthens CV normalization around location and qualification handling, adds a repeatable local corpus benchmark workflow, and expands the admin system page with richer Ollama visibility.

Profile CV builder

New backend capabilities

JobTrackerApi/Controllers/ProfileCvController.cs

  • Hardened POST /api/profile-cv/rewrite-section
    • accepts flexible jobApplicationId payloads (number or blank string)
    • uses richer saved-job context for tailoring
    • logs empty AI responses with useful context
  • Added GET /api/profile-cv/templates
  • Added POST /api/profile-cv/rewrite-preview
    • rewrites either the whole CV or one selected section
    • rebuilds structured CV from the rewritten full text
    • maps the result into the shared template renderer
    • returns rendered HTML, file name, rewritten text, and full replacement text
  • Added POST /api/profile-cv/export-pdf
    • uses the same rendered HTML and the shared Playwright exporter

Frontend flow

job-tracker-ui/src/pages/ProfilePage.tsx

  • Replaced the old rewrite draft box with a template-driven builder section.
  • Users can:
    • choose from 6 templates
    • optionally target one section
    • target by free-text role or saved job
    • inspect the rewritten content
    • inspect the actual rendered preview
    • download a PDF
    • replace the master CV with the rebuilt full-text result

Templates

Shared renderer: JobTrackerApi/Services/CvTemplateRenderer.cs

Available templates:

  • ats-minimal
  • harvard
  • auckland
  • edinburgh
  • monarch
  • fjord

Adding a new template

  1. Add the new template id to NormalizeTemplateId() in:
    • JobTrackerApi/Services/CvTemplateRenderer.cs
    • JobTrackerApi/Controllers/ProfileCvController.cs
  2. Add a render branch in CvTemplateRenderer.Render().
  3. Add a descriptor to GetCvTemplateDescriptors().
  4. Add the matching card entry in job-tracker-ui/src/pages/ProfilePage.tsx if you want a custom preview card.

PDF generation

The master CV builder now reuses the existing server-side pipeline:

  1. rewrite full text / section
  2. rebuild structured CV
  3. map to TailoredCvDocument
  4. render HTML via ICvTemplateRenderer
  5. export PDF via ICvPdfExporter / Playwright

This keeps PDF output visually aligned with the selected template and avoids a separate client-only print implementation.

Parser and structured CV changes

Shared schema

Models/StructuredCvProfile.cs

Added:

  • education[].qualificationLevel
  • top-level certifications[]
  • top-level projects[]

qualification remains the original preserved text.

Normalization improvements

Models/StructuredCvProfileJson.cs

  • tighter location sanitization to avoid skill or role spillover into location fields
  • qualification level normalization to one of:
    • Secondary
    • Diploma/Certificate
    • Bachelor
    • Master
    • PhD
    • Other
  • first-class normalization for certifications and projects
  • section reconstruction now includes certifications and projects

Extraction prompt improvements

JobTrackerApi/Controllers/ProfileCvController.cs

The LLM extraction prompt now explicitly asks for:

  • qualification level enum
  • certifications
  • projects
  • strict location separation rules
  • preservation of original qualification text

Benchmark workflow

Runner

Use:

./scripts/run-cv-benchmark.sh

Optional overrides:

CV_BENCHMARK_OUTPUT_DIR=/absolute/output/path \
CV_BENCHMARK_APPROVED_DIR=/absolute/approved/fixtures/path \
./scripts/run-cv-benchmark.sh

Inputs

The runner scans:

  • /home/pi/cvs

Supported corpus file types:

  • PDF
  • DOCX
  • TXT
  • MD

Outputs

The runner writes:

  • index.json — machine-readable summary
  • report.md — markdown overview
  • outputs/*.json — latest normalized structured output per CV
  • candidate-fixtures/*.json — created when no approved fixture exists yet

Approved fixtures are local by design and should be reviewed manually before being promoted into the approved fixture path you use for regression comparisons.

Admin review

GET /api/admin/system/cv-benchmark

The admin system page surfaces:

  • benchmark root path
  • last benchmark update time
  • latest markdown summary

Ollama admin visibility

Python health endpoint

tools/summarizer/app.py

GET /health now returns additional Ollama metadata when configured/reachable:

  • ollama_version
  • ollama_installed_models
  • ollama_loaded_models
  • ollama_loaded_count

Backend propagation

JobTrackerApi/Services/SummarizerService.cs

The backend metrics shape now carries those fields through to admin consumers.

Admin UI

job-tracker-ui/src/pages/AdminSystemPage.tsx

The system page now shows:

  • Ollama version
  • loaded model count
  • installed model chips
  • loaded model chips
  • benchmark summary panel

Verification used on this branch

Backend

dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter ProfileCvControllerTests
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter "ProfileCvControllerTests|AuthAndSystemControllerTests|JobApplicationsApplicationPackageTests"
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter CvCorpusHarnessTests

Frontend

cd job-tracker-ui && CI=true npm test -- --runInBand --watch=false src/profile-page.test.tsx
cd job-tracker-ui && CI=true npm test -- --runInBand --watch=false src/admin-system-page.test.tsx
cd job-tracker-ui && CI=true npm test -- --runInBand --watch=false src/profile-page.test.tsx src/admin-system-page.test.tsx src/job-details-generated-drafts.test.tsx

Benchmark runner

CV_BENCHMARK_OUTPUT_DIR="$(pwd)/tmp/cv-benchmarks/latest" \
CV_BENCHMARK_APPROVED_DIR="$(pwd)/tmp/cv-benchmarks/approved" \
./scripts/run-cv-benchmark.sh

Python service tests

The summarizer Python unit tests were updated for the new health payload, but this machine currently lacks pip / venv support (python3 -m venv fails because python3.12-venv is not installed), so test execution is environment-blocked here. Once Python packaging is available, run:

cd tools/summarizer
python3 -m pytest -q tests/test_app.py