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 |
```python
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 :
```python
# 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 :
```python
# 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 :
```python
# 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 :
```python
# 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
```python
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 :
```python
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
```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
```bash
# 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** :
```python
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 :
```python
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é
```python
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
```jinja2
{# 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*