Spaces:
Sleeping
π 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
GΓ©nΓ©ration automatique de rΓ©sumΓ© professionnel
- Analyse des expΓ©riences et compΓ©tences
- CrΓ©ation d'un profil percutant
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 :
- Template Word (docx) comme base de design
- Remplissage dynamique avec Jinja2/docxtpl
- 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 :
- Ouvrir Word/LibreOffice
- Designer votre CV avec le style souhaitΓ©
- Remplacer les donnΓ©es par les placeholders Jinja2 :
{{ full_name }}pour le nom{% for exp in experiences %}...{% endfor %}pour les boucles
- Sauvegarder en
.docxdansbackend/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