feat(M3): modèles de données Pydantic (22 modèles, 10 modules)
Modèles créés : - models/agenda.py : Status, LessonStatus, HomeworkBlock, Lesson (frozen), SchoolEventKind, SchoolEvent (frozen), TheoreticalLesson (frozen) - models/homework.py : Homework (frozen) - models/message.py : MessageType, Message (frozen) - models/blog.py : BlogArticle (frozen), ExternalInfo (mutable) - models/diff.py : AgendaChangeType, AgendaChange (frozen), AgendaDiff (frozen) - models/pronote.py : PronoteData (mutable) - models/sync.py : CalDAVSyncStatus, CalDAVSyncPlan, CalDAVSyncResult (mutable) - models/synthesis.py : SynthesisInput, SynthesisResult (mutable) - models/xmpp.py : XmppMessage (frozen, external_info: ExternalInfo | None) - models/__init__.py : ré-export des 22 modèles via __all__ Conventions appliquées : - Pydantic v2 : model_config = ConfigDict(frozen=True), pas de json_encoders - StrEnum au lieu de (str, Enum) (ruff UP042) - Alias _date/_time pour éviter collision champ date/type date - Sphinx/reST docstrings sur toutes les classes - TODO.md : 11 items M3 cochés Validations (@verifier) : - ruff check : PASS (0 error) - ruff format --check : PASS (10 fichiers) - mypy strict : PASS (10 fichiers) - bandit : PASS (0 issue) - import 22 modèles : OK - sérialisation JSON (frozen + mutable) : OK - frozen immuable, PronoteData/CalDAVSyncResult mutable : OK - StrEnum isinstance str : OK - pytest : 0 test (infrastructure OK) Co-authored-by: OpenCode/orchestrator <opencode-orchestrator@agents.invalid>
This commit is contained in:
22
TODO.md
22
TODO.md
@@ -50,17 +50,17 @@ Implémenter la configuration Pydantic Settings, le masquage des secrets et la j
|
|||||||
|
|
||||||
Définir tous les modèles de domaine, immuables pour les contrats, mutables pour les résultats de travail.
|
Définir tous les modèles de domaine, immuables pour les contrats, mutables pour les résultats de travail.
|
||||||
|
|
||||||
- [ ] Créer `models/agenda.py` : `Status`, `LessonStatus`, `HomeworkBlock`, `Lesson` (frozen), `SchoolEventKind`, `SchoolEvent`, `TheoreticalLesson`.
|
- [x] Créer `models/agenda.py` : `Status`, `LessonStatus`, `HomeworkBlock`, `Lesson` (frozen), `SchoolEventKind`, `SchoolEvent`, `TheoreticalLesson`.
|
||||||
- [ ] Créer `models/homework.py` : `Homework` (frozen, `id` = hachage stable).
|
- [x] Créer `models/homework.py` : `Homework` (frozen, `id` = hachage stable).
|
||||||
- [ ] Créer `models/message.py` : `MessageType`, `Message` (frozen).
|
- [x] Créer `models/message.py` : `MessageType`, `Message` (frozen).
|
||||||
- [ ] Créer `models/diff.py` : `AgendaChangeType`, `AgendaChange` (frozen), `AgendaDiff` (frozen).
|
- [x] Créer `models/diff.py` : `AgendaChangeType`, `AgendaChange` (frozen), `AgendaDiff` (frozen).
|
||||||
- [ ] Créer `models/pronote.py` : `PronoteData` (mutable).
|
- [x] Créer `models/pronote.py` : `PronoteData` (mutable).
|
||||||
- [ ] Créer `models/sync.py` : `CalDAVSyncStatus`, `CalDAVSyncPlan`, `CalDAVSyncResult` (mutable).
|
- [x] Créer `models/sync.py` : `CalDAVSyncStatus`, `CalDAVSyncPlan`, `CalDAVSyncResult` (mutable).
|
||||||
- [ ] Créer `models/synthesis.py` : `SynthesisInput`, `SynthesisResult`.
|
- [x] Créer `models/synthesis.py` : `SynthesisInput`, `SynthesisResult`.
|
||||||
- [ ] Créer `models/blog.py` : `BlogArticle` (frozen), `ExternalInfo` (§5 bis.5/6).
|
- [x] Créer `models/blog.py` : `BlogArticle` (frozen), `ExternalInfo` (§5 bis.5/6).
|
||||||
- [ ] Créer `models/xmpp.py` : `XmppMessage` (frozen) intégrant `external_info`.
|
- [x] Créer `models/xmpp.py` : `XmppMessage` (frozen) intégrant `external_info`.
|
||||||
- [ ] Créer `models/__init__.py` ré-exportant tous les modèles.
|
- [x] Créer `models/__init__.py` ré-exportant tous les modèles.
|
||||||
- [ ] Valider la sérialisation JSON (datetime/date en ISO) pour chaque modèle.
|
- [x] Valider la sérialisation JSON (datetime/date en ISO) pour chaque modèle.
|
||||||
|
|
||||||
### Critères d'acceptation
|
### Critères d'acceptation
|
||||||
- Chaque modèle s'instancie et se sérialise en JSON valide.
|
- Chaque modèle s'instancie et se sérialise en JSON valide.
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
"""Modèles de données Pydantic pour le pipeline pronote-sync."""
|
||||||
|
|
||||||
|
from pronote_sync.models.agenda import (
|
||||||
|
HomeworkBlock,
|
||||||
|
Lesson,
|
||||||
|
LessonStatus,
|
||||||
|
SchoolEvent,
|
||||||
|
SchoolEventKind,
|
||||||
|
Status,
|
||||||
|
TheoreticalLesson,
|
||||||
|
)
|
||||||
|
from pronote_sync.models.blog import BlogArticle, ExternalInfo
|
||||||
|
from pronote_sync.models.diff import AgendaChange, AgendaChangeType, AgendaDiff
|
||||||
|
from pronote_sync.models.homework import Homework
|
||||||
|
from pronote_sync.models.message import Message, MessageType
|
||||||
|
from pronote_sync.models.pronote import PronoteData
|
||||||
|
from pronote_sync.models.sync import CalDAVSyncPlan, CalDAVSyncResult, CalDAVSyncStatus
|
||||||
|
from pronote_sync.models.synthesis import SynthesisInput, SynthesisResult
|
||||||
|
from pronote_sync.models.xmpp import XmppMessage
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"AgendaChange",
|
||||||
|
"AgendaChangeType",
|
||||||
|
"AgendaDiff",
|
||||||
|
"BlogArticle",
|
||||||
|
"CalDAVSyncPlan",
|
||||||
|
"CalDAVSyncResult",
|
||||||
|
"CalDAVSyncStatus",
|
||||||
|
"ExternalInfo",
|
||||||
|
"Homework",
|
||||||
|
"HomeworkBlock",
|
||||||
|
"Lesson",
|
||||||
|
"LessonStatus",
|
||||||
|
"Message",
|
||||||
|
"MessageType",
|
||||||
|
"PronoteData",
|
||||||
|
"SchoolEvent",
|
||||||
|
"SchoolEventKind",
|
||||||
|
"Status",
|
||||||
|
"SynthesisInput",
|
||||||
|
"SynthesisResult",
|
||||||
|
"TheoreticalLesson",
|
||||||
|
"XmppMessage",
|
||||||
|
]
|
||||||
|
|||||||
90
pronote_sync/models/agenda.py
Normal file
90
pronote_sync/models/agenda.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
"""Modèles de données pour l'agenda Pronote (cours, événements, agenda théorique)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date as _date
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import time as _time
|
||||||
|
from enum import StrEnum
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
|
||||||
|
class Status(StrEnum):
|
||||||
|
"""Statut générique pour les événements."""
|
||||||
|
|
||||||
|
NORMAL = "normal"
|
||||||
|
CANCELLED = "cancelled"
|
||||||
|
MOVED = "moved"
|
||||||
|
|
||||||
|
|
||||||
|
class LessonStatus(StrEnum):
|
||||||
|
"""Statut d'un cours."""
|
||||||
|
|
||||||
|
NORMAL = "normal"
|
||||||
|
CANCELLED = "cancelled"
|
||||||
|
MOVED = "moved"
|
||||||
|
|
||||||
|
|
||||||
|
class HomeworkBlock(BaseModel):
|
||||||
|
"""Représente un bloc de devoir extrait de la description d'un cours."""
|
||||||
|
|
||||||
|
kind: Literal["due", "assigned"] = Field(
|
||||||
|
..., description="Type de bloc (échéance ou attribution)"
|
||||||
|
)
|
||||||
|
date: _date = Field(..., description="Date associée au bloc")
|
||||||
|
text: str = Field(..., description="Texte du devoir (brut)")
|
||||||
|
html: str = Field(default="", description="Texte du devoir (HTML)")
|
||||||
|
|
||||||
|
|
||||||
|
class Lesson(BaseModel):
|
||||||
|
"""Représente un cours dans l'agenda Pronote."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
id: str = Field(..., description="UID stable du cours (normalisé)")
|
||||||
|
start: datetime = Field(..., description="Date/heure de début")
|
||||||
|
end: datetime = Field(..., description="Date/heure de fin")
|
||||||
|
subject: str = Field(..., description="Matière")
|
||||||
|
teachers: list[str] = Field(default_factory=list, description="Liste des professeurs")
|
||||||
|
rooms: list[str] = Field(default_factory=list, description="Liste des salles")
|
||||||
|
group: str | None = Field(None, description="Groupe (ex: Classe entière)")
|
||||||
|
status: LessonStatus = Field(default=LessonStatus.NORMAL, description="Statut du cours")
|
||||||
|
content: str | None = Field(None, description="Contenu pédagogique")
|
||||||
|
homework_blocks: list[HomeworkBlock] = Field(
|
||||||
|
default_factory=list,
|
||||||
|
description="Blocs de devoirs extraits de la description",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolEventKind(StrEnum):
|
||||||
|
"""Type d'événement scolaire."""
|
||||||
|
|
||||||
|
HOLIDAY = "holiday"
|
||||||
|
PUBLIC_HOLIDAY = "public_holiday"
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolEvent(BaseModel):
|
||||||
|
"""Représente un événement scolaire (vacances, jours fériés)."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
kind: SchoolEventKind = Field(..., description="Type d'événement")
|
||||||
|
label: str = Field(..., description="Libellé (ex: Vacances de Noël)")
|
||||||
|
from_date: _date = Field(..., description="Date de début (inclusive)")
|
||||||
|
to_date: _date = Field(..., description="Date de fin (exclusive)")
|
||||||
|
|
||||||
|
|
||||||
|
class TheoreticalLesson(BaseModel):
|
||||||
|
"""Représente un cours dans l'agenda théorique."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
id: str = Field(..., description="Identifiant unique")
|
||||||
|
day_of_week: int = Field(..., description="Jour de la semaine (0=lundi, 6=dimanche)")
|
||||||
|
start_time: _time = Field(..., description="Heure de début")
|
||||||
|
end_time: _time = Field(..., description="Heure de fin")
|
||||||
|
subject: str = Field(..., description="Matière")
|
||||||
|
teachers: list[str] = Field(default_factory=list, description="Liste des professeurs")
|
||||||
|
rooms: list[str] = Field(default_factory=list, description="Liste des salles")
|
||||||
42
pronote_sync/models/blog.py
Normal file
42
pronote_sync/models/blog.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""Modèles de données pour le blog du collège (RSS) et les informations externes."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
from pronote_sync.models.message import Message
|
||||||
|
|
||||||
|
|
||||||
|
class BlogArticle(BaseModel):
|
||||||
|
"""Représente un article du blog du collège."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
id: str = Field(..., description="GUID de l'article (clé de déduplication)")
|
||||||
|
title: str = Field(..., description="Titre de l'article")
|
||||||
|
url: str = Field(..., description="URL canonique de l'article")
|
||||||
|
published_at: datetime = Field(..., description="Date de publication (UTC)")
|
||||||
|
updated_at: datetime | None = Field(None, description="Date de dernière mise à jour")
|
||||||
|
category: str | None = Field(None, description="Catégorie de l'article")
|
||||||
|
author: str | None = Field(None, description="Auteur (si disponible)")
|
||||||
|
content_html: str = Field(..., description="Contenu HTML complet")
|
||||||
|
content_text: str = Field(..., description="Contenu en texte brut (pour XMPP)")
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalInfo(BaseModel):
|
||||||
|
"""Agrège les informations externes (blog, messages Pronote) pour le message XMPP."""
|
||||||
|
|
||||||
|
blog_articles: list[BlogArticle] = Field(
|
||||||
|
default_factory=list,
|
||||||
|
description="Liste des nouveaux articles du blog",
|
||||||
|
)
|
||||||
|
pronote_messages: list[Message] = Field(
|
||||||
|
default_factory=list,
|
||||||
|
description="Liste des messages Pronote",
|
||||||
|
)
|
||||||
|
other_info: list[str] = Field(
|
||||||
|
default_factory=list,
|
||||||
|
description="Autres informations (extensible)",
|
||||||
|
)
|
||||||
40
pronote_sync/models/diff.py
Normal file
40
pronote_sync/models/diff.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"""Modèles de données pour la comparaison d'agenda (diff)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
from pronote_sync.models.agenda import Lesson, TheoreticalLesson
|
||||||
|
|
||||||
|
|
||||||
|
class AgendaChangeType(StrEnum):
|
||||||
|
"""Type de changement dans l'agenda."""
|
||||||
|
|
||||||
|
ADDED = "added"
|
||||||
|
REMOVED = "removed"
|
||||||
|
MODIFIED = "modified"
|
||||||
|
|
||||||
|
|
||||||
|
class AgendaChange(BaseModel):
|
||||||
|
"""Représente un changement entre l'agenda réel et l'agenda théorique."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
type: AgendaChangeType = Field(..., description="Type de changement")
|
||||||
|
lesson: Lesson | None = Field(None, description="Cours concerné (pour ADDED/MODIFIED)")
|
||||||
|
theoretical_lesson: TheoreticalLesson | None = Field(
|
||||||
|
None, description="Cours théorique concerné (pour REMOVED/MODIFIED)"
|
||||||
|
)
|
||||||
|
details: str = Field(default="", description="Détails du changement")
|
||||||
|
|
||||||
|
|
||||||
|
class AgendaDiff(BaseModel):
|
||||||
|
"""Représente les différences entre l'agenda réel et l'agenda théorique."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
target_date: date = Field(..., description="Date cible de la comparaison")
|
||||||
|
changes: list[AgendaChange] = Field(default_factory=list, description="Liste des changements")
|
||||||
21
pronote_sync/models/homework.py
Normal file
21
pronote_sync/models/homework.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
"""Modèle de données pour les devoirs Pronote."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
|
||||||
|
class Homework(BaseModel):
|
||||||
|
"""Représente un devoir Pronote."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
id: str = Field(..., description="ID stable (hachage)")
|
||||||
|
subject: str = Field(..., description="Matière")
|
||||||
|
teachers: list[str] = Field(default_factory=list, description="Liste des professeurs")
|
||||||
|
assigned_on: date | None = Field(None, description="Date de distribution")
|
||||||
|
due_on: date = Field(..., description="Date d'échéance")
|
||||||
|
text: str = Field(..., description="Texte du devoir (brut)")
|
||||||
|
html: str = Field(default="", description="Texte du devoir (HTML)")
|
||||||
30
pronote_sync/models/message.py
Normal file
30
pronote_sync/models/message.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
"""Modèle de données pour les messages Pronote."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
|
||||||
|
class MessageType(StrEnum):
|
||||||
|
"""Type de message Pronote."""
|
||||||
|
|
||||||
|
DISCUSSION = "discussion"
|
||||||
|
INFORMATION = "information"
|
||||||
|
SURVEY = "survey"
|
||||||
|
|
||||||
|
|
||||||
|
class Message(BaseModel):
|
||||||
|
"""Représente un message ou une information Pronote."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
id: str = Field(..., description="Identifiant unique")
|
||||||
|
type: MessageType = Field(..., description="Type de message")
|
||||||
|
title: str = Field(..., description="Titre")
|
||||||
|
content: str = Field(..., description="Contenu")
|
||||||
|
author: str = Field(..., description="Auteur")
|
||||||
|
date: datetime = Field(..., description="Date de création")
|
||||||
|
read: bool = Field(False, description="Lu ou non")
|
||||||
26
pronote_sync/models/pronote.py
Normal file
26
pronote_sync/models/pronote.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"""Modèle de données normalisées récupérées depuis Pronote."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from pronote_sync.models.agenda import Lesson, SchoolEvent
|
||||||
|
from pronote_sync.models.homework import Homework
|
||||||
|
from pronote_sync.models.message import Message
|
||||||
|
|
||||||
|
|
||||||
|
class PronoteData(BaseModel):
|
||||||
|
"""Données normalisées récupérées depuis Pronote."""
|
||||||
|
|
||||||
|
lessons: list[Lesson] = Field(default_factory=list, description="Liste des cours")
|
||||||
|
homeworks: list[Homework] = Field(default_factory=list, description="Liste des devoirs")
|
||||||
|
school_events: list[SchoolEvent] = Field(
|
||||||
|
default_factory=list, description="Liste des événements scolaires"
|
||||||
|
)
|
||||||
|
messages: list[Message] = Field(
|
||||||
|
default_factory=list, description="Liste des messages/informations"
|
||||||
|
)
|
||||||
|
target_date: date = Field(..., description="Date cible (J+1 ou prochain jour scolaire)")
|
||||||
|
generated_at: datetime = Field(..., description="Date/heure de génération")
|
||||||
42
pronote_sync/models/sync.py
Normal file
42
pronote_sync/models/sync.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""Modèles de données pour la synchronisation CalDAV."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from pronote_sync.models.agenda import Lesson, SchoolEvent
|
||||||
|
from pronote_sync.models.homework import Homework
|
||||||
|
|
||||||
|
|
||||||
|
class CalDAVSyncStatus(StrEnum):
|
||||||
|
"""Statut de synchronisation CalDAV."""
|
||||||
|
|
||||||
|
SUCCESS = "success"
|
||||||
|
FAILED = "failed"
|
||||||
|
SKIPPED = "skipped"
|
||||||
|
|
||||||
|
|
||||||
|
class CalDAVSyncPlan(BaseModel):
|
||||||
|
"""Plan de synchronisation CalDAV."""
|
||||||
|
|
||||||
|
lessons_to_add: list[Lesson] = Field(default_factory=list)
|
||||||
|
lessons_to_update: list[Lesson] = Field(default_factory=list)
|
||||||
|
lessons_to_remove: list[str] = Field(default_factory=list, description="Liste d'UID")
|
||||||
|
homeworks_to_add: list[Homework] = Field(default_factory=list)
|
||||||
|
homeworks_to_update: list[Homework] = Field(default_factory=list)
|
||||||
|
homeworks_to_remove: list[str] = Field(default_factory=list, description="Liste d'UID")
|
||||||
|
school_events_to_add: list[SchoolEvent] = Field(default_factory=list)
|
||||||
|
school_events_to_update: list[SchoolEvent] = Field(default_factory=list)
|
||||||
|
school_events_to_remove: list[str] = Field(default_factory=list, description="Liste d'UID")
|
||||||
|
|
||||||
|
|
||||||
|
class CalDAVSyncResult(BaseModel):
|
||||||
|
"""Résultat d'une synchronisation CalDAV (mutable)."""
|
||||||
|
|
||||||
|
status: CalDAVSyncStatus = Field(..., description="Statut global")
|
||||||
|
added: int = Field(0, description="Nombre d'événements ajoutés")
|
||||||
|
updated: int = Field(0, description="Nombre d'événements mis à jour")
|
||||||
|
removed: int = Field(0, description="Nombre d'événements supprimés")
|
||||||
|
errors: list[str] = Field(default_factory=list, description="Liste des erreurs")
|
||||||
28
pronote_sync/models/synthesis.py
Normal file
28
pronote_sync/models/synthesis.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
"""Modèles de données pour la synthèse IA."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from pronote_sync.models.agenda import SchoolEvent
|
||||||
|
from pronote_sync.models.diff import AgendaDiff
|
||||||
|
from pronote_sync.models.message import Message
|
||||||
|
|
||||||
|
|
||||||
|
class SynthesisInput(BaseModel):
|
||||||
|
"""Entrée pour la synthèse IA."""
|
||||||
|
|
||||||
|
agenda_diff: AgendaDiff | None = Field(None, description="Différences d'agenda")
|
||||||
|
messages: list[Message] = Field(default_factory=list, description="Messages importants")
|
||||||
|
school_events: list[SchoolEvent] = Field(
|
||||||
|
default_factory=list, description="Événements scolaires"
|
||||||
|
)
|
||||||
|
target_date: date = Field(..., description="Date cible")
|
||||||
|
|
||||||
|
|
||||||
|
class SynthesisResult(BaseModel):
|
||||||
|
"""Résultat de la synthèse IA."""
|
||||||
|
|
||||||
|
text: str | None = Field(None, description="Texte de la synthèse IA")
|
||||||
31
pronote_sync/models/xmpp.py
Normal file
31
pronote_sync/models/xmpp.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"""Modèle de données pour le message XMPP final."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
from pronote_sync.models.blog import ExternalInfo
|
||||||
|
from pronote_sync.models.diff import AgendaChange
|
||||||
|
from pronote_sync.models.homework import Homework
|
||||||
|
from pronote_sync.models.message import Message
|
||||||
|
|
||||||
|
|
||||||
|
class XmppMessage(BaseModel):
|
||||||
|
"""Représente le message final à envoyer par XMPP."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
target_date: date = Field(..., description="Date cible")
|
||||||
|
synthesis: str | None = Field(None, description="Synthèse IA (optionnelle, 3-5 phrases)")
|
||||||
|
homeworks: list[Homework] = Field(default_factory=list, description="Liste brute des devoirs")
|
||||||
|
changes: list[AgendaChange] = Field(
|
||||||
|
default_factory=list, description="Liste des changements d'agenda"
|
||||||
|
)
|
||||||
|
messages: list[Message] = Field(
|
||||||
|
default_factory=list, description="Liste des messages/informations"
|
||||||
|
)
|
||||||
|
external_info: ExternalInfo | None = Field(
|
||||||
|
None, description="Informations externes (blog, messages Pronote)"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user