FHIR + CDS Hooks + Gemini : un score de risque qu'un clinicien lira vraiment
Les scores de risque meurent quand ils sont des boîtes noires. L'intégration MeldRx via FHIR/CDS Hooks tire les données patient ; Gemini Flash renvoie du JSON structuré avec explications, confiance et actions recommandées ; l'UI livre aux cliniciens un rapport PDF téléchargeable.
Les widgets de prédiction de risque qui se greffent à un DME sont ignorés s'ils ne s'expliquent pas. Le hackathon MeldRx était une excuse pour concevoir d'abord la surface d'explication et faire entrer le modèle dedans.

Pourquoi je l'ai construit
Avant ce hackathon, je n'avais jamais construit d'application santé, et je n'avais jamais entendu parler de CDS Hooks ou de FHIR. Je voulais une excuse forcée d'apprendre ce volet de l'industrie sur une vraie cible d'intégration, plutôt que de lire des spécifications dans le vide. L'autre motivation était plus simple : les cliniciens sont sous pression de temps, et un outil qui fait remonter l'historique d'un patient plus vite, en montrant son raisonnement, c'est quelque chose que je voudrais avoir à côté de moi si c'était moi qui prenais la décision.
Ce qu'elle fait
Dans la vue DME de MeldRx, un bouton sur la carte patient ouvre l'assistant. Le transfert passe par un flux de consentement de type SMART pour que l'utilisateur autorise explicitement l'accès aux données avant toute lecture. Une fois à l'intérieur, l'app récupère les ressources Condition et Observation du patient via FHIR et les envoie à Gemini Flash pour analyse.
La sortie qui revient a un point de vue : un score de risque avec une explication transparente, des actions recommandées, des mesures préventives, et un court résumé écrit pour un clinicien qui a trente secondes. Le modèle s'auto-évalue aussi avec une estimation de précision et le raisonnement derrière cette estimation, et toute l'analyse peut être exportée en PDF qui reste au dossier.

La sortie structurée n'est pas négociable
On demande à Gemini Flash un JSON strict avec les champs sur lesquels l'UI s'appuie : risk_score, confidence, drivers, suggested_actions. Une logique de relance sur réponses malformées garantit le contrat. Si le modèle renvoie de la prose, je redemande. L'UI en aval n'a jamais à parser défensivement.
Actif vs résolu, la visualisation qui a mérité sa place
La plupart des listes d'affections traitent tout comme actuel. Le cerveau d'un clinicien, non. Le tableau de bord sépare visuellement les affections actives et résolues, fait remonter les diagnostics les plus fréquents du panel, et exporte le résumé consolidé en PDF, l'artefact que le clinicien sauvegarde réellement dans le dossier.

Comment je l'ai construit
Next.js avec un mélange de JavaScript et TypeScript par-dessus, CDS Hooks et FHIR comme contrat d'intégration pour sortir les données patient de MeldRx, React Redux pour l'état, Recharts pour les visualisations, Tailwind plus DaisyUI pour le style, et @react-pdf/renderer pour l'export prêt au dossier. Gemini Flash est derrière un appel axios entouré d'une logique de relance. Hébergé sur Vercel.
- Gemini Flash a été choisi spécifiquement pour la latence. Les flux santé ne tolèrent pas une attente de 12 secondes sur un clic de carte.
- CDS Hooks est le contrat pour le moment où l'app a le droit de s'afficher, FHIR est le contrat pour ce qu'elle lit. Les deux sont non optionnels pour être pris au sérieux dans un DME.
- Redux est plus lourd que ce que l'app demande strictement, mais ça rend le flux de consentement et l'état d'analyse faciles à raisonner d'une carte à l'autre.
Ce qui a été difficile
Le prompt engineering jusqu'à ce que la sortie tombe dans la forme JSON exacte attendue par l'UI a pris le plus de temps. Au-delà du prompt, le modèle renvoyait occasionnellement du JSON malformé pendant les tests. La solution : une relance avec backoff, attendre 500 ms en cas d'échec pour ne pas marteler le modèle, puis réessayer jusqu'à 10 fois. Depuis que je l'ai ajoutée, je n'ai pas vu un seul échec atteindre l'UI.
L'autre partie difficile, c'était la courbe d'apprentissage. CDS Hooks, les formes de ressources FHIR, le transfert d'authentification SMART, rien de tout ça n'était sur ma carte avant ce hackathon. La première journée a surtout consisté à lire les spécifications et la documentation du bac à sable MeldRx avant d'écrire le moindre code qui comptait.
Ce que j'ai appris
- Dans une UI clinique, l'explication est la fonctionnalité. Le score est l'effet secondaire.
- Les contrats JSON stricts plus la relance battent à tous les coups le nettoyage de prose en sortie.
- FHIR est verbeux mais prévisible. Une fois qu'on accepte le modèle de ressources, tout s'aligne proprement.
La suite
La précision. Le chiffre auto-évalué le plus élevé que j'ai vu est 85 %, et je veux le pousser plus haut en extrayant davantage de signal patient pertinent et en travaillant plus loin la structure du prompt. Ensuite, la plus grande idée, c'est de transformer l'assistant en une couche de mise en file d'attente : faire produire au modèle une priorité qui est renvoyée à la vue carte de MeldRx, pour que le triage ne soit plus strictement premier arrivé, premier servi. Les notifications texte aux patients sur l'avancement de leur rendez-vous s'intègrent naturellement dans la même boucle.
Dernier point sur la feuille de route : sortir d'un modèle de pointe hébergé. Gemini était le bon choix pour livrer en 48 heures, mais une version production de ceci devrait tourner sur un petit modèle de langue ou un modèle interne affiné, à la fois pour la résidence des données et pour un comportement prévisible sur le contrat JSON.

Aider les copropriétaires à argumenter face à des PDF de 200 pages
Un avis de cotisation spéciale arrive et un copropriétaire a 30 jours pour décider de se battre. Le PDF fait 200 pages de comptabilité et de jargon juridique. CondoShield le lit, fait remonter les leviers et rédige la lettre de contestation, en anglais ou en français.

Laisser Gemini écrire le SQL sur BigQuery pour que les fans n'aient pas à le faire
Une couverture baseball personnalisée qui personnalise vraiment : suivez vos joueurs, choisissez votre horaire, et une couche SQL traduite par LLM laisse l'IA générer des stats et des visualisations à partir de données MLB fraîches, sans changement de code.
