Pourquoi chaque technologie a été choisie
Langage principal du projet. Choix motivé par :
| (union types) depuis 3.10click et argparsepdfplumber.open(path).pages[i].extract_text()Fallback : PyMuPDF (fitz) si pdfplumber manquant.
Convertit chaque page du PDF en image (PNG) pour l'OCR.
Wrapper Python de Tesseract 5.3+ pour la reconnaissance de caractères.
fra+eng (CV bilingue FR/EN)Alternatives possibles : easyocr paddleocr (plus précis mais plus lourd).
Client API compatible OpenAI. On ne connecte pas à l'API d'OpenAI — on change juste le base_url :
client = openai.OpenAI(
base_url="http://localhost:1234/v1",
api_key="not-needed",
)
Pourquoi pas HuggingFace ? Dépendances trop lourdes (transformers, torch). LM Studio externalise tout dans le processus local.
Le schéma YAML est converti en valeurs par défaut JSON. Le LLM utilise cette structure comme contrainte de sortie.
# YAML → valeurs par défaut JSON
personal:
full_name: string → ""
email: string → ""
experience:
- company: string → [ { "company": "" } ]
Framework CLI Python. Plus ergonomique qu'argparse :
@click.command()
@click.argument("pdf", type=click.Path(exists=True))
@click.option("-o", "--output", type=click.Path())
@click.option("--schema", "schema_path", type=click.Path())
@click.option("--extract", is_flag=True)
@click.option("--format", "output_format", type=click.Choice(["json", "docx"]))
@click.option("--verbose", "-v", is_flag=True)
def main(pdf, output, schema_path, extract, output_format, verbose):
...
Validation du JSON produit par le LLM. Vérifie que la sortie respecte le schéma attendu. Si non conforme, le LLM peut être relancé avec les erreurs.
Génère un CV Word professionnel à partir du JSON structuré. C'est un bonus — la vraie valeur est le JSON qui alimente Power Platform / Power Automate.
Pourquoi pas Word directement ? python-docx est fragile (mises en forme perdues). Power Platform est fait pour le templating.
Charge les variables d'environnement depuis .env (URL et clé LM Studio).
Output CLI coloré et formaté (utilisé dans cli.py pour les messages de statut).
[project]
name = "cv-tool"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"pdfplumber>=0.10.0",
"PyMuPDF>=1.23.0",
"pytesseract>=0.3.10",
"pdf2image>=1.16.0",
"pydantic>=2.0",
"pyyaml>=6.0",
"rich>=13.0",
"click>=8.1",
"openai>=1.0",
"python-dotenv>=1.0",
]
[project.optional-dependencies]
ocr-alt = ["easyocr>=1.2", "paddleocr>=2.0"]
docx = ["python-docx>=1.1.0"]
dev = ["pytest>=7.0", "pytest-cov", "ruff", "mypy"]
[project.scripts]
cv-tool = "cv_tool.cli:main"