This commit is contained in:
el 2025-06-24 18:17:53 +02:00
commit d7666f7b2c
44 changed files with 2246 additions and 0 deletions

View file

View file

@ -0,0 +1,23 @@
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional
class AiInteractionBase(BaseModel):
job_offer_text: str
cv_text_used: Optional[str] = None
interaction_type: str = "scoring" # Valeur par défaut
class AiInteractionCreate(AiInteractionBase):
ai_request: str
ai_response: str
score: Optional[float] = None
analysis_results: Optional[str] = None
user_id: Optional[int] = None
document_id: Optional[int] = None
class AiInteractionResponse(AiInteractionCreate):
id: int
created_at: datetime
class Config:
from_attributes = True

View file

@ -0,0 +1,23 @@
from pydantic import BaseModel, Field
from datetime import datetime
class DocumentBase(BaseModel):
filename: str
class DocumentCreate(DocumentBase):
# Pas besoin de filepath ici, il sera généré par le backend
pass
class DocumentResponse(DocumentBase):
id: int
filepath: str
owner_id: int
uploaded_at: datetime
class Config:
from_attributes = True
class DocumentDeleteResponse(BaseModel):
detail: str
filename: str
id: int

View file

@ -0,0 +1,110 @@
# backend/schemas/france_travail.py
from datetime import datetime
from typing import List, Optional, Dict, Any, Union
from pydantic import BaseModel, Field, field_validator, computed_field
# Modèles de données pour les structures communes (Lieu, Entreprise, etc.)
class LieuTravail(BaseModel):
libelle: Optional[str] = Field(None, example="Paris")
codePostal: Optional[str] = Field(None, example="75001")
commune: Optional[str] = Field(None, example="Paris")
class TypeContrat(BaseModel):
code: Optional[str] = Field(None, example="CDI")
libelle: Optional[str] = Field(None, example="Contrat à durée indéterminée")
class Appellation(BaseModel):
code: Optional[str] = Field(None, example="10034")
libelle: Optional[str] = Field(None, example="Développeur informatique")
class OrigineOffre(BaseModel):
url: Optional[str] = Field(None, example="https://candidat.francetravail.fr/candidature/offre/1234567")
typeOrigine: Optional[str] = Field(None, example="ONLINE")
class Entreprise(BaseModel):
nom: Optional[str] = Field(None, example="Ma Super Entreprise")
description: Optional[str] = None
url: Optional[str] = None
id: Optional[str] = None
class Salaire(BaseModel):
libelle: Optional[str] = Field(None, example="2500 EUR brut/mois")
commentaire: Optional[str] = None
typeForfait: Optional[str] = None
periode: Optional[str] = None
min: Optional[float] = None
max: Optional[float] = None
class Competence(BaseModel):
code: Optional[str] = None
libelle: Optional[str] = None
description: Optional[str] = None
exigence: Optional[str] = None
class Experience(BaseModel):
libelle: Optional[str] = Field(None, example="Débutant accepté")
code: Optional[str] = None
class Formation(BaseModel):
domaineLibelle: Optional[str] = None
niveaulibelle: Optional[str] = None
codeFormation: Optional[str] = None
class Permis(BaseModel):
libelle: Optional[str] = None
code: Optional[str] = None
# Modèle pour une offre individuelle
class Offre(BaseModel):
id: str = Field(..., example="1234567")
intitule: str = Field(..., example="Développeur Full Stack")
description: Optional[str] = None
dateCreation: datetime
dateActualisation: datetime
lieuTravail: Optional[LieuTravail] = None
typeContrat: Optional[Union[TypeContrat, str]] = None
romeCode: Optional[str] = None
romeLibelle: Optional[str] = None
appellationLibelle: Optional[str] = None
entreprise: Optional[Entreprise] = None
origineOffre: Optional[OrigineOffre] = None
nbPostes: Optional[int] = None
nbResultats: Optional[int] = None
@field_validator('typeContrat', mode='before')
@classmethod
def validate_type_contrat(cls, v: Any) -> Any:
if isinstance(v, str):
return TypeContrat(code=v, libelle=None)
return v
class Config:
from_attributes = True
# AJOUTEZ CETTE PROPRIÉTÉ CALCULÉE
@computed_field
def url_francetravail(self) -> str:
"""Génère l'URL de l'offre sur le site candidat.francetravail.fr."""
return f"https://candidat.francetravail.fr/offres/recherche/detail/{self.id}"
# Modèle pour les détails complets d'une offre
class OffreDetail(Offre):
# OffreDetail hérite de Offre, donc il aura automatiquement la propriété url_francetravail
description: str = Field(..., example="Description détaillée du poste...")
complementExercice: Optional[str] = None
urlDossierCandidature: Optional[str] = None # Ce champ vient directement de l'API s'il est fourni
qualification: Optional[str] = None
appellations: Optional[List[Appellation]] = None
competences: Optional[List[Competence]] = None
entreprise: Optional[Entreprise] = None
formations: Optional[List[Formation]] = None
langues: Optional[List[Dict[str, Any]]] = None
permis: Optional[List[Permis]] = None
class Config:
from_attributes = True
class FranceTravailSearchResponse(BaseModel):
resultats: List[Offre] = Field(default_factory=list)
totalResults: Optional[int] = Field(None, description="Nombre total d'offres correspondant aux critères")
range: Optional[str] = Field(None, description="Plage des résultats actuels, ex: '0-14/100'")

10
backend/schemas/token.py Normal file
View file

@ -0,0 +1,10 @@
# backend/schemas/token.py
from pydantic import BaseModel
from typing import Optional
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
email: Optional[str] = None

23
backend/schemas/user.py Normal file
View file

@ -0,0 +1,23 @@
from pydantic import BaseModel, EmailStr
from typing import Optional
from datetime import datetime
class UserBase(BaseModel):
email: EmailStr
class UserCreate(UserBase):
password: str
name: Optional[str] = None # Conforme au PRD: nom/prénom optionnels
class UserLogin(UserBase):
password: str
class UserResponse(UserBase):
id: int
is_active: bool
created_at: datetime
updated_at: datetime
name: Optional[str] = None
class Config:
from_attributes = True # Ancien orm_mode = True pour Pydantic v2+