Générateur dynamique de questionnaires cliniques avec interface Gradio et scoring automatisé en R ou Python
Project description
📖 English version available: See README_english.md.
PrevMed (Prévention Médicale)
Plateforme minimaliste permettant à des personnes non techniques de produire des questionnaires cliniques ne stockant aucune information personnelle.
Table des matières
- Objectif Principal
- Description Technique
- Installation
- Utilisation
- Analytics (Optionnel)
- Configuration du questionnaire (YAML)
- Scripts de scoring
- Génération de rapports PDF
- Stockage des données structurées (si activé)
- Structure du projet
- Logs
- Exemple ProbaLYNCH
- Développement
- Licence
- Références et Crédits
- Roadmap
Objectif Principal
PrevMed est conçu pour simplifier le workflow clinique en permettant aux professionnels de santé de créer facilement des questionnaires d'aide à la décision clinique avec des compétences courantes en programmation : un script en langage R (ou Python) et un fichier .yaml.
Fonctionnement :
- Le patient remplit le questionnaire sur l'interface web
- Un PDF avec les réponses et résultats est généré instantanément
- Le patient vient en consultation avec ce PDF
- Aucune donnée personnelle n'est stockée sur le serveur
Ce système fait gagner du temps à tout le monde : le patient prépare ses réponses en amont, et le clinicien dispose immédiatement d'informations structurées et de scores calculés automatiquement.
Description Technique
PrevMed permet de créer des questionnaires cliniques interactifs à partir de fichiers de configuration YAML. Le système génère automatiquement une interface web avec Gradio, gère la logique conditionnelle des questions, exécute des scripts de scoring (R ou Python), et produit des rapports PDF.
Caractéristiques principales :
- ✨ Configuration déclarative via YAML
- 🔀 Questions conditionnelles (affichage dynamique basé sur les réponses précédentes)
- 📊 Support de scripts de scoring en R (via rpy2) ou Python
- 🖥️ Interface web intuitive avec Gradio
- 📄 Génération automatique de rapports PDF
- 📝 Logging détaillé avec loguru
- 🎯 Type hints et documentation NumPy style
Installation
PrevMed peut être installé de plusieurs façons selon vos besoins :
Méthode 1 : Installation depuis PyPI (Recommandée pour les utilisateurs finaux)
La méthode la plus simple pour une utilisation en production :
# Installer PrevMed depuis PyPI
uv pip install PrevMed
# Ou avec pip traditionnel
pip install PrevMed
Prérequis :
- Python 3.13.5 (ou version compatible)
- R et rpy2 si vous utilisez des scripts de scoring en R :
sudo apt install r-base - Sur Ubuntu 22.04, vous pourriez avoir besoin de :
sudo apt-get install libtirpc-dev(source)
Note : Vous devrez toujours cloner le dépôt ou télécharger les exemples séparément pour accéder aux fichiers YAML d'exemple et aux scripts de scoring.
Méthode 2 : Installation depuis les sources (Recommandée pour le développement)
Pour le développement ou la personnalisation :
# Cloner le dépôt
git clone https://github.com/PrevMedOrg/PrevMed
cd PrevMed
# Créer et activer un environnement virtuel
uv venv
source .venv/bin/activate # Sur Windows : .venv\Scripts\activate
# Installer en mode éditable
uv pip install -e .
Prérequis : Identiques à la Méthode 1
Méthode 3 : Docker depuis PyPI (Déploiement en production)
Pour un déploiement en production conteneurisé sans code source local :
# Cloner le dépôt (seulement nécessaire pour docker-compose.yml et les exemples)
git clone https://github.com/PrevMedOrg/PrevMed
cd PrevMed
# Accéder au répertoire docker
cd docker
# Modifier docker-compose.yml pour définir INSTALL_MODE à "pypi"
# Changer la ligne: INSTALL_MODE: local
# En: INSTALL_MODE: pypi
# Optionnellement modifier la section 'command' pour spécifier les arguments souhaités
# Par exemple: --survey-yaml, --scoring-script, --save-user-data, etc.
# Lancer le conteneur en mode détaché (construit et installe depuis PyPI)
sudo docker compose up --build -d
Note : Le répertoire examples sera monté depuis votre clone local. Vous pouvez également fournir vos propres fichiers YAML et scripts de scoring en modifiant les montages de volumes dans docker-compose.yml.
Méthode 4 : Docker depuis les sources (Développement)
Pour un développement conteneurisé avec le code source local :
# Cloner le dépôt
git clone https://github.com/PrevMedOrg/PrevMed
cd PrevMed
# Accéder au répertoire docker
cd docker
# S'assurer que INSTALL_MODE est défini à "local" dans docker-compose.yml (c'est la valeur par défaut)
# Optionnellement modifier la section 'command' pour spécifier les arguments souhaités
# Par exemple: --survey-yaml, --scoring-script, --save-user-data, etc.
# Lancer le conteneur en mode détaché (construit depuis les sources locales)
sudo docker compose up --build -d
Gestion des volumes :
- Les dossiers
logs/etsurvey_data/sont montés comme volumes pour persister les données entre redémarrages - Les PDFs sont générés en mémoire par défaut (pas de fichiers sur disque), assurant une confidentialité maximale
Sécurité du conteneur Docker :
- Le conteneur s'exécute avec l'utilisateur non privilégié
nobody(pas de root) - Le système de fichiers du conteneur est en lecture seule (
read_only: true), sauf pour les volumes montés (logs/etsurvey_data/) - Ces mesures suivent les bonnes pratiques de sécurité Docker et réduisent la surface d'attaque
Cette configuration permet de bénéficier de l'isolation Docker tout en conservant les logs et données importantes, sans créer de fichiers temporaires sur le disque.
Utilisation
Lancement basique
prevmed --survey-yaml <chemin_yaml> --scoring-script <chemin_script>
Exemple avec ProbaLYNCH
Le projet inclut un exemple complet du questionnaire ProbaLYNCH (cf Références et Crédits) pour l'évaluation du risque de syndrome de Lynch :
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml --scoring-script examples/ProbaLYNCH/ProbaLYNCH.R
Ceci lancera une interface Gradio accessible via votre navigateur web.
Options de ligne de commande
PrevMed supporte plusieurs options pour personnaliser le comportement de l'application :
Sauvegarde des données utilisateur
Par défaut, aucune donnée utilisateur n'est sauvegardée. Les rapports PDF générés sont créés en mémoire (en utilisant BytesIO) uniquement pour le téléchargement par le patient, sans logging des réponses ou des résultats - aucun fichier n'est jamais écrit sur disque.
Pour sauvegarder les données utilisateur de manière permanente (dans le répertoire survey_data/), utilisez l'option --save-user-data :
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml \
--scoring-script examples/ProbaLYNCH/ProbaLYNCH.R \
--save-user-data
Avec --save-user-data activé, les données suivantes sont sauvegardées :
- Fichiers JSON compressés (
.json.gz) contenant toutes les réponses et résultats - Logs CSV centralisés pour analyse rapide
- Rapports PDF stockés de manière permanente dans
survey_data/
Sans cette option (comportement par défaut) :
- Les PDFs sont générés en mémoire uniquement (en utilisant BytesIO) - aucun fichier écrit sur disque
- Aucune donnée n'est loggée dans les fichiers CSV
- Aucun fichier JSON n'est sauvegardé
- Respect maximal de la vie privée des patients - empreinte disque nulle
Autres options utiles
# Ouvrir automatiquement le navigateur au démarrage
prevmed --survey-yaml <yaml> --scoring-script <script> --open-browser
# Utiliser un port personnalisé (par défaut: 7860)
prevmed --survey-yaml <yaml> --scoring-script <script> --port 8080
# Activer le logging de niveau debug dans la console
prevmed --survey-yaml <yaml> --scoring-script <script> --debug
# Spécifier l'URL réelle où le questionnaire est hébergé (apparaîtra dans les PDFs)
prevmed --survey-yaml <yaml> --scoring-script <script> --actual-url "https://survey.hopital.fr/probalynch"
# Afficher des mentions légales en bas de page (élément <details> repliable)
prevmed --survey-yaml <yaml> --scoring-script <script> --terms-md mentions_legales.md
Arguments supplémentaires pour demo.launch()
PrevMed permet de passer n'importe quel argument supporté par Gradio directement à demo.launch(). Tous les arguments non reconnus par PrevMed sont automatiquement transmis à Gradio.
Formats supportés :
# Arguments avec valeur (chaîne, int, float)
prevmed --survey-yaml <yaml> --scoring-script <script> --gradio-option value
# Drapeaux booléens (True)
prevmed --survey-yaml <yaml> --scoring-script <script> --enable-feature
# Drapeaux booléens (False)
prevmed --survey-yaml <yaml> --scoring-script <script> --no-disable-feature
Exemples pratiques :
# Désactiver la fermeture automatique du serveur après inactivité
prevmed --survey-yaml <yaml> --scoring-script <script> --prevent-thread-lock
# Activer le mode favicon personnalisé
prevmed --survey-yaml <yaml> --scoring-script <script> --favicon-path /path/to/favicon.ico
# Combiner plusieurs arguments
prevmed --survey-yaml <yaml> --scoring-script <script> \
--max-file-size 10000000 \
--allowed-paths /data /images \
--no-show-error
Note : Consultez la documentation Gradio Blocks pour la liste complète des arguments supportés par demo.launch().
Options de performance
PrevMed inclut des options pour optimiser les performances sous charge importante :
# Augmenter le nombre maximum de threads (par défaut: 40)
prevmed --survey-yaml <yaml> --scoring-script <script> --max-threads 100
# Désactiver la file d'attente des requêtes (activée par défaut)
prevmed --survey-yaml <yaml> --scoring-script <script> --no-queue
Note : La file d'attente (queue) est activée par défaut car elle améliore les performances sous charge. Pour plus d'informations sur l'optimisation des performances de Gradio, consultez le guide officiel : Setting Up a Demo for Maximum Performance.
Analytics (Optionnel)
PrevMed supporte l'intégration de Umami, une solution d'analytics respectueuse de la vie privée, self-hostable, open-source, respectant le RGPD et avec une option gratuite.
Note de confidentialité: Umami est configuré par défaut pour respecter le paramètre Do Not Track (DNT) du navigateur - les utilisateurs qui ont activé DNT dans leur navigateur ne seront pas suivis. Cette option peut être modifiée avec le paramètre --umami-ignore-dnt si nécessaire.
Configuration
Pour activer l'analytics, utilisez les arguments de ligne de commande --umami-website-id et optionnellement --umami-url :
# Option 1: Utiliser le service cloud gratuit Umami (cloud.umami.is)
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml \
--scoring-script examples/ProbaLYNCH/ProbaLYNCH.R \
--umami-website-id "votre-website-id"
# Option 2: Utiliser votre propre instance Umami auto-hébergée
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml \
--scoring-script examples/ProbaLYNCH/ProbaLYNCH.R \
--umami-url "https://votre-instance.example.com" \
--umami-website-id "votre-website-id"
Exemple complet :
# Avec cloud.umami.is (gratuit)
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml \
--scoring-script examples/ProbaLYNCH/ProbaLYNCH.R \
--umami-website-id "70991a3f-4cc9-49ae-a848-867bc75a1fd1"
# Avec instance auto-hébergée
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml \
--scoring-script examples/ProbaLYNCH/ProbaLYNCH.R \
--umami-url "https://analytics.monhopital.fr" \
--umami-website-id "70991a3f-4cc9-49ae-a848-867bc75a1fd1"
# Pour ignorer les préférences Do Not Track du navigateur (non recommandé)
prevmed --survey-yaml examples/ProbaLYNCH/ProbaLYNCH.yaml \
--scoring-script examples/ProbaLYNCH/ProbaLYNCH.R \
--umami-website-id "70991a3f-4cc9-49ae-a848-867bc75a1fd1" \
--umami-ignore-dnt
Options disponibles :
--umami-website-id: ID du site web Umami (requis pour activer l'analytics)--umami-url: URL de l'instance Umami (optionnel, par défaut utilise cloud.umami.is)--umami-ignore-dnt: Ignorer les préférences Do Not Track du navigateur (optionnel, non recommandé pour des raisons de confidentialité)
Note : Si aucun argument analytics n'est fourni, l'application fonctionne sans analytics.
Configuration du questionnaire (YAML)
Les questionnaires sont définis dans des fichiers YAML avec la structure suivante :
survey_name: Nom du questionnaire
# Uniquement pour être mentionnée dans les logs etc:
survey_version: 1.0.0
PrevMed_version: 1.0.0
# Optionnel: titre personnalisé affiché en haut à gauche de la page
# Si défini, remplace le survey_name comme titre
# Si commence par # ou <: traité comme du markdown (et donc permettant le HTML aussi)
# Sinon: ajout automatique de `# ` avant de l'afficher comme du markdown.
page_title: Mon questionnaire
# Optionnel: afficher survey_name comme titre en haut de la page (par défaut: true)
# Ignoré si page_title est défini
show_survey_title: true
# Optionnel: afficher la version du questionnaire sur la page web et dans le PDF (par défaut: true)
show_survey_version: true
# Optionnel: afficher la version de la webapp sur la page web et dans le PDF (par défaut: true)
show_webapp_version: true
# Optionnel: texte d'en-tête affiché en haut du questionnaire (format Markdown, avec support HTML)
header: |
## À propos de ce questionnaire
Description du questionnaire...
# Optionnel: texte Markdown affiché juste avant les questions (après le header et les versions)
questions_header: |
Veuillez répondre aux questions suivantes.
# Optionnel: texte du résumé de la section légale (par défaut: "LEGAL")
# Utilisé comme label du <details><summary> pour les mentions légales (--terms-md)
legal_summary: "Mentions légales et contact"
# Optionnel: contenu Markdown supplémentaire inclus dans le rapport PDF généré
# Supporte: titres (#, ##, ###), gras (**texte**), italique (*texte*), liens [texte](url)
pdf_extra_content: |
## Informations importantes
Ceci est un texte **en gras** et *en italique*.
Pour plus d'informations, visitez [notre site](https://example.com).
questions:
- variable: nom_variable
order: 1
widget: Radio|Number|Checkbox|Textbox
widget_args:
# Arguments spécifiques au widget
choices: ["Option1", "Option2"] # Pour Radio
precision: 0 # Pour Number
step: 1 # Pour Slider
label: "Texte du widget" # Optionnel: par défaut utilise question
question: "Texte de la question"
skip_if: "(nom_variable == 2) and (nom_variable > autre_variable)" # Si l'expression vaut True alors la question n'est pas posée (l'expression doit être en Python et a accès aux variables du reste du script.)
Types de widgets disponibles
Par principe, PrevMed devrait marcher avec n'importe quel widget Gradio. La liste des widgets Gradio est disponible ici. Les widgets suivants sont les plus utilisés:
- Radio : Boutons radio pour choix unique
choices: Liste des options (requis)
- Number : Champ numérique avec contrôles
- Checkbox : Case à cocher booléenne
- Textbox : Champ texte libre
Logique conditionnelle
PrevMed supporte deux types de logique conditionnelle :
1. Affichage conditionnel des questions (skip_if)
Les questions peuvent être affichées ou masquées dynamiquement via le champ skip_if. Les conditions sont des expressions Python évaluées avec les valeurs des variables précédentes :
- variable: age_diagnostic
skip_if: "not (diagnostic_positif == True)"
# Cette question ne s'affiche que si diagnostic_positif n'est pas True
- variable: age_crc_proband
skip_if: "personal_crc_count == 0"
# Cette question est ignorée si le patient n'a aucun cancer colorectal
Points importants :
- L'expression retourne
True→ la question est ignorée - L'expression retourne
False→ la question est affichée - Les expressions peuvent utiliser toutes les variables des questions précédentes
- Les opérateurs Python standards sont supportés (
==,!=,>,<,and,or,not, etc.)
2. Validation des réponses (valid_if)
Les réponses peuvent être validées avant de passer à la question suivante via le champ valid_if. Si la validation échoue, un message d'erreur est affiché et l'utilisateur doit corriger sa réponse :
- variable: current_age
widget: Number
question: "Âge actuel du patient (en années)"
valid_if: "current_age >= 15 and current_age <= 120"
invalid_message: "L'âge doit être compris entre 15 et 120 ans."
- variable: personal_crc_count
widget: Number
question: "Combien de cancers colorectaux ?"
valid_if: "personal_crc_count >= 0"
invalid_message: "Le nombre de cancers ne peut pas être négatif."
Points importants :
- L'expression retourne
True→ la réponse est valide, on peut continuer - L'expression retourne
False→ la réponse est invalide, un avertissement est affiché - Le champ
invalid_message(optionnel) permet de personnaliser le message d'erreur - Si
invalid_messagen'est pas fourni, un message par défaut est utilisé - La validation s'exécute avant de passer à la question suivante
Scripts de scoring
Script R
Le script R doit définir une fonction scoring() qui prend les variables du questionnaire comme arguments nommés et retourne une liste avec 3 éléments :
- Une chaîne de caractères contenant du markdown à afficher au patient
- Une liste de listes représentant une table (première liste = headers, suivantes = lignes de données)
- Une liste nommée avec les options PDF (
include_md_in_pdfetinclude_data_in_pdf)
scoring <- function(variable1, variable2 = NULL, ...) {
# Logique de calcul
score_total <- 0.40
# Générer le texte markdown à afficher au patient sur l'interface web
# Ce texte est TOUJOURS affiché au patient directement dans son navigateur
markdown_result <- sprintf("## Résultats\n\nVotre score total est: %.1f%%", score_total * 100)
# Créer la table de données (format: liste de listes)
# Première liste = headers, suivantes = lignes de données
table_data <- list(
c("Catégorie", "Probabilité"), # Headers
c("Catégorie 1", sprintf("%.2f%%", 0.15 * 100)),
c("Catégorie 2", sprintf("%.2f%%", 0.25 * 100)),
c("Total", sprintf("%.2f%%", 0.40 * 100))
)
# Options de génération PDF
pdf_options <- list(
include_md_in_pdf = TRUE, # Inclure aussi le markdown dans le PDF (il est toujours affiché sur l'interface web)
include_data_in_pdf = TRUE # Inclure la table de données dans le PDF
)
# Retourner une liste avec 3 éléments
list(
markdown_result, # Élément 1: texte markdown
table_data, # Élément 2: table de données
pdf_options # Élément 3: options PDF
)
}
Points importants :
- Les paramètres conditionnels doivent avoir
= NULLcomme valeur par défaut - Retourner une liste avec 3 éléments : markdown, table_data, pdf_options
- Le premier élément est une chaîne markdown qui est toujours affichée au patient sur l'interface web. L'option
include_md_in_pdfcontrôle si ce même texte est aussi inclus dans le rapport PDF (supporte le formatage markdown complet - voir ci-dessous) - Le deuxième élément est une liste de listes où la première liste contient les headers et les suivantes les lignes de données
- Le troisième élément contrôle ce qui est inclus dans le PDF (markdown et/ou table) - notez que le markdown est toujours affiché sur la page web indépendamment de ce paramètre
- Les noms de paramètres doivent correspondre aux noms de variables du YAML
Script Python
Le script Python doit définir une fonction scoring() qui retourne un tuple avec 3 éléments :
- Une chaîne contenant du markdown à afficher au patient
- Une liste de listes représentant une table (première liste = headers, suivantes = lignes de données)
- Un dictionnaire avec les options PDF (
include_md_in_pdfetinclude_data_in_pdf)
def scoring(variable1: str, variable2: int = None, **kwargs) -> tuple[str, list[list[str]], dict[str, bool]]:
"""Calcul du score."""
# Logique de calcul
score_total = 0.40
# Générer le texte markdown à afficher au patient sur l'interface web
# Ce texte est TOUJOURS affiché au patient directement dans son navigateur
markdown_result = f"## Résultats\n\nVotre score total est: {score_total * 100:.1f}%"
# Créer la table de données (format: liste de listes)
# Première liste = headers, suivantes = lignes de données
table_data = [
["Catégorie", "Probabilité"], # Headers
["Catégorie 1", f"{0.15 * 100:.2f}%"],
["Catégorie 2", f"{0.25 * 100:.2f}%"],
["Total", f"{0.40 * 100:.2f}%"]
]
# Options de génération PDF
pdf_options = {
"include_md_in_pdf": True, # Inclure aussi le markdown dans le PDF (il est toujours affiché sur l'interface web)
"include_data_in_pdf": True # Inclure la table de données dans le PDF
}
# Retourner un tuple avec 3 éléments
return (markdown_result, table_data, pdf_options)
Points importants :
- Retourner un tuple avec 3 éléments : markdown, table_data, pdf_options
- Le premier élément est une chaîne markdown qui est toujours affichée au patient sur l'interface web. L'option
include_md_in_pdfcontrôle si ce même texte est aussi inclus dans le rapport PDF (supporte le formatage markdown complet - voir ci-dessous) - Le deuxième élément est une liste de listes où la première liste contient les headers et les suivantes les lignes de données
- Le troisième élément contrôle ce qui est inclus dans le PDF (markdown et/ou table) - notez que le markdown est toujours affiché sur la page web indépendamment de ce paramètre
- Les valeurs de la table peuvent être de n'importe quel type (elles seront converties en chaînes automatiquement)
- Les noms de paramètres doivent correspondre aux noms de variables du YAML
Formatage Markdown supporté
Le champ markdown retourné par les scripts de scoring supporte les éléments suivants :
- Titres :
#,##,###, etc. (niveaux arbitraires) - Gras :
**texte** - Italique :
*texte* - Liens :
[texte](url)(les liens avec URL vide sont ignorés pour éviter les erreurs) - Tables : format pipe standard
- HTML : les balises HTML sont supportées dans les champs Markdown (ex :
<h1 style="text-align: center;">,<details>,<summary>, etc.)
Exemple de table dans le markdown :
| Catégorie | Valeur |
|-----------|--------|
| A | 10% |
| B | 20% |
Génération de rapports PDF
Les rapports PDF sont générés automatiquement à la fin du questionnaire et incluent :
- Nom et version du questionnaire
- Code de référence unique (format XXX-YYY, facile à mémoriser)
- Horodatage de génération
- Résultats du scoring (texte formaté + tableau structuré)
- Toutes les réponses aux questions
Génération de PDFs en mémoire
Approche de stockage des PDFs :
- Par défaut : les PDFs sont générés entièrement en mémoire en utilisant BytesIO (aucun fichier écrit sur disque)
- Avec
--save-user-data: les PDFs sont sauvegardés de manière permanente danssurvey_data/en plus des données JSON
Fonctionnement de la génération en mémoire :
Lorsque --save-user-data n'est pas activé (comportement par défaut) :
- Le PDF est généré directement en mémoire en utilisant le buffer BytesIO de Python
- Les octets du PDF sont transférés directement au navigateur du patient pour téléchargement
- Aucun fichier n'est jamais écrit sur disque - protection maximale de la vie privée
- La mémoire est automatiquement libérée après la fin du téléchargement
- Aucun nettoyage nécessaire - pas de fichiers temporaires à gérer
Exemple de workflow :
- Patient complète le questionnaire à 14h00
- PDF généré en mémoire (BytesIO)
- Patient télécharge le PDF directement depuis la mémoire
- La mémoire est libérée automatiquement après le téléchargement
- Aucune trace ne reste sur le serveur - confidentialité totale
Cette approche assure une empreinte disque nulle et une confidentialité maximale des patients en éliminant toute gestion de fichiers temporaires.
Stockage des données structurées (si activé)
Lorsque l'option --save-user-data est activée, PrevMed sauvegarde toutes les données sous deux formats complémentaires :
Fichiers JSON compressés (si --save-user-data activé)
Avec --save-user-data, chaque soumission est sauvegardée en JSON compressé (.json.gz) dans survey_data/ avec :
- Nom du questionnaire et versions
- Réponses complètes
- Résultats de scoring
- Code de référence unique
- Timestamp Unix
- Hashes de client (pour détection de doublons anonyme)
Format du nom de fichier : {timestamp}_{reference_code}_{unique_id}.json.gz
Exemple : 1729500000_A2B-3C4_a1b2c3d4.json.gz
Note : Le {unique_id} est un fragment UUID (premiers 8 caractères) qui garantit l'unicité absolue même en cas de collision d'horodatage.
Logs CSV (si --save-user-data activé)
Avec --save-user-data, un fichier CSV centralisé enregistre toutes les soumissions pour analyse rapide :
Emplacement : survey_data/csv/{PrevMed_version}/{survey_name}_{survey_version}/survey_submissions.csv
Exemple : survey_data/csv/0.8.0/ProbaLYNCH_1.0.0/survey_submissions.csv
Caractéristiques du système CSV
Structure des colonnes :
- Colonnes fixes :
reference_code,row_number,timestamp_unix,datetime - Colonnes de scoring : une par résultat (ex:
p_MLH1,p_MSH2, formatées en pourcentages) - Colonnes de hashes :
answers_hash+ hashes individuels par attribut client (ex:user_agent_hash,ip_address_hash)
Gestion de la concurrence :
- Utilise
filelockpour garantir l'atomicité des écritures - Supporte l'accès concurrent depuis plusieurs processus/serveurs
- Timeout de 10 secondes sur le verrou
Rotation automatique :
- Le CSV est automatiquement archivé après 1000 lignes
- Fichier archivé :
survey_submissions_{timestamp}.csv(sauvegarde permanente) - Nouveau CSV créé automatiquement pour continuer l'enregistrement
- Objectif : maintenir des performances élevées même avec accès concurrent intensif
Gestion des erreurs :
- En cas de timeout du verrou (charge très élevée), les données sont sauvegardées dans un fichier de secours
- Format :
survey_submissions_fallback_{timestamp}_{uuid}.csv(où{uuid}est un fragment UUID de 8 caractères) - Garantie : aucune perte de données même sous charge extrême
Détection de doublons :
answers_hash: hash court (12 caractères) des réponses uniquement- Hashes individuels de client : chaque attribut (user-agent, IP, etc.) haché séparément avec le code de référence comme sel
- Permet l'analyse de doublons tout en préservant la vie privée
Exemple de contenu CSV :
reference_code,row_number,timestamp_unix,datetime,p_MLH1,p_MSH2,p_MSH6,p_PMS2,p_total,answers_hash,user_agent_hash,ip_address_hash,session_hash_hash
A2B-3C4,1,1729500000,2024-10-21 14:20:00,15.23,25.47,8.92,10.38,60.00,a1b2c3d4e5f6,x9y8z7w6v5u4,q1w2e3r4t5y6,m1n2b3v4c5x6
D5E-6F7,2,1729500120,2024-10-21 14:22:00,2.15,3.28,1.45,1.12,8.00,f6e5d4c3b2a1,u4v5w6z7y8x9,y6t5r4e3w2q1,x6c5v4b3n2m1
Avantages de cette architecture :
- Performance : rotation limite la taille des fichiers pour maintenir vitesse d'accès
- Fiabilité : système de fallback garantit zéro perte de données
- Traçabilité : archivage automatique avec timestamps
- Analyse : format CSV facilite l'analyse statistique rapide
- Scalabilité : gestion de concurrence permet déploiement multi-processus/multi-serveurs
- Vie privée : hashes salés permettent détection de doublons sans stocker données personnelles brutes
Structure du projet
PrevMed/
├── src/
│ ├── __init__.py # Setup du logging
│ ├── __main__.py # Point d'entrée CLI
│ └── utils/
│ ├── gui.py # Interface Gradio
│ ├── css.py # Le CSS utilisé dans Gradio
│ ├── js.py # Le js utilisé dans Gradio
│ ├── io.py # Chargement YAML et scripts
│ ├── logic.py # Logique conditionnelle
│ ├── pdf.py # Génération PDF
│ ├── scoring.py # Exécution scripts R/Python
│ └── settings.py # Stocke des variables disponibles dans tout le script
├── examples/
│ └── ProbaLYNCH/
│ ├── ProbaLYNCH.yaml # Configuration ProbaLYNCH
│ └── ProbaLYNCH.R # Script de scoring ProbaLYNCH
├── logs/ # Logs rotatifs (créé automatiquement)
├── survey_pdfs/ # Rapports PDF (créé automatiquement)
├── requirements.txt
└── setup.py
Logs
Les logs sont automatiquement sauvegardés dans ./logs/ avec rotation journalière et rétention de 365 jours. Le format inclut :
- Horodatage avec millisecondes
- Niveau de log
- Fichier, fonction et ligne
- Message
Exemple ProbaLYNCH
Pour illustrer le fonctionnement de PrevMed, nous avons implémenté le questionnaire ProbaLYNCH (cf. Références et Crédits).
Le questionnaire ProbaLYNCH évalue le risque de mutations dans les gènes MLH1, MSH2, MSH6 et PMS2 (syndrome de Lynch) basé sur :
- L'histoire personnelle de cancers (colorectal, endomètre, autres)
- Les âges au diagnostic
- L'histoire familiale (apparentés du 1er et 2ème degré)
Le modèle ProbaLYNCH utilise un modèle de régression logistique multinomiale avec transformation softmax pour calculer les probabilités de mutation pour chaque gène d'une liste prédéterminée de gênes. Une adaptation en langage R a été écrite en 2025 par Laury NICOLAS, médecin au CHU de Clermont-Ferrand, France. Ce script R à ensuite été optimisé par madame Anna Serova-Erard au CHU de Clermont-Ferrand, France.
Développement
Conventions de code
- Type hints et docstrings NumPy style partout
- Commentaires explicites pour les décisions de design
- Utilisation de
logurupour le logging - Code simple et robuste privilégié
- Utilisation de Ruff comme linter pour assurer la qualité du code
Contributions
Ce projet a été développé avec l'assistance de aider.chat.
Nous accueillons volontiers :
- 🐛 Les signalements de bugs via les Issues
- ✨ Les demandes de fonctionnalités
- 🔧 Les Pull Requests pour améliorer le projet
N'hésitez pas à contribuer !
Licence
Actuellement sous licence GNU Affero General Public License. Cependant, nous sommes flexibles et ouverts à des arrangements de licence alternatifs - n'hésitez pas à nous contacter si vous avez besoin d'une licence différente pour votre cas d'usage.
Références et Crédits
Concernant l'exemple ProbaLYNCH :
- Afin de permettre à tout un chacun d’évaluer sa probabilité d’être porteur du risque génétique, l’association de soutien à la génétique épidémiologique ASAGE (loi 1901 n°RNA W751217490, J.O. du 15 décembre 2012), met à disposition libre, gratuite et sans stockage d’aucune donnée personnelle, l’application ProbaLYNCH (sous licence GNU Affero General Public License) : le code informatique montrant l’absence de conservation des données est accessible en ligne et tourne chez un hébergeur français. L’application initiale a été codée en langage informatique R en 2025, quand il était Dr Junior dans le Service GENOAP (Génétique-Oncogénétique-Adulte-Prévention) du CHU de Clermont-Ferrand, par le Dr Laury NICOLAS, actuellement Chef de Clinique de l’Université Antilles-Guyane - Assistant des Hôpitaux au CHU de la Guadeloupe. Le script R a été optimisé à GENOAP par Madame Anna SEROVA-ERARD, Conseillère en Génétique et Médecine Prédictive. Les illustrations ont été réalisées par Madame Anne SPECQ, Conseillère en Génétique et Médecine Prédictive, ancienne stagiaire de GENOAP. L'application ProbaLynch a été finalisée par Olicorp.
- Kastrinos et al, J Clin Oncol 35, 2165-2172 (2017). DOI: 10.1200/JCO.2016.69.6120. « Development and Validation of the PREMM5 Model for Comprehensive Risk Assessment of Lynch Syndrome ».
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file prevmed-1.0.0.tar.gz.
File metadata
- Download URL: prevmed-1.0.0.tar.gz
- Upload date:
- Size: 51.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
692207b252cc762944729e70e6e271e6501ff7f9c15f827e16a429549a759dec
|
|
| MD5 |
ad3e3f8e23eb0568a3fb81f037555916
|
|
| BLAKE2b-256 |
8499dc20a203f78b81f915562531719092880134292d0a7b497a3eda4270b0ca
|
File details
Details for the file prevmed-1.0.0-py3-none-any.whl.
File metadata
- Download URL: prevmed-1.0.0-py3-none-any.whl
- Upload date:
- Size: 29.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97baecc008681a44f449d4f484fc3ee7954e6c321966bbff18897c577b4ab768
|
|
| MD5 |
f6fde87a1c556d04686a78e00246f122
|
|
| BLAKE2b-256 |
58df915a92d8b2628a39c41394626d6289dd509b9c8b5956106b2617c6983d9d
|