Files
jobtrackingapp/tools/summarizer
cesnimda 173187dcbb feat(cv): Phase 2.1-b — extract Projects, Certifications, and languages-from-prose
The structured model and StructuredCvProfileJson.FromSections already map
Projects/Certifications/Languages headings, but the AI normalize prompt
never emitted them, so on the benchmark CV the entire Projects section and
the in-summary languages (English Native, Norwegian B1) were silently
dropped. This closes that gap upstream — no backend schema or data change.

ai-service (tools/summarizer/app.py):
- /cv/normalize: added # Projects and # Certifications headings; a
  languages-from-prose rule (pull "native English", "Norwegian at B1" out
  of the summary even with no Languages section; ignore programming
  languages); and skill-group prefix stripping ("Development:",
  "DevOps & Infrastructure:", "Practices:" dropped, only the skills kept).
- /cv/classify-block: Projects and Certifications added to the section
  enum + rules (fallback path).

Backend:
- LooksLikeNormalizedMarkdownCv now recognises # Projects / # Certifications
  so those CVs still take the markdown assembly path.

Tests:
- CvExtractionCoverageTests (4) lock the C# mapping of Projects,
  Certifications and Languages sections into the structured profile.
- ai-service test_classify_block_supports_projects_section (1).
426 backend tests, 17 ai-service tests pass; app.py compiles.

The LLM behaviour (prompt -> headings) needs Ollama to observe and was not
run here; the C# side that consumes the headings is proven and the prompt
change is additive. Merge-not-replace + the review screen are the next
increment (2.1-a, approved: always-review, conservative merge).

Deployment: these prompts live in the ai-service container, which
deploy.sh does not rebuild by default -- deploy with
DEPLOY_BUILD_AI_SERVICE=true or the change won't take effect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 11:40:04 +02:00
..
2026-03-21 11:55:27 +01:00
2026-03-21 11:55:27 +01:00

Local AI Service

This service runs a local Hugging Face summarization model and also exposes document text extraction with OCR for supported PDFs and images.

Capabilities

  • job/role summarization
  • PDF text extraction
  • OCR fallback for scanned PDFs
  • OCR for image uploads (png, jpg, jpeg, webp)
  • DOCX / TXT / MD extraction
  • optional Ollama-backed CV block classification for harder sectioning

Install

Windows:

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python -m uvicorn app:app --host 127.0.0.1 --port 8001 --workers 1

Linux / macOS:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m uvicorn app:app --host 127.0.0.1 --port 8001 --workers 1

If the host is missing python3-venv or pip, use the bootstrap script instead:

./scripts/bootstrap-and-test.sh bootstrap

Docker

The Dockerfile installs Tesseract OCR so scanned PDFs and supported images can be processed inside the container.

Tests

Run the summarizer unit tests with:

./scripts/bootstrap-and-test.sh test

The script:

  • creates .venv with stdlib venv when available
  • falls back to user-space virtualenv when host venv support is missing
  • installs requirements-dev.txt
  • writes pytest cache under tmp/pytest-cache to avoid stale root-owned .pytest_cache directories

API

  • GET /health — health check and runtime capabilities, including lazy model state (model_loaded, model_disabled, summarize_available, model_load_error) plus Ollama version/model metadata when configured
  • POST /summarize — JSON body { "text": "...", "max_length": 150, "min_length": 30 }
  • POST /extract-text — multipart file upload, returns extracted text and OCR metadata
  • POST /cv/classify-block — JSON body { "block": "..." }, uses Ollama when OLLAMA_MODEL is configured

Ollama

Set these before starting the service if you want the hybrid CV classifier enabled:

export OLLAMA_BASE_URL=http://ollama:11434
export OLLAMA_MODEL=qwen2.5:7b

Choose the model by setting OLLAMA_MODEL and then warming it with the helper script:

OLLAMA_MODEL=qwen2.5:7b ./scripts/start-ollama-cv.sh

Equivalent manual flow:

docker compose up -d ollama
docker compose exec ollama ollama pull qwen2.5:7b
docker compose up -d ai-service
  • Model weights are downloaded on first pull.
  • OCR quality depends on scan quality and language support.
  • Default OCR language is English (eng).