cv-generator / DOCUMENTATION.md
Liantsoaxx08's picture
avec une design cv felxible
771c280
|
Raw
History Blame Contribute Delete
32.7 kB

πŸ“š Documentation Technique - CV Generator

🎯 Vue d'ensemble du Projet

CV Generator est une application web moderne permettant de générer des CV professionnels au format PDF, optimisés pour les systèmes ATS (Applicant Tracking System). L'application utilise l'intelligence artificielle pour améliorer le contenu du CV.


πŸ—οΈ Architecture du Projet

Structure des Dossiers

CVGENERATOR/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ models/          # ModΓ¨les de donnΓ©es Pydantic
β”‚   β”‚   β”‚   └── cv_models.py
β”‚   β”‚   β”œβ”€β”€ services/        # Logique mΓ©tier
β”‚   β”‚   β”‚   β”œβ”€β”€ gemini_service.py
β”‚   β”‚   β”‚   └── document_service.py
β”‚   β”‚   β”œβ”€β”€ routes/          # Points d'entrΓ©e API
β”‚   β”‚   β”‚   └── cv_routes.py
β”‚   β”‚   └── main.py          # Configuration FastAPI
β”‚   β”œβ”€β”€ venv/                # Environnement virtuel Python
β”‚   └── requirements.txt
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ index.html           # Interface utilisateur
β”‚   β”œβ”€β”€ styles.css           # Styles responsive
β”‚   └── script.js            # Logique frontend
β”œβ”€β”€ app.py                   # Point d'entrΓ©e Hugging Face
β”œβ”€β”€ Dockerfile               # Configuration Docker
β”œβ”€β”€ requirements.txt         # DΓ©pendances production
└── README.md

πŸ”§ Principes SOLID AppliquΓ©s

Notre architecture respecte les 5 principes SOLID pour garantir un code maintenable et Γ©volutif.

1. S - Single Responsibility Principle (SRP)

Chaque classe a une seule responsabilitΓ© :

Classe ResponsabilitΓ© Unique
GeminiService Communication avec l'API Gemini AI
DocxGenerator GΓ©nΓ©ration de documents DOCX
PDFConverter Conversion DOCX vers PDF
CVGeneratorService Orchestration du processus de gΓ©nΓ©ration

class DocxGenerator(DocumentGeneratorInterface):
    def generate(self, cv_data: CVData, output_path: str) -> str:
        # Génère uniquement le document DOCX
        pass

2. O - Open/Closed Principle (OCP)

Les classes sont ouvertes Γ  l'extension mais fermΓ©es Γ  la modification :

# Interface abstraite - peut Γͺtre Γ©tendue sans modifier l'existant
class DocumentGeneratorInterface(ABC):
    @abstractmethod
    def generate(self, cv_data: CVData, output_path: str) -> str:
        pass

# Extension possible sans modifier l'interface
class DocxGenerator(DocumentGeneratorInterface):
    pass

class LatexGenerator(DocumentGeneratorInterface):  # Futur
    pass

3. L - Liskov Substitution Principle (LSP)

Les sous-classes peuvent remplacer leurs classes parentes :

# N'importe quelle implΓ©mentation de DocumentGeneratorInterface
# peut Γͺtre utilisΓ©e de maniΓ¨re interchangeable
def create_cv(generator: DocumentGeneratorInterface, data: CVData):
    return generator.generate(data, "output.docx")

# Fonctionne avec DocxGenerator ou toute autre implΓ©mentation
create_cv(DocxGenerator(), cv_data)

4. I - Interface Segregation Principle (ISP)

Des interfaces spΓ©cifiques plutΓ΄t qu'une interface monolithique :

# Interfaces sΓ©parΓ©es pour chaque fonctionnalitΓ©
class DocumentGeneratorInterface(ABC):
    @abstractmethod
    def generate(self, cv_data, output_path) -> str: pass

class AIServiceInterface(ABC):
    @abstractmethod
    def generate_summary(self, data) -> str: pass
    @abstractmethod
    def enhance_experience(self, description) -> str: pass

5. D - Dependency Inversion Principle (DIP)

Les modules de haut niveau dΓ©pendent d'abstractions :

# Le service dépend d'abstractions, pas d'implémentations concrètes
class CVGeneratorService:
    def __init__(self, 
                 docx_generator: DocxGenerator,      # Injection
                 pdf_converter: PDFConverter):       # de dΓ©pendances
        self.docx_generator = docx_generator
        self.pdf_converter = pdf_converter

πŸ”„ Flux de DonnΓ©es

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        FRONTEND                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Γ‰tape 1 │───▢│  Γ‰tape 2 │───▢│  Γ‰tape 3 │───▢│  Γ‰tape 4 β”‚  β”‚
β”‚  β”‚ Infos    β”‚    β”‚Formation β”‚    β”‚ExpΓ©rienceβ”‚    β”‚CompΓ©tencesβ”‚  β”‚
β”‚  β”‚Personnelsβ”‚    β”‚          β”‚    β”‚          β”‚    β”‚& Langues β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                        β”‚        β”‚
β”‚                                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”‚
β”‚                                              β”‚    Γ‰tape 5     β”‚ β”‚
β”‚                                              β”‚   AperΓ§u &     β”‚ β”‚
β”‚                                              β”‚   GΓ©nΓ©ration   β”‚ β”‚
β”‚                                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                        β”‚
                                                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     API FASTAPI                                  β”‚
β”‚                                                                  β”‚
β”‚   POST /api/cv/generate                                         β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚                                                          β”‚   β”‚
β”‚   β”‚  1. Validation des donnΓ©es (Pydantic)                   β”‚   β”‚
β”‚   β”‚                     β”‚                                    β”‚   β”‚
β”‚   β”‚                     β–Ό                                    β”‚   β”‚
β”‚   β”‚  2. GΓ©nΓ©ration rΓ©sumΓ© IA (GeminiService)                β”‚   β”‚
β”‚   β”‚                     β”‚                                    β”‚   β”‚
β”‚   β”‚                     β–Ό                                    β”‚   β”‚
β”‚   β”‚  3. CrΓ©ation DOCX (DocxGenerator)                       β”‚   β”‚
β”‚   β”‚                     β”‚                                    β”‚   β”‚
β”‚   β”‚                     β–Ό                                    β”‚   β”‚
β”‚   β”‚  4. Conversion PDF (PDFConverter)                       β”‚   β”‚
β”‚   β”‚                     β”‚                                    β”‚   β”‚
β”‚   β”‚                     β–Ό                                    β”‚   β”‚
β”‚   β”‚  5. Retour URLs de tΓ©lΓ©chargement                       β”‚   β”‚
β”‚   β”‚                                                          β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ€– IntΓ©gration de l'IA (Gemini)

FonctionnalitΓ©s IA

  1. GΓ©nΓ©ration automatique de rΓ©sumΓ© professionnel

    • Analyse des expΓ©riences et compΓ©tences
    • CrΓ©ation d'un profil percutant
  2. AmΓ©lioration des descriptions d'expΓ©rience

    • Reformulation professionnelle
    • Ajout de verbes d'action

Gestion des Erreurs et Fallback

class GeminiService:
    FALLBACK_MODELS = [
        "gemini-2.0-flash",
        "gemini-1.5-flash", 
        "gemini-1.0-pro"
    ]
    
    def _call_with_retry(self, prompt: str) -> str:
        """Essaie plusieurs modèles en cas d'échec"""
        for model_name in self.FALLBACK_MODELS:
            try:
                model = genai.GenerativeModel(model_name)
                response = model.generate_content(prompt)
                return response.text
            except Exception:
                continue
        return self._generate_fallback_summary()

Gestion des Quotas

En cas de dépassement de quota API, l'application génère automatiquement un résumé basé sur les données fournies :

def _generate_fallback_summary(self, cv_data: CVData) -> str:
    """Génère un résumé sans IA en cas de quota dépassé"""
    skills = ", ".join([s.name for s in cv_data.skills[:5]])
    return f"Professionnel expΓ©rimentΓ© avec des compΓ©tences en {skills}..."

πŸ“„ GΓ©nΓ©ration de Documents ATS-Friendly

Principes de Design ATS

Les systèmes ATS (Applicant Tracking System) analysent automatiquement les CV. Notre générateur respecte ces règles :

βœ… Bonnes Pratiques ❌ Γ€ Γ‰viter
Structure linΓ©aire Colonnes multiples
Police standard (Calibri) Polices dΓ©coratives
Titres en majuscules Graphiques/Images
Format simple Tableaux complexes
Texte pur En-tΓͺtes/Pieds de page

Structure du CV GΓ©nΓ©rΓ©

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           NOM COMPLET                  β”‚  ← CentrΓ©, 24pt, Gras
β”‚    βœ‰ email | ☎ tΓ©lΓ©phone | πŸ“ ville   β”‚  ← Infos contact
β”‚         LinkedIn | Portfolio           β”‚  ← Liens
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ PROFIL PROFESSIONNEL                   β”‚  ← Section titre
β”‚ ─────────────────────────────          β”‚  ← Ligne bleue
β”‚ RΓ©sumΓ© gΓ©nΓ©rΓ© par IA...                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
│ EXPÉRIENCE PROFESSIONNELLE             │
β”‚ ─────────────────────────────          β”‚
β”‚ Poste  |  Jan 2020 - PrΓ©sent          β”‚  ← Titre + dates
β”‚ Entreprise                             β”‚  ← Italique
β”‚ β–Έ RΓ©alisation 1                        β”‚  ← Bullet points
β”‚ β–Έ RΓ©alisation 2                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ FORMATION                              β”‚
β”‚ ─────────────────────────────          β”‚
β”‚ DiplΓ΄me  |  2015 - 2018               β”‚
β”‚ Γ‰cole                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
│ COMPÉTENCES                            │
β”‚ ─────────────────────────────          β”‚
β”‚ Expert: Python β€’ JavaScript β€’ React    β”‚  ← GroupΓ©es par niveau
β”‚ IntermΓ©diaire: Docker β€’ AWS            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ LANGUES                                β”‚
β”‚ ─────────────────────────────          β”‚
β”‚ β–Έ FranΓ§ais: Natif                      β”‚
β”‚ β–Έ Anglais: Courant                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ CENTRES D'INTΓ‰RÊT                      β”‚
β”‚ ─────────────────────────────          β”‚
β”‚ Lecture β€’ Sport β€’ Voyages              β”‚  ← Sur une ligne
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🎨 Design Frontend Responsive

Breakpoints CSS

/* Desktop */
@media (min-width: 1200px) { ... }

/* Tablette */
@media (max-width: 768px) { ... }

/* Mobile */
@media (max-width: 480px) { ... }

/* Très petit écran */
@media (max-width: 360px) { ... }

FonctionnalitΓ©s Responsive

  • Formulaires adaptatifs : Colonnes β†’ Lignes sur mobile
  • Navigation tactile : Boutons agrandis
  • Typographie fluide : clamp() pour tailles de police
  • Labels masquΓ©s : Sur trΓ¨s petits Γ©crans

πŸš€ DΓ©ploiement

Architecture de DΓ©ploiement (Hugging Face Spaces)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 Hugging Face Spaces                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚              Docker Container                  β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚           Python 3.10-slim              β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  FastAPI  β”‚    β”‚   LibreOffice   β”‚  β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  (app.py) β”‚    β”‚   (PDF Conv.)   β”‚  β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚  β”‚
β”‚  β”‚  β”‚        β”‚                                β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”                         β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  Frontend β”‚                         β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”‚  (static) β”‚                         β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                         β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                        β”‚                             β”‚
β”‚                   Port 7860                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
                    Internet

Variables d'Environnement

Variable Description Requis
GEMINI_API_KEY ClΓ© API Google Gemini βœ…
PORT Port du serveur (défaut: 7860) ❌

πŸ§ͺ Tests et Validation

Points de Test API

# Health Check
curl http://localhost:8000/api/cv/health

# GΓ©nΓ©ration de CV
curl -X POST http://localhost:8000/api/cv/generate \
  -H "Content-Type: application/json" \
  -d '{
    "personal_info": {...},
    "education": [...],
    "experiences": [...],
    "skills": [...],
    "languages": [...]
  }'

Validation des DonnΓ©es

Toutes les donnΓ©es sont validΓ©es par Pydantic :

class PersonalInfo(BaseModel):
    full_name: str = Field(..., min_length=2, max_length=100)
    email: EmailStr
    phone: str
    address: str
    linkedin: Optional[str] = None
    portfolio: Optional[str] = None
    summary: Optional[str] = None

πŸ“ˆ AmΓ©liorations Futures

Roadmap

  • Templates multiples : DiffΓ©rents designs de CV
  • Export LaTeX : Pour les CV acadΓ©miques
  • Analyse ATS : Score de compatibilitΓ©
  • Multi-langues : Interface en plusieurs langues
  • Stockage cloud : Sauvegarde des CV
  • Authentification : Comptes utilisateurs

πŸ‘₯ Contribution

Standards de Code

  • Python : PEP 8, type hints
  • JavaScript : ES6+, async/await
  • CSS : BEM methodology, variables CSS
  • Commits : Conventional Commits

Structure des Commits

feat: ajout de la gΓ©nΓ©ration PDF
fix: correction du bug de conversion
docs: mise Γ  jour de la documentation
style: formatage du code
refactor: restructuration du service Gemini

πŸ“ Licence

Ce projet est dΓ©veloppΓ© dans un cadre Γ©ducatif.


Documentation gΓ©nΓ©rΓ©e le 31 dΓ©cembre 2025


🎯 Approche Technique : Génération de CV avec Template et Ajustement Automatique

πŸ“‹ Vue d'ensemble de l'Approche

Notre système de génération de CV utilise une approche hybride innovante combinant :

  1. Template Word (docx) comme base de design
  2. Remplissage dynamique avec Jinja2/docxtpl
  3. Ajustement automatique des tailles et espacements selon le volume de contenu

Cette approche garantit que le CV tient toujours sur une seule page, quelle que soit la quantitΓ© d'informations.


πŸ—οΈ Architecture de la Solution

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
│                    PROCESSUS DE GÉNÉRATION                       │
β”‚                                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚  β”‚   DonnΓ©es    │───▢│   Calcul     │───▢│  SΓ©lection   β”‚       β”‚
β”‚  β”‚   CV (JSON)  β”‚    β”‚   Volume     β”‚    β”‚   Preset     β”‚       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β”‚                                                 β”‚                β”‚
β”‚                                                 β–Ό                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚  β”‚   Template   │───▢│  Remplissage │───▢│  Ajustement  β”‚       β”‚
β”‚  β”‚   .docx      β”‚    β”‚   Jinja2     β”‚    β”‚  Tailles     β”‚       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β”‚                                                 β”‚                β”‚
β”‚                                                 β–Ό                β”‚
β”‚                                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚                                          β”‚   CV Final   β”‚       β”‚
β”‚                                          β”‚  (1 page)    β”‚       β”‚
β”‚                                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”§ Composants Principaux

1. Template Word (template.docx)

Le template est un fichier Word avec un design 2 colonnes contenant des placeholders Jinja2 :

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  COLONNE GAUCHE  β”‚        COLONNE DROITE              β”‚
β”‚                  β”‚                                    β”‚
β”‚  CONTACT         β”‚   {{ full_name }}                  β”‚
β”‚  {{ phone }}     β”‚                                    β”‚
β”‚  {{ email }}     β”‚   PROFIL                           β”‚
β”‚  {{ address }}   β”‚   {{ summary }}                    β”‚
β”‚                  β”‚                                    β”‚
│  COMPÉTENCES     │   FORMATION                        │
β”‚  {% for skill    β”‚   {% for edu in education %}       β”‚
β”‚  in skills %}    β”‚   {{ edu.degree }}                 β”‚
β”‚  β€’ {{ skill.     β”‚   ({{ edu.period }})               β”‚
β”‚  display }}      β”‚   {% endfor %}                     β”‚
β”‚  {% endfor %}    β”‚                                    β”‚
│                  │   EXPÉRIENCES                      │
β”‚  LANGUES         β”‚   {% for exp in experiences %}     β”‚
β”‚  {% for lang %}  β”‚   {{ exp.job_title }}              β”‚
β”‚  β€’ {{ lang.      β”‚   {{ exp.company }}                β”‚
β”‚  display }}      β”‚   {% endfor %}                     β”‚
β”‚  {% endfor %}    β”‚                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Calcul du Volume de Contenu

L'algorithme calcule un score de volume basΓ© sur tous les Γ©lΓ©ments du CV :

def _calculate_content_volume(self, cv_data):
    volume = 0
    
    # ExpΓ©riences : 2 points + lignes de description
    for exp in cv_data.experiences:
        volume += 2  # Titre + entreprise
        if exp.description:
            lines = exp.description.split('\n')
            volume += len([l for l in lines if l.strip()])
    
    # Formations : 2 points chacune
    for edu in cv_data.education:
        volume += 2
        if edu.description:
            volume += 1
    
    # Autres Γ©lΓ©ments : 1 point chacun
    volume += len(cv_data.skills)
    volume += len(cv_data.languages)
    volume += len(cv_data.hobbies)
    
    # Résumé : 1 point par 100 caractères
    if cv_data.personal_info.summary:
        volume += len(cv_data.personal_info.summary) // 100 + 1
    
    return volume

3. Système de Presets (Paliers)

Selon le volume calculΓ©, un preset est sΓ©lectionnΓ© :

Preset Volume Police Nom Police Section Police Normale Police Petite
light < 18 22pt 11pt 10pt 9pt
medium 18-25 20pt 10pt 9pt 8pt
dense 25-35 18pt 9pt 8pt 7pt
very_dense > 35 16pt 8pt 7pt 6pt

4. Espacements Adaptatifs

Les espacements entre paragraphes varient Γ©galement :

Preset Espace Avant Espace Après Interligne
light 3pt 1pt 0.9
medium 2pt 1pt 0.9
dense 1pt 0pt 0.9
very_dense 0pt 0pt 0.9

πŸ“Š Diagramme du Flux de DonnΓ©es

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   CVData JSON   β”‚
                    β”‚                 β”‚
                    β”‚ β€’ personal_info β”‚
                    β”‚ β€’ experiences   β”‚
                    β”‚ β€’ education     β”‚
                    β”‚ β€’ skills        β”‚
                    β”‚ β€’ languages     β”‚
                    β”‚ β€’ hobbies       β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚   _calculate_content_volume   β”‚
              β”‚                              β”‚
              β”‚   Volume = Ξ£(Γ©lΓ©ments)       β”‚
              β”‚                              β”‚
              β”‚   Ex: 3 exp + 2 edu + 5 skillsβ”‚
              β”‚       + 2 lang + 3 hobbies   β”‚
              β”‚       = ~25 points           β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚     _get_size_preset          β”‚
              β”‚                              β”‚
              β”‚   if volume > 35: very_dense β”‚
              β”‚   elif volume > 25: dense    β”‚
              β”‚   elif volume > 18: medium   β”‚
              β”‚   else: light                β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚      _prepare_context         β”‚
              β”‚                              β”‚
              β”‚   Transforme CVData en dict  β”‚
              β”‚   compatible Jinja2          β”‚
              β”‚                              β”‚
              β”‚   β€’ description_lines        β”‚
              β”‚   β€’ period formatΓ©           β”‚
              β”‚   β€’ display strings          β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚   DocxTemplate.render()       β”‚
              β”‚                              β”‚
              β”‚   Remplit les placeholders   β”‚
              β”‚   {{ variable }}             β”‚
              β”‚   {% for %} ... {% endfor %} β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚   _adjust_document_sizes      β”‚
              β”‚                              β”‚
              β”‚   Parcourt tous les Γ©lΓ©ments β”‚
              β”‚   β€’ Paragraphes              β”‚
              β”‚   β€’ Cellules de tableau      β”‚
              β”‚                              β”‚
              β”‚   Applique :                 β”‚
              β”‚   β€’ Tailles de police        β”‚
              β”‚   β€’ Espacements              β”‚
              β”‚   β€’ Interligne               β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚        CV Final .docx         β”‚
              β”‚                              β”‚
              β”‚   βœ… Tient sur 1 page        β”‚
              β”‚   βœ… Design prΓ©servΓ©         β”‚
              β”‚   βœ… Lisible                 β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🎨 Avantages de l'Approche Template

βœ… Points Forts

Avantage Description
Design prΓ©servΓ© Le template Word garde toutes les mises en forme (couleurs, polices, bordures)
Facilement modifiable Un designer peut modifier le template sans toucher au code
SΓ©paration des responsabilitΓ©s Design (template) vs Logique (Python)
RΓ©utilisable Plusieurs templates possibles pour diffΓ©rents styles
Ajustement intelligent Le CV s'adapte automatiquement au contenu

⚠️ Limitations

Limitation Solution
Template doit exister Guide de crΓ©ation fourni
Syntaxe Jinja2 requise Documentation des placeholders
Ajustement post-rendu Peut légèrement modifier le design

πŸ”„ Algorithme d'Ajustement DΓ©taillΓ©

def _adjust_document_sizes(self, doc, preset_name):
    """
    Parcourt le document et ajuste dynamiquement :
    1. Les tailles de police selon leur taille actuelle
    2. Les espacements avant/après paragraphes
    3. L'interligne (line_spacing)
    """
    preset = self.SIZE_PRESETS[preset_name]
    spacing = self.SPACING_PRESETS[preset_name]
    
    # Règle de mapping des tailles
    # β‰₯ 20pt β†’ taille 'name' (titre principal)
    # β‰₯ 11pt β†’ taille 'section' (titres de section)
    # β‰₯ 9pt  β†’ taille 'normal' (texte courant)
    # < 9pt  β†’ taille 'small' (dΓ©tails, dates)
    
    for paragraph in doc.paragraphs:
        paragraph.space_before = spacing['before']
        paragraph.space_after = spacing['after']
        paragraph.line_spacing = 0.9  # Compact
        
        for run in paragraph.runs:
            if run.font.size >= Pt(20):
                run.font.size = preset['name']
            elif run.font.size >= Pt(11):
                run.font.size = preset['section']
            # ... etc

πŸ“ˆ Exemples de RΓ©sultats

Cas 1 : CV LΓ©ger (Volume < 18)

  • 1 expΓ©rience
  • 1 formation
  • 3 compΓ©tences
  • 2 langues

RΓ©sultat : Preset light, grandes polices, espacement confortable

Cas 2 : CV Moyen (Volume 18-25)

  • 2 expΓ©riences
  • 2 formations
  • 5 compΓ©tences
  • 3 langues
  • 3 hobbies

Résultat : Preset medium, polices légèrement réduites

Cas 3 : CV Dense (Volume 25-35)

  • 3 expΓ©riences avec descriptions dΓ©taillΓ©es
  • 3 formations
  • 8 compΓ©tences
  • 3 langues
  • 5 hobbies

RΓ©sultat : Preset dense, polices compactes, espacements minimaux

Cas 4 : CV Très Dense (Volume > 35)

  • 5+ expΓ©riences
  • 4+ formations
  • 10+ compΓ©tences

RΓ©sultat : Preset very_dense, tout est compressΓ© pour tenir sur 1 page


πŸ› οΈ Technologies UtilisΓ©es

Technologie RΓ΄le
docxtpl Moteur de template Jinja2 pour Word
python-docx Manipulation programmatique des documents Word
LibreOffice Conversion DOCX β†’ PDF (headless)
Pydantic Validation des donnΓ©es d'entrΓ©e
FastAPI API REST pour le service

πŸ“ Guide de CrΓ©ation de Template

Pour crΓ©er un nouveau template :

  1. Ouvrir Word/LibreOffice
  2. Designer votre CV avec le style souhaitΓ©
  3. Remplacer les donnΓ©es par les placeholders Jinja2 :
    • {{ full_name }} pour le nom
    • {% for exp in experiences %}...{% endfor %} pour les boucles
  4. Sauvegarder en .docx dans backend/app/templates/

Placeholders Disponibles

{# Informations personnelles #}
{{ full_name }}
{{ email }}
{{ phone }}
{{ address }}
{{ summary }}

{# ExpΓ©riences #}
{% for exp in experiences %}
  {{ exp.job_title }}
  {{ exp.company }}
  {{ exp.period }}
  {% for line in exp.description_lines %}
    {{ line }}
  {% endfor %}
{% endfor %}

{# Formation #}
{% for edu in education %}
  {{ edu.degree }}
  {{ edu.institution }}
  {{ edu.period }}
{% endfor %}

{# CompΓ©tences #}
{% for skill in skills %}
  {{ skill.display }}
{% endfor %}

{# Langues #}
{% for lang in languages %}
  {{ lang.display }}
{% endfor %}

{# Hobbies #}
{% for hobby in hobbies %}
  {{ hobby }}
{% endfor %}

🎯 Conclusion

Cette approche Template + Ajustement Automatique offre le meilleur des deux mondes :

  • FlexibilitΓ© du design : Le template Word permet n'importe quel style visuel
  • Garantie de pagination : L'ajustement automatique assure toujours 1 page
  • MaintenabilitΓ© : SΓ©paration claire entre design et logique
  • Γ‰volutivitΓ© : Facile d'ajouter de nouveaux templates ou presets

Documentation technique - Janvier 2026