Skip to content

CHU-Brest/Stream

Repository files navigation

Stream

Python CC BY-NC-SA 4.0

Génération de comptes rendus d'hospitalisation (CRH) synthétiques à partir de statistiques PMSI nationales et de modèles de langage (LLM).

Stream unifie plusieurs méthodes de génération au sein d'une architecture commune, chacune étant implémentée sous forme de pipeline :

Pipeline Source de données Méthode Statut
Brest ATIH (Base nationale) Tirage pondéré DP/CCAM/DAS/DMS + LLM Implémenté
AP-HP ATIH (Base nationale) Tirage pondéré PMSI + LLM Implémenté

Projets de référence : Doppelgänger (CHU Brest) et Recode-Scenario (AP-HP).

Architecture

Stream/
├── cli.py                        # Point d'entrée CLI
├── runner.py                     # Orchestration du pipeline
├── core/
│   ├── config.py                 # Chargement YAML
│   ├── logger.py                 # Logger console
│   └── clients.py                # Definition des clients de connexion (Ollama, Mistral, Antropic)
├── pipelines/
│   ├── __init__.py               # Expose les pipelines et modules communs
│   ├── pipeline.py               # Classes de base et clients LLM
│   ├── fictive.py               # Génération de séjours fictifs (Brest/AP-HP)
│   ├── scenario.py              # Transformation en scénarios textuels
│   ├── report.py                # Génération de rapports CRH via LLM
│   ├── brest/
│   │   ├── __init__.py           # Expose BrestPipeline, constants, sampler
│   │   ├── pipeline.py           # Pipeline Brest spécifique
│   │   ├── constants.py          # Constantes et sources de données
│   │   ├── fictive.py            # Création de CR fictif
│   │   ├── report.py             # Création de rapport
│   │   └── sampler.py            # Échantillonnage et génération aléatoire
│   └── aphp/
│       ├── __init__.py           # Expose les modules AP-HP et APHPPipeline
│       ├── pipeline.py           # Pipeline AP-HP spécifique
│       ├── loader.py             # Chargement des référentiels et données PMSI
│       ├── scenario.py           # Construction des scénarios cliniques
│       ├── managment.py          # Classification des types de prise en charge
│       ├── prompt.py             # Génération des prompts utilisateur et système
│       ├── sampler.py            # Échantillonnage et génération aléatoire
│       ├── constants.py          # Constantes et listes de codes
│       ├── fictive.py            # Création de CR fictif
│       ├── report.py             # Création de rapport
│       ├── referentials/         # Référentiels AP-HP (ICD-10, CCAM, GHM, etc.)
│       └── templates/            # Modèles de prompts système
└── config/
    ├── prompts.yaml              # System prompts LLM
    └── servers.example.yaml      # Template config (copier vers servers.yaml)

Installation

Avec pip :

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Avec uv:

uv venv
source .venv/bin/activate
uv sync

Configuration

Copier le template et renseigner vos clés API :

cp config/servers.example.yaml config/servers.yaml

Éditer config/servers.yaml :

pipelines:
  brest:
    data:
      input: "data/brest/"       # CSV PMSI extraits via SAS
      output: "reports/brest/"   # CRH générés
  aphp:
    data:
      input: "data/aphp/"                    # Fichiers PMSI AP-HP
      output: "reports/aphp/"                # CRH générés
      referentials: "data/aphp/referentials" # Référentiels AP-HP

    generation:
      mode: "direct"           # direct ou mistral_batch
      max_tokens: 4096         # Nombre maximum de tokens par requête
      poll_interval_seconds: 1 # Intervalle de polling en secondes

servers:
  ollama:
    host: "http://localhost:11434"
    model: "mistral"
  claude:
    api_key: "sk-..."
    model: "claude-sonnet-4-6"
  mistral:
    api_key: "..."
    model: "mistral-large-latest"

Pour reproduire la méthode historique AP-HP avec Mistral, le pipeline AP-HP peut être lancé en mode batch Mistral :

pipelines:
  aphp:
    generation:
      mode: "mistral_batch"
      max_tokens: 128000
      poll_interval_seconds: 1

Ce mode est spécifique au client mistral. Le mode direct reste le mode par défaut et fonctionne avec Ollama, Claude et Mistral.

Données d'entrée (pipeline Brest)

Déposer les CSV suivants dans le répertoire data.input configuré :

Fichier Contenu
PMSI_DP.csv Probabilités P(DP | GHM5)
PMSI_DAS.csv Probabilités P(DAS | GHM5, AGE, SEXE, DP)
PMSI_CCAM_DP.csv Probabilités P(CCAM | GHM5, DP)
PMSI_DMS.csv Durées de séjour (P25, P50, P75)
ALL_CIM10.csv Référentiel diagnostics CIM-10
ALL_CCAM.csv Référentiel actes CCAM
ALL_CLASSIF_PMSI.csv Référentiel GHM

Ces fichiers sont produits par les scripts d'extraction ATIH spécifiques au CHU Brest.

Données d'entrée (pipeline AP-HP)

Déposer les fichiers suivants dans le répertoire data.input configuré :

Fichier Contenu
scenarios_*.parquet Profils PMSI avec diagnostics principaux et associés
bn_pmsi_related_diag_*.csv Diagnostics associés par GHM
bn_pmsi_procedures_*.csv Actes CCAM par GHM

Ces fichiers sont produits par les scripts d'extraction ATIH spécifiques à l'AP-HP. Les référentiels AP-HP doivent être placés dans data.referentials.

Utilisation

# Générer 500 CRH avec Ollama (local)
python cli.py brest --n-sejours 500

# Générer avec Claude, filtré sur les GHM chirurgicaux "06C"
python cli.py brest --client claude --n-sejours 1000 --ghm5 06C

# Générer avec Mistral, 3 actes CCAM max, 4 DAS max
python cli.py brest --client mistral --n-ccam 3 --n-das 4
# Générer 2 CRH AP-HP avec le mode direct par défaut
python cli.py aphp --n-sejours 2

# Générer des CRH AP-HP avec Claude
python cli.py aphp --client claude --n-sejours 10

# Générer des CRH AP-HP avec Mistral en mode direct
python cli.py aphp --client mistral --n-sejours 10

Options

Option Défaut Description
pipeline brest ou aphp
--client ollama ollama, claude ou mistral
--n-sejours 1000 Nombre de séjours fictifs
--n-ccam 1 Nombre max d'actes CCAM par séjour (Brest uniquement)
--n-das 5 Nombre max de diagnostics associés (Brest uniquement)
--ghm5 Filtre sur les codes GHM5 (ex. 06C)
--batch-size 1000 Lignes par fichier Parquet de sortie

Sortie

Les sorties sont écrites en fichiers Parquet horodatés dans le répertoire data.output.

Pour les générations classiques :

reports/brest/medical_reports_1000_20260405_143022.parquet
reports/aphp/medical_reports_10_20260512_113644.parquet

Pour le pipeline AP-HP, les scénarios complets sont également sauvegardés avant l’appel au LLM :

reports/aphp/generated_scenarios_10_20260512_113402.parquet

Ces fichiers contiennent notamment les diagnostics, DAS, actes, règle de codage, template, scenario, user_prompt, system_prompt, prefix et prefix_len.

En mode Mistral batch AP-HP, les sorties sont sauvegardées séparément :

reports/aphp/aphp_mistral_batch_reports_10_20260512_115347.parquet

Schéma minimal des sorties CRH : generation_id, scenario, report, model, timestamp.

Les sorties AP-HP peuvent contenir des colonnes supplémentaires utiles au debug et à la comparaison avec la méthode historique AP-HP.

Tests

Pour exécuter les tests unitaires, utilisez la commande suivante :

python -m  tests/ -v

ou plus simplement à l'aide du Makefile

make test

Les tests couvrent :

  • L'initialisation des pipelines Brest et AP-HP
  • La vérification des données d'entrée
  • L'intégration des pipelines avec le runner

Architecture des Pipelines

Les pipelines suivent une architecture modulaire avec trois étapes principales :

get_fictive() → get_scenario() → get_report()
  1. get_fictive() : Génère des séjours fictifs à partir des données chargées.
  2. get_scenario() : Transforme les séjours fictifs en scénarios textuels pour le LLM.
  3. get_report() : Génère les comptes rendus d'hospitalisation (CRH) à partir des scénarios.

Modules communs

Trois nouveaux modules ont été ajoutés pour centraliser la logique commune entre les pipelines :

pipelines/fictive.py

Module responsable de la génération de séjours fictifs à partir des données PMSI.

Fonction principale :

  • generate_fictive_stays(data, n_sejours, generate_fn, **kwargs)

Responsabilités :

  • Génération de séjours fictifs pour les pipelines Brest et AP-HP
  • Logique d'échantillonnage spécifique à chaque pipeline
  • Réduction de la duplication de code

pipelines/scenario.py

Module responsable de la transformation des séjours fictifs en scénarios textuels pour les LLM.

Fonction principale :

  • format_scenarios(df, scenario_fn, **kwargs)

Responsabilités :

  • Transformation des séjours en prompts textuels
  • Formatage spécifique Brest (simple) et AP-HP (riche)
  • Gestion des templates et règles ATIH

pipelines/report.py

Module responsable de la génération de rapports CRH via appels LLM.

Fonction principale :

  • generate_reports(df, client, model, batch_size, output_dir, generate_fn)

Responsabilités :

  • Interaction avec les clients LLM (Anthropic, Mistral, Ollama)
  • Gestion des batches et persistance des résultats
  • Formatage des réponses LLM

Comparaison des Pipelines

flowchart TD
    subgraph Source["Source de données (ATIH)"]
        A["Base nationale ATIH"]
    end

    subgraph Brest["Pipeline Brest"]
        B1["Extraction CHU Brest"] --> B2["CSV: DP/DAS/DMS/CCAM"]
        B2 --> B3["Tirage pondéré simple"]
        B3 --> B4["Scénarios génériques"]
        B4 --> B5["Templates LLM basiques"]
    end

    subgraph APHP["Pipeline AP-HP"]
        A2["Extraction AP-HP"] --> A3["Parquet: Scénarios PMSI"]
        A3 --> A4["Tirage + règles ATIH"]
        A4 --> A5["Scénarios enrichis"]
        A5 --> A6["Templates LLM spécifiques"]
        A6 --> A7["Validation ATIH"]
    end

    A --> B1
    A --> A2

    style Source fill:#f9f,stroke:#333
    style Brest fill:#bbf,stroke:#333
    style APHP fill:#bfb,stroke:#333
Loading

Différences clés

Aspect Pipeline Brest (CHU Brest) Pipeline AP-HP (Paris)
Extraction Scripts CHU Brest Scripts AP-HP spécifiques
Format CSV (DP/DAS/DMS/CCAM) Parquet (scénarios PMSI)
Tirage Pondéré simple Pondéré + règles ATIH
Modules fictive.py, scenario.py + report.py personnalisé
Classification Basique MCO/SSR/HAD (managment.py)
Validation Standard Règles ATIH spécifiques
Templates Génériques Spécifiques AP-HP
Complexité Simple Sur-couche métier

Intégration dans les pipelines

Les pipelines Brest et AP-HP ont été mis à jour pour utiliser ces modules communs :

Brest Pipeline

class BrestPipeline(BasePipeline):
    @override
    def get_fictive(self, data, **kwargs):
        return generate_fictive_stays(data, generate_fn=generate_brest_fictive, **kwargs)

    @override
    def get_scenario(self, df):
        return format_scenarios(df, scenario_fn=format_brest_scenario)

     @override
    def get_report(
        self,
        df: pl.DataFrame,
        client: AnthropicClient | MistralClient | OllamaClient,
        model: str,
        batch_size: int = 1000,
    ) -> pl.DataFrame:
        output_dir = Path(self.config["data"]["output"])
        system_prompt = self.prompt["generate"]["system_prompt"]
        return generate_reports(
            df=df,
            client=client,
            model=model,
            generate_fn=generate_brest_report,
            batch_size=batch_size,
            output_dir=output_dir,
            system_prompt=system_prompt,
        )

AP-HP Pipeline

Le pipeline AP-HP utilise les modules communs avec une sur-couche spécifique pour la génération de rapports. Cette sur-couche implémente la logique métier AP-HP pour :

  • Gestion des référentiels ATIH : Chargement et validation des codes ICD-10, CCAM et GHM spécifiques à l'AP-HP
  • Classification des prises en charge : Application des règles de managment (MCO, SSR, HAD) selon les référentiels ATIH
  • Génération de prompts enrichis : Intégration des templates système spécifiques AP-HP avec règles de formatage ATIH
  • Validation des scénarios : Vérification de la cohérence clinique selon les règles métiers AP-HP
class APHPPipeline(BasePipeline):
    @override
    def get_fictive(self, data, **kwargs):
        return generate_fictive_stays(data, generate_fn=generate_aphp_ficitive, **kwargs)
    
    @override
    def get_scenario(self, df):
        return format_scenarios(df, scenario_fn=format_aphp_scenario, **kwargs)
    
    @override
    def get_report(
        self,
        df: pl.DataFrame,
        client: Any,
        model: str,
        batch_size: int = 1000,
    ) -> pl.DataFrame:
        """Generate one CRH per scenario using the row's own system prompt.

        Overrides :meth:`~pipelines.pipeline.BasePipeline.get_report` to read
        ``df_row["system_prompt"]`` instead of a single global system prompt.
        """
        output_dir = Path(self.config["data"]["output"])
        return generate_reports(
            df,
            client,
            model,
            batch_size=batch_size,
            output_dir=output_dir,
            generate_fn=generate_aphp_report,
            system_prompt="",  # just for signature since system from is in the df in the function generate_aphp_report
        )

Ajouter un pipeline

Créer une classe héritant de BasePipeline et implémenter les 4 méthodes :

from pipelines.pipeline import BasePipeline

class MonPipeline(BasePipeline):
    name = "mon_pipeline"

    def check_data(self) -> None:
        """Verify that source data is present and prepare it if needed."""
        # Ajoutez des messages de log pour faciliter le débogage
        self.logger.info("Vérification des données d'entrée pour le pipeline %s.", self.name)
        # Votre logique de vérification des données ici
        self.logger.info("Données vérifiées avec succès.")

    def load_data(self) -> dict[str, pl.LazyFrame]:
        """Load prepared data as LazyFrames."""
        # Ajoutez des messages de log pour suivre le chargement des données
        self.logger.info("Chargement des données pour le pipeline %s.", self.name)
        # Votre logique de chargement des données ici
        self.logger.info("Données chargées avec succès.")
        return {}

    def get_fictive(self, data, **kwargs) -> pl.DataFrame:
        """Generate fictitious hospital stays from loaded data."""
        # Ajoutez des messages de log pour suivre la génération des séjours fictifs
        self.logger.info("Génération de %d séjours fictifs.", kwargs.get("n_sejours", 1000))
        # Votre logique de génération des séjours fictifs ici
        self.logger.info("Génération des séjours fictifs terminée avec succès.")
        return pl.DataFrame()

    def get_scenario(self, df) -> pl.DataFrame:
        """Transform fictitious stays into text scenarios for the LLM."""
        # Ajoutez des messages de log pour suivre le formatage des scénarios
        self.logger.info("Formatage des scénarios pour %d séjours.", len(df))
        # Votre logique de formatage des scénarios ici
        self.logger.info("Formatage des scénarios terminé avec succès.")
        return df

Puis l'enregistrer dans runner.py (PIPELINES) et cli.py (choices).

Roadmap de fusion

gantt
    title Roadmap de fusion des pipelines
    dateFormat  YYYY-MM
    section Étapes techniques
    Unification interfaces       :a1, 2024-05, 2024-06
    Refactoring ciblé            :a2, 2024-06, 2024-07
    Validation complète          :a3, 2024-07, 2024-08
    section Décisions architecturales
    Référentiels                :crit1, 2024-05, 2024-05
    Règles métiers               :crit2, 2024-05, 2024-06
    Validation données           :crit3, 2024-06, 2024-06
    Templates LLM                :crit4, 2024-06, 2024-07
    section Livraison
    Intégration continue         :2024-07, 2024-08
    Documentation finale         :2024-08, 2024-08
Loading

Détails des étapes

1. Unification des interfaces (Mai-Juin 2024)

  • Aligner get_report() entre pipelines
  • Standardiser les structures de données
  • Créer des adaptateurs pour les spécificités

2. Refactoring ciblé (Juin-Juillet 2024)

  • Extraire la logique métier AP-HP
  • Documenter les divergences nécessaires
  • Optimiser les performances

3. Validation complète (Juillet-Août 2024)

  • Tests d'intégration croisés Brest/AP-HP
  • Benchmarking comparatif
  • Validation des données et cohérence

Décisions architecturales clés

mindmap
  root((Décisions architecturales))
    Référentiels
      Séparés (Brest/AP-HP)
      Unifiés avec mappings
      Système de plugins
    Règles métiers
      Modules spécifiques
      Configurable (YAML)
      Moteur générique
    Validation
      Stricte (échec rapide)
      Progressive (warnings)
      Scoring qualité
    Templates LLM
      Séparés par établissement
      Unifié conditionnel
      Composition modulaire
Loading

Processus décisionnel

  1. Ateliers collaboratifs (Mai 2024)

    • Alignement Brest/AP-HP sur les besoins
    • Priorisation des décisions
  2. Prototypage (Juin 2024)

    • Preuves de concept pour options critiques
    • Évaluation technique
  3. Benchmarking (Juillet 2024)

    • Mesures de performance
    • Évaluation maintenabilité
  4. Documentation (Août 2024)

    • ADR (Architecture Decision Records)
    • Mise à jour diagrammes

Licence

Ce projet est sous licence Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.

Vous êtes libre de :

  • Partager — copier et redistribuer le projet
  • Adapter — remixer et transformer le projet Sous les conditions suivantes :
  • Attribution — Vous devez citer le projet original
  • Non Commercial — Usage commercial interdit sans accord explicite
  • Partage dans les mêmes conditions — Toute modification doit être publiée sous la même licence

About

Tool for generating structured clinical scenarios to support automated medical document creation.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors