#Open Exchange

0 Abonnés · 86 Publications

Les solutions Open Exchange de la plateforme de données InterSystems sont une galerie de solutions logicielles, d'outils et de frameworks qui ont été développés avec la plateforme de données InterSystems (Caché, Ensemble, HealthShare, InterSystems IRIS, InterSystems IRIS for Health) ou qui sont destinés à aider au développement, au déploiement et à la prise en charge des solutions conçues avec la plateforme de données InterSystems.

Vous pouvez utiliser n'importe quelle ressource publiée ou publier votre propre outil, exemple technologique ou solution.

Découvrir Open Exchange.

Article Lorenzo Scalese · Mai 7, 2025 6m read

Introduction

À mesure que l'automatisation pilotée par l'IA devient un élément essentiel des systèmes d'information modernes, l'intégration des capacités d'IA dans les plateformes existantes doit être transparente et efficace. Le projet IRIS Agent montre comment l'IA générative peut fonctionner sans effort avec InterSystems IRIS, grâce à son puissant cadre d'interopérabilité, sans qu'il soit nécessaire d'apprendre Python ou de créer des workflows d'IA distincts à partir de zéro.
Ce projet examine la manière dont ChatGPT et Anthropic Claude, deux modèles d'IA parmi les plus avancés, peuvent interagir avec IRIS à l'aide de GPT personnalisés et du protocole MCP (Model Context Protocol). Plutôt que de créer des pipelines d'IA isolés, IRIS Agent traite l'IA comme un service d'interopérabilité, permettant ainsi aux organisations d'améliorer l'automatisation, la prise de décision et le traitement des données sans perturber leur architecture existante.
En s'appuyant sur des outils d'interopérabilité natifs d'IRIS, les développeurs peuvent intégrer des modèles d'IA de manière transparente, comme n'importe quel autre composant du système. Cette approche garantit la stabilité, la sécurité, l'évolutivité et l'auditabilité, tout en permettant une interaction en langage naturel, la récupération de données en temps réel et l'administration automatisée du système, le tout dans l'environnement familier d'IRIS.

Technologies sous-jacentes à IRIS Agent

Le projet IRIS Agent s'appuie sur un ensemble de technologies puissantes pour garantir efficacité, évolutivité et intégration transparente:

  • InterSystems IRIS – Une plateforme robuste dédiée au développement d'applications et à l'intégration de données, qui utilise ObjectScript pour le code côté serveur.
  • Custom GPT Bot – Un assistant IA personnalisé conçu pour rationaliser les interactions avec le système, basé sur ChatGPT.
  • Claude AI Desktop – Facilite la communication avec le serveur via le protocole MCP (Model Context Protocol).
  • Node.js – Gère les communications avec le serveur MCP
  • OpenAPI – Documentation API standardisée.
  • Docker – Compartimente l'application pour simplifier le déploiement et la gestion des dépendances.

Présentation interne

Voici à quoi ressemble notre projet sous le capot IRIS:

La Production comprend les éléments suivants:

  • LanguageModelIn: un service qui reçoit une requête API et la redirige vers l'opération responsable.
  • Meds: une opération qui recherche des médicaments sur une API tierce.
  • Metrics: une opération qui recherche des informations OPS telles que les journaux, les erreurs et les messages dans le système Iris.
  • Namespaces: une opération qui répertorie, recherche et modifie les espaces de noms dans le système Iris.
  • Users: une opération qui répertorie, recherche, crée et supprime des utilisateurs dans le système Iris.

Le fonctionnement du service est particulièrement visible dans l'afficheur de messages et les traces. Il peut nous aider à suivre les opérations et à diagnostiquer les problèmes, par exemple les requêtes:

…et les réponses:


L'un des points forts de ce projet réside dans le fait que le service LanguageModelIn génère automatiquement une documentation API ouverte pour les opérations métier dans le cadre de la production IRIS Interoperability. Cette API  nous permet de connecter facilement les GPT personnalisés à ChatGPT et au serveur MCP (Model Context Protocol) à Claude AI Desktop. 

Intégration avec ChatGPT 

Après avoir terminé tous les processus d'installation et de configuration, que vous trouverez dans notre fichier ReadMe, ReadMe, demandons à notre agent IRIS GPT d'OpenAI quelles sont ses fonctionnalités actuelles:

  

Et créez un nouvel utilisateur…

   


Vérification des mises à jour...

   

Intégration avec des Sources de données externes

L'une des fonctionnalités remarquables de l'agent IRIS est sa capacité à interroger de manière transparente non seulement les données stockées dans la base de données InterSystems IRIS, mais également des sources de données externes. Dans notre exemple, l'agent s'intègre à l'OpenFDA API pour fournir des informations en temps réel sur les médicaments. Cela permet aux utilisateurs de rechercher des informations sur les médicaments, des rapports de sécurité et des données de conformité réglementaire directement dans le système. 
Dans notre projet, l'API offre la possibilité de rechercher des médicaments par leur nom. Recherchons donc les médicaments dont le nom contient le mot "flu".

   

Si vous souhaitez l'essayer dès maintenant, suivez le lien et engagez une conversation avec notre IRIS Agent démo.

Intégration avec Claude AI Desktop

L'une des fonctionnalités clés de l'agent IRIS est sa capacité à interagir avec Claude AI Desktop, un assistant IA local développé par Anthropic. L'intégration est assurée par le protocole MCP (Model Context Protocol), qui facilite la communication entre Claude et les applications externes. Pour ce faire, l'agent IRIS utilise un serveur MCP Node.js dédié qui sert d'intermédiaire, traitant les requêtes entrantes et les acheminant entre Claude et le système IRIS.
Cette configuration permet aux utilisateurs d'interagir directement avec l'agent IRIS via l'interface Claude, en émettant des commandes en langage naturel pour récupérer des données système, gérer les configurations et exécuter des tâches administratives. Le serveur MCP garantit un échange de données fluide, tout en maintenant l'efficacité et la sécurité, et fournit aux administrateurs un assistant puissant basé sur l'IA pour la gestion du système.

         

Conclusion

Le projet IRIS Agent présente le potentiel de l'automatisation pilotée par l'IA dans les environnements d'entreprise modernes. En intégrant de manière transparente InterSystems IRIS, Claude AI et Custom GPT, il simplifie la gestion des systèmes, améliore l'efficacité et ouvre la voie à de futures innovations. Notre projet démontre également que vous êtes déjà prêt pour la révolution de l'IA avec InterSystems IRIS!


Si vous avez apprécié la découverte d'IRIS Agent et de ses fonctionnalités et que vous souhaitez nous soutenir, veuillez prendre quelques instants pour voter pour notre application ici https://openexchange.intersystems.com/contest/40. Je vous remercie!


Développeurs de projet:

Banksia Global est une société de conseil technologique de premier plan qui aide les organisations à exploiter pleinement le potentiel des solutions modernes de gestion des données. En mettant l'accent sur la plateforme InterSystems IRIS, Banksia Global fournit des conseils stratégiques, des services d'intégration de systèmes et de développement de logiciels personnalisés à des clients issus de divers secteurs. Son expertise réside dans la fourniture de solutions hautement performantes et évolutives qui permettent aux entreprises de stimuler l'innovation, de rationaliser leurs opérations et de saisir de nouvelles opportunités. Réputée pour son approche collaborative et agile, Banksia Global travaille en étroite collaboration avec ses clients afin de s'assurer que chaque solution est adaptée à leurs besoins spécifiques, favorisant ainsi des partenariats à long terme et une croissance durable.

0
0 59
Article Sylvain Guilbaud · Jan 31, 2025 4m read

Préférez-vous ne pas lire? Regardez la vidéo de démonstration que j'ai créée:

<iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/-OwOAHC5b3s" width="640"></iframe>


En tant que développeur d'interfaces, je reçois souvent des questions qui nécessitent d'étudier de grandes quantités de messages. Par exemple, lors d'une réunion récente, notre chef de projet m'a demandé combien de sites utilisaient réellement notre nouvelle interface de commandement.

D'habitude, j'essaie de copier la sortie de la visionneuse de messages pour la coller dans Excel ou simplement d'exécuter un rapport de messages pour chaque site qui passe des commandes et d'utiliser le nombre de messages renvoyés…

Cette fois-ci, en utilisant l'extension de navigateur Iris Whiz browser extension j'avais des options.

Option 1 - Simple: Exportation de CSV

Une idée mise en œuvre à partir du portail InterSystems Ideas, il suffit de cliquer sur le bouton Export (Exporter) en tant que CSV dans la barre de boutons d'IRIS Whiz pour télécharger la recherche en cours en tant que fichier CSV pour une manipulation facile d'Excel/Sheets.

Option 2 - Chic: Analyse

Dans ce cas, je venais de compléter l'outil d'analyse dans mon extension de navigateur Iris Whiz.

En ajoutant la valeur PV1-3.2 à mes critères de recherche de messages dans la visionneuse de messages (Message Viewer), j'ai pu facilement exécuter le rapport, cliquer sur Analyse et avoir instantanément les renseignements sous la forme d'un simple diagramme en forme de beignet - aucune exportation n'a été nécessaire.

 

 

Ensuite, le chef de projet a voulu savoir quels types d'examens étaient commandés par ces sites. J'ai ajouté la valeur OBR-4.2 à mes critères de recherche et j'ai relancé le rapport. En cliquant sur le bouton d'analyse, j'ai pu voir les sites qui passaient commande et les examens commandés. (Chaque critère de recherche de message est présenté sous la forme d'un graphique en anneau, étiqueté à la fin de la partie graphique de la page d'analyse)

La troisième question se pose.

Quelles commandes sont passées par quels sites?

En cliquant sur le site voulu dans le graphique interactif en anneau, j'ai pu visualiser les données dans la visionneuse de données de la page d'analyse. Un autre clic sur le bouton de filtrage à l'intérieur de cette boîte applique cette sélection de données comme filtre à tous les graphiques - ce qui signifie que le graphique en anneau des examens ne montre plus que les examens commandés pour ce site.

Graphique de site et graphique d'examen filtré par site:

 

Et enfin, la question la plus difficile.

Quand tout cela se produit-il?

Passer en revue les messages dans la page de visualisation des messages pour voir quand les commandes sont passées n'est pas une bonne idée...

Heureusement, j'ai ajouté une chronologie à la page d'analyse.

J'ai supprimé le filtre et cliqué sur le bouton 'Show on Line Graph' (Affichage du graphique linéaire) (activé pour le graphique PV1-3 dans la capture d'écran ci-dessus) afin d'afficher les données du site sur le graphique chronologique en haut de la page.

Une rapide capture d'écran nous a permis d'envoyer ce rapport à nos sites afin qu'ils puissent confirmer le nombre de commandes pour chaque jour et s'assurer que tout fonctionnait comme prévu.
Ces rapports devaient être exécutés chaque semaine, mais heureusement pour moi, cette tâche avait été simplifiée, notamment grâce à la fonction de recherche sauvegardée dans la page de visualisation des messages, qui me permettait de ne jamais avoir à me soucier des critères de recherche à ajouter.

 

Conclusions

1. Données sensibles:

Les données de votre recherche dans la visionneuse de messages (Message Viewer) sont envoyées dans un nouvel onglet du navigateur et disparaissent dès que l'onglet est fermé - vous n'avez donc pas à vous soucier de l'enregistrement de données sensibles dans le navigateur. Si vous souhaitez enregistrer un rapport utilisez la fonctionnalité par défaut d'InterSystems pour les recherches enregistrées et exécutez simplement le rapport à nouveau à une date ultérieure. J'avais prévu un mécanisme d'enregistrement des recherches à partir de la page d'analyse, mais il n'a pas été retenu dans cette version.

2. Vitesse:

La page d'analyse est alimentée par la recherche de messages et je n'ai pas mis de limites strictes à la quantité de données pouvant être affichées. Plus vous ajoutez de messages et de critères de recherche, plus la page d'analyse ralentira. C'est pourquoi j'ai ajouté une fenêtre contextuelle si vous essayez de charger plus de 200 messages, ce qui vous permet de choisir de charger ou non le diagramme à barres en haut de la page. 

Le diagramme à barres présente chaque message sous la forme d'une case à sélectionner. En cliquant sur une case du diagramme, le message est ajouté à la liste des messages sélectionnés dans la fenêtre de visualisation des données (à gauche de la page). Vous pouvez alors cliquer sur le bouton 'View Selected Messages' (Voir les messages sélectionnés) pour ouvrir ces messages dans une nouvelle page et profiter des fonctionnalités de comparaison des messages de l'extension.

Lorsque vous cliquez sur ce bouton, essayez de ne pas sélectionner trop de messages. Un maximum de 10 devrait suffire. 

Si vous téléchargez le diagramme à barres avec de grands ensembles de données (10 000), cela ne sera certainement pas bon pour votre navigateur, mais je vous laisse le soin de choisir.

0
0 45
Article Sylvain Guilbaud · Jan 29, 2025 3m read

Lors du dernier concours InterSystems "Bringing Ideas to Reality", j'ai parcouru le portail d'idées à la recherche de problèmes d'interface utilisateur à traiter. 

<iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/zw51X1JQhQ0" width="640"></iframe>

J'ai implémenté les idées suivantes dans l'extension de navigateur IRIS Whiz browser extension, so if you use the management portal to help with your day-to-day integration management this extension could be for you!

Fonctionnalité ajoutée: Rafraîchissement de la file d'attente

Iris a désormais une liste déroulante de rafraîchissement automatique pour la page des files d'attente (Queues). Cette option permet de rafraîchir la file d'attente à l'intervalle sélectionné. Cette fonctionnalité ne s'applique pas à Ensemble, qui en dispose déjà.

C'est utile si vous avez un concours de clics à venir et que vous avez besoin du repos de votre doigt de clic.

Implémenté à partir de l'idée: https://ideas.intersystems.com/ideas/DPI-I-487

 

Fonctionnalité ajoutée : Exportation de la recherche au format CSV

Dans la page de la visionneuse de messages Message Viewer, vous pouvez cliquer sur le bouton Iris Whiz Export pour télécharger une copie CSV des données contenues actuellement dans votre table de recherche.

Utile si vous voulez faire une analyse rapide de vos données sans utiliser la nouvelle page Chart.JS que j'ai mis une éternité à créer (voir ici en action!).

Implémenté à partir de l'idée: https://ideas.intersystems.com/ideas/DPI-I-566

 

Fonctionnalité ajoutée : Tri de la file d'attente des pages de production

Ajout d'options de tri pour l'onglet "file d'attente" de la page de production. Le tri par défaut est le nombre d'erreurs. Cliquez sur l'en-tête d'un table pour passer de l'ordre de tri asc à l'ordre de tri desc. Utilisez la barre de recherche pour trouver rapidement des éléments.

Utile si vous ne voulez pas faire défiler sur l'écran pour accéder à la plus grande file d'attente.

Implémenté à partir de l'idée: https://ideas.intersystems.com/ideas/DPI-I-628

 

Fonctionnalité Ajoutée: Ordre insensible à la casse de la liste déroulante des catégories

Permet de classer par ordre alphabétique la liste déroulante des catégories dans la page de production, quel que soit la casse. Sans cela, l'ordre est dépendant de la casse.

Utile si vous voulez trouver des choses dans la liste des catégories, sans avoir à tout recatégoriser dans la même casse pour y parvenir.

Implémenté à partir de l'idée: https://ideas.intersystems.com/ideas/DPI-I-625

Bonus! 

Il existe également un taux de rafraîchissement dans l'onglet de la visionneuse de messages dans la page de production.  Cela rafraîchira également votre onglet de file d'attente si vous sélectionnez un intervalle et naviguez vers l'onglet de la file d'attente. 

Si l'une de ces idées vous plaît, téléchargez l'extension de navigateur et communiquez moi vos commentaires. Vous trouverez une vidéo d'installation sur la liste d'OpenExchange que je vous recommande de regarder car vous devrez en réaliser une partie pour que la plupart des fonctionnalités fonctionnent!

0
0 36
Article Lorenzo Scalese · Jan 6, 2025 6m read

Salut la Communauté,

image
Dans cet article, je présenterai mon application iris-HL7v2Gen.

IRIS-HL7v2Gen est une application CSP qui facilite la génération dynamique de messages de test HL7. Ce processus est essentiel pour tester, déboguer et intégrer les systèmes de données de soins de santé. L'application permet aux utilisateurs de générer une grande variété de types de messages HL7, de valider leur structure par rapport aux spécifications HL7, d'explorer la hiérarchie des messages et de transmettre les messages par TCP/IP aux systèmes de production. Ces fonctionnalités sont particulièrement utiles dans les contextes où la conformité aux normes HL7 est obligatoire pour assurer l'interopérabilité entre différents organismes ou systèmes de soins de santé.

Fonctionnalités de l'application

  • Génération Dynamique de Messages HL7: Création instantanée de messages HL7 pour une gamme de types de messages, facilitant ainsi les tests complets.
  • Exploration de la structure des messages: Visualisation de la structure des messages générés sur la base des spécifications HL7.
  • Visualisation des jeux de valeurs: Visualisation des jeux de valeurs codées prédéfinis pour des champs spécifiques.
  • Validation des messages: Validation des messages par rapport aux normes HL7 pour garantir la conformité.
  • Communication TCP/IP: Transmission facile de messages à la production à l'aide de paramètres TCP/IP.
  • Prise en charge d'un grand nombre de types de messages: Prise en charge de 184 types de messages HL7, garantissant la polyvalence pour les différents besoins d'intégration des soins de santé.
  • ClassMethod: Génération d'un message de test par l'invocation d'une méthode de classe
  • Version prise en charge: Actuellement, la version 2.5 de HL7 est prise en charge
0
0 55
InterSystems officiel Adeline Icard · Déc 9, 2024

Cela fait un moment que je n'ai pas publié d'article sur Embedded Git sur la Communauté des développeurs, et j'aimerais faire le point sur l'énorme quantité de travail que nous avons accompli cette année et sur la direction que nous allons prendre ensuite.

Contexte

Si vous créez des solutions sur IRIS et que vous souhaitez utiliser Git, c'est parfait ! Utilisez simplement VSCode avec un dépôt git local et transmettez vos modifications sur le serveur : c'est aussi simple que cela.

Mais que se passe-t-il si :

0
0 45
Article Guillaume Rongier · Sept 23, 2024 9m read

IrisFirebase - FCM
 

Bonjour la communauté!

Après avoir lancé mon application dans l'OpenExchange (IrisFirebase avec la fonctionnalité permettant d'utiliser la base de données en temps réel de Firebase), j'ai remarqué d'autres fonctionnalités intéressantes de Firebase que nous pourrions utiliser. C'est pourquoi, en vérifiant les possibilités que Firebase nous apporte, j'ai décidé d'ajouter une nouvelle fonctionnalité au FCM d'IrisFirebase !!! (Firebase Cloud Messaging).

Comment?? Ne savez-vous pas quelle est la clé de Firebase Cloud Messaging? Ne vous inquiétez pas! Je vais vous l'expliquer tout de suite.

Firebase Cloud Messaging. “Explication”:

Firebase Cloud Messaging (FCM) est un service fourni par Google. Il permet aux développeurs d'envoyer des notifications et des messages aux appareils des utilisateurs, tels que les smartphones, les tablettes ou les ordinateurs. 

Nous avons un dicton en Espagne : "Una imagen vale más que mil palabras" (une image vaut mille mots). Voici donc un exemple pour vous:



 

Comme vous pouvez le voir dans les captures d'écran, vous pouvez envoyer des messages avec un titre, un corps et une image personnalisés. Mais il y a une autre chose fascinante que je souhaite vous montrer.

Oui, je sais ce que vous pensez en ce moment... "Hé, ça a l'air génial, mais ça doit être assez cher, surtout pour une personne aussi fragile que moi".Alors, c'est la meilleure partie! C'est totalement gratuit!! Jetez un œil à la preuve ci-dessous:

https://firebase.google.com/products/cloud-messaging



 

Souhaitez-vous savoir de quelle manière vous pouvez envoyer des messages à vos applications, pages web, etc…? Quelle chance!!! Pourquoi? Car je vais vous expliquer comment le faire de manière très simple. Préparez vos timbres et enveloppes numériques car nous allons "envoyer” un tas de "lettres". Allons-y! 

 

Préparation de notre environnement:

Si vous avez examiné mon précédent article expliquant comment utiliser IrisFirebase, vous devriez avoir une App déjà configurée dans Firebase avec une instance d'IrisFirebase en cours d'exécution. Au cas où vous ne l'auriez pas lu, veuillez suivre les étapes, 1, 2, 4, 5 et 6 de l'article ci-dessous:

https://community.intersystems.com/post/firebase-module-unleashing-power-firebase-realtime-database-intersystems-iris

Ok, si vous avez suivi toutes les étapes correctement, vous devriez avoir une instance d'IrisFirebase en cours d'exécution, alors continuons.

Première étape: configurez votre application pour utiliser FCM:

Pour être capable d'envoyer des messages, vous devez d'abord configurer FCM dans votre application Firebase.

Saisissez votre console Firebase et sélectionnez votre projet (dans mon cas, il s'agit de IrisFirebaseExample):


Appuyez ensuite sur le bouton Tous les produits:


 

Recherchez le produit "Cloud Messaging”:


 

Vous devez maintenant ajouter une ou plusieurs applications suivant que vous développez une application pour Android uniquement ou pour plusieurs plateformes différentes. (Dans mon cas, j'ai opté pour Android):

(Si vous prévoyez d'envoyer des messages à iOS, vous devez avoir un compte développeur Apple payant car il faut générer un certificat).


Remplissez les champs obligatoires avec les renseignements sur votre App/web (le champ SHA-1 est facultatif):

 

Après quelques secondes, un écran vous demandant de télécharger le fichier de configuration apparaîtra. Cliquez sur " Download google-service.json " et gardez-le en sécurité car il est crucial pour votre travail. (Vous devrez le copier à la racine du projet de votre application plus tard). Après avoir sauvegardé le fichier, cliquez sur le bouton Next.


 

L'étape suivante explique comment ajouter le SDK Firebase à votre application.


 

Cette étape est différente si vous créez une application avec Kotlin, Groovy, Flutter, etc. Dans mon cas, j'ai utilisé Flutter, et la façon la plus simple de le faire est d'installer le CLI de Firebase:

https://firebase.google.com/docs/android/setup

Je n'expliquerai pas ces étapes car elles dépassent le cadre de ce tutoriel. Cependant, n'hésitez pas à me poser des questions dans les commentaires.

Alors, continuons en appuyant sur le bouton "Suivant".

À ce stade, nous avons terminé le côté console Firebase. Félicitations, vous avez passé la partie ennuyeuse!!!


 

Deuxième étape: Configurez IrisFirebase.FCM:

Si vous avez configuré l'application précédente dans IrisFirebase avec Firebase RealTime Database, vous pouvez l'utiliser avec FCM. Si vous n'avez pas cette application, vous pouvez la configurer en lançant la méthode ConfigApp de la classe Firebase.Helper.cls. Vous trouverez un exemple de la manière de procéder dans la classe Test.TestFCM.cls:

ClassMethod init()
{
  Do##class(Firebase.Helper).ConfigApp("appNotas",””,"irisfirebaseexample.json")
}

N'oubliez pas d'utiliser vos paramètres privés (le deuxième paramètre URL n'est obligatoire que pour la base de données en temps réel ; il ne s'applique pas au FCM, vous pouvez donc l'omettre ou l'envoyer vide.

C'est très bien ! Nous avons maintenant tous les systèmes configurés : notre instance IrisFirebase avec FCM et notre App ou Web avec le SDK Firebase.

Il est temps de commencer l'envoi de messages!

Troisième étape: envoi d'un message à un seul appareil:

Pour envoyer un message à un appareil particulier, vous devez connaître l'identifiant du jeton de l'application que vous souhaitez notifier.

Vous pouvez obtenir cet identifiant de jeton à partir de l'application/du site web que vous utilisez. Ci-dessous, vous trouverez un exemple de la façon d'obtenir l'identifiant du jeton d'une instance de votre application installée sur un appareil Android avec Flutter de manière programmatique:


 

Avec ce code, vous obtiendrez la variable "jeton". L'identifiant du jeton ressemblera à ce qui suit:

fErQlmmjTsq2E2-p7RN6zD:APA91bFhdeCGit17QSIXrlbfovr59BgviGIDHI0nnp7t9i_YFKAPSACkTvP_iKOV-b3Xaj73uhl7Z0S41vfmH_YVV8Ep9Evad69-s1Hkt9pu3VrkeZQGTc8vAJgKSY1qkhuP7HU6t7UJ

 

Selon la façon dont vous utilisez votre application, vous pouvez préférer stocker cet identifiant dans Iris avec un identifiant qui identifie votre client. Pour ce faire, vous pouvez utiliser la méthode SaveToken. Vous trouverez un exemple de son fonctionnement dans la classe Test.TestFCM.cls

ClassMethod TestSaveToken()
{
  Set token = "fErQlmmjTsq2E2-p7RN6zD:APA91bFhdeCGit17QSIXrlbfovr59BgviGIDHI0nnp7t9i_YFKAPSACkTvP_iKOV-b3Xaj73uhl7Z0S41vfmH_YVV8Ep9Evad69-s1Hkt9pu3VrkeZQGTc8vAJgKSY1qkhuP7HU6t7HJ"Set appName = "appNotas"Set id = 123456Do##class(Firebase.FCM).SaveToken(appName, token, id)
}

 

Dans ce cas, il peut s'agir de votre identifiant client ou de tout autre identifiant susceptible de vous aider à identifier cet appareil à l'avenir.

Donc, maintenant nous sommes complètement prêts à envoyer un message. Pour ce faire, vous pouvez utiliser l'une des méthodes suivantes:

La première méthode: consiste à envoyer des messages directement à un jeton (méthode Send), voyez l'exemple ci-dessous:

ClassMethod TestSendMessage()
{
 Set appName = "appNotas"Set title = "IrisFirebase FCM"Set body = "Now you can send messages from Iris using IrisFirebase!!!"Set image = "https://openexchange.intersystems.com/mp/img/packages/3553/vaeo3isvwgubxb2ya7vb0c9edgs.jpeg"Set token = "fErQlmmjTsq2E2-p7RN6zD:APA91bFhdeCGit17QSIXrlbfovr59BgviGIDHI0nnp7t9i_YFKAPSACkTvP_iKOV-b3Xaj73uhl7Z0S41vfmH_YVV8Ep9Evad69-s1Hkt9pu3VrkeZQGTc8vAJgKSY1qkhuP7HU6t7HJ"Set data = {}
 Set data.param1 = "param1 value"Set data.param2 = "param2 value"Set result = ##class(Firebase.FCM).Send(appName, token, title, body, image, data)
 If (result = 1)
 {
  U 0W"Message sended OK"
 }Else{
  U 0W"Error sending message"
 }

}

Comme vous pouvez le constater, pour envoyer un message, vous aurez besoin des éléments suivants:

AppName: C'est le nom de l'application que vous avez écrit dans la méthode ConfigApp.

Le Titre, le Corps et l'Image sont expliqués dans la capture d'écran:



 

Jeton: il s'agit de l'identifiant du token que vous avez obtenu auprès de l'application.

Data : Il s'agit d'un outil très intéressant (data est un dictionnaire JSON avec une paire de valeurs clés où vous pouvez envoyer des données cachées personnalisées à l'appareil). Peut-être envoyez-vous à votre client les détails de son prochain rendez-vous, vous pouvez donc utiliser cette structure pour envoyer des informations à afficher dans votre application ou ce que vous voulez.

La deuxième méthode: consiste à envoyer un message à un identifiant client (ou autre):

Dans ce cas, vous pouvez utiliser la méthode SendMessageToId. Voyez l'exemple ci-dessous:

ClassMethod TestSendMessageToId()
{
 Set appName = "appNotas"Set id = 123456Set title = "título"Set body = "Cuerpo Mensaje"Set image = "https://openexchange.intersystems.com/mp/img/packages/3553/vaeo3isvwgubxb2ya7vb0c9edgs.jpeg"Set token = "fErQlmmjTsq2E2-p7RN6zD:APA91bFhdeCGit17QSIXrlbfovr59BgviGIDHI0nnp7t9i_YFKAPSACkTvP_iKOV-b3Xaj73uhl7Z0S41vfmH_YVV8Ep9Evad69-s1Hkt9pu3VrkeZQGTc8vAJgKSY1qkhuP7HU6t7FD"Set data = {}
 Set data.param1 = "param1 value"Set data.param2 = "param2 value"Set result = ##class(Firebase.FCM).SendMessageToId(appName, id, title, body, image, data)


 If (result = 1)
 {
  U 0W"Message sended OK"
 }Else{
  U 0W"Error sending message"
 }
}

Comme vous pouvez le constater, la différence entre la méthode précédente et la présente est que dans ce dernier cas, vous devez connaître l'identifiant de votre jeton enregistré au lieu d'utiliser le jeton à l'aide de la méthode SaveToken.

Les autres paramètres sont les mêmes.

 

La dernière étape: consiste à envoyer le même message à toutes les instances de votre application/Web:

Pour ce faire, vous pouvez utiliser l'outil natif de Firebase pour envoyer des campagnes.

Accédez à la console Firebase, saisissez votre projet et appuyez sur le bouton "Messaging":


 

Dans cet écran, vous pourrez créer une nouvelle campagne en cliquant sur “New Campaign” ("Nouvelle campagne") puis sur "Notifications":


 

Vous verrez l'explication détaillée des étapes à suivre pour envoyer le même message à toutes les instances de votre application. 


 

Si vous le souhaitez, vous pouvez appliquer certains filtres au cours du processus:


 

Vous pourrez programmer votre campagne ou l'envoyer immédiatement:


 

Vous pouvez également ajouter des analyses:


 

v:

Lorsque vous êtes prêt, appuyez sur Réviser (Review) et Publier (Publish).

Votre nouvelle campagne apparaîtra dans la section de messagerie "Messaging".

Si vous avez préalablement sélectionné l'option "envoyer immédiatement" ("send now"), vous recevrez la notification dans quelques secondes:


 

Firebase prétend pouvoir envoyer des millions de messages en quelques secondes. Par conséquent, si vous envisagez d'envoyer le même message à tous vos clients, je vous recommande de créer une campagne plutôt que d'envoyer le même message à tous vos clients un par un à partir d'IRIS. En revanche, si vous envoyez le message à un groupe de clients ou si le message doit être personnalisé pour chaque client, l'envoi à partir d'IrisFirebase est la meilleure option!.
 

Cliquez sur le lien ci-dessous pour trouver la nouvelle version d'IrisFirebase avec FCM sur l'OpenExchange:

https://openexchange.intersystems.com/package/irisfirebas

Pour découvrir le code de l'application en Flutter que j'ai utilisée dans ce tutoriel, consultez le lien suivant:

https://github.com/daniel-aguilar-garcia/push_app_flutter_example

Voilà, c'est tout pour l'instant. J'espère que vous trouverez cette nouvelle fonctionnalité intrigante et que vous l'utiliserez beaucoup!

Faites-moi savoir dans les commentaires ce que vous pensez de cette nouvelle fonctionnalité. N'hésitez pas à me contacter si vous souhaitez que j'ajoute de nouveaux éléments à IrisFirebase.

Merci d'avoir lu!!

0
0 88
Article Iryna Mykhailova · Août 16, 2024 1m read

Il existe de nombreux articles communautaires intéressants concernant la « recherche vectorielle sur IRIS » et des exemples dans OpenExchange. Chaque fois que je les vois, je suis ravi de savoir que tant de développeurs essaient déjà les vecteurs sur IRIS !

Mais si vous n'avez pas encore essayé la « recherche vectorielle sur IRIS », donnez-moi une minute 😄 Je crée une classe IRIS - et avec une seule classe IRIS, vous pouvez voir comment vous placez les données vectorielles dans votre base de données IRIS et comment vous les comparez dans votre application.

0
0 41
Article Pierre LaFay · Juin 26, 2024 2m read

Si l'un de vos package sur OEX fait l'objet d'une évaluation, vous n'êtes informé par OEX que de VOTRE propre package.   
L'évaluation reflète l'expérience de l'évaluateur avec le statut trouvé au moment de l'évaluation.   
Il s'agit en quelque sorte d'un instantané qui peut avoir changé entre-temps.   
Les évaluations par d'autres membres de la communauté sont marquées d'un * dans la dernière colonne.

J'ai également placé un certain nombre de Pull Requests sur GitHub lorsque j'ai trouvé un problème que je pouvais résoudre.    
Certaines ont été acceptées et fusionnées, d'autres ont été ignorées.     
Donc si vous avez fait un changement majeur et que vous attendez une révision modifiée, faites-le moi savoir.

0
0 29
Article Pierre LaFay · Juin 26, 2024 2m read

Si l'un de vos paquet sur OEX fait l'objet d'une évaluation, vous n'êtes informé par OEX que de VOTRE propre paquet.   
L'évaluation reflète l'expérience de l'évaluateur avec le statut trouvé au moment de l'évaluation.   
Il s'agit en quelque sorte d'un instantané qui peut avoir changé entre-temps.   
Les évaluations par d'autres membres de la communauté sont marquées d'un * dans la dernière colonne.

J'ai également placé un certain nombre de Pull Requests sur GitHub lorsque j'ai trouvé un problème que je pouvais résoudre.    
Certaines ont été acceptées et fusionnées, d'autres ont été ignorées.     
Donc si vous avez fait un changement majeur et que vous attendez une révision modifiée, faites-le moi savoir.

0
0 23
Article Guillaume Rongier · Mai 24, 2024 5m read

Comme la plupart d'entre vous le savent probablement déjà, depuis environ la fin de 2022 InterSystems IRIS a inclus la fonctionnalité de stockage de colonnes dans sa base de données, eh bien, dans l'article d'aujourd'hui, nous allons la mettre à l'épreuve par rapport au stockage de rangées habituel.

Stockage de colonnes

Quelle est la principale caractéristique de ce type de stockage? Si nous consultons la documentation officielle, nous verrons ce tableau fantastique qui explique les principales caractéristiques des deux types de stockage (par rangées ou par colonnes):

Comme vous pouvez le constater, le stockage de colonnes est principalement conçu pour les tâches analytiques dans le cadre desquelles des requêtes sont lancées sur des champs spécifiques de notre tableau, tandis que le stockage de rangées est plus optimal lorsqu'un grand nombre d'opérations d'insertion, de mise à jour et de suppression sont nécessaires. ainsi que pour l'obtention d'enregistrements complets.

Si vous continuez la lecture de la documentation, vous verrez à quel point il est simple de configurer notre table pour qu'elle puisse utiliser le stockage de colonnes:

CREATETABLEtable (columntype, column2 type2, column3 type3) WITH STORAGETYPE = COLUMNAR

En utilisant cette commande, nous définissons toutes les colonnes de notre tableau avec un stockage de colonnes, mais nous pouvons opter pour un modèle mixte où notre tableau dispose d'un stockage de rangées, mais dont certaines colonnes font appel à un stockage de colonnes.

Ce scénario mixte pourrait être intéressant lorsque des opérations d'agrégation telles que les sommes, les moyennes, etc. sont courantes. Dans un tel cas, nous pourrions définir la colonne qui utilisera le stockage en question:

CREATETABLEtable (columntype, column2 type2, column3 type3 WITH STORAGETYPE = COLUMNAR)

Dans l'exemple précédent, nous avons défini une table avec un stockage de rangées et une colonne (column3) avec un stockage de colonnes.

Comparatif

Pour comparer le temps consacré au stockage de colonnes et au stockage de rangées dans des requêtes différentes, nous avons créé un petit exercice à l'aide de Jupyter Notebook qui insère une série d'enregistrements que nous générons dans deux tables, la première avec un stockage de rangées (Test.PurchaseOrderRow) et la seconde avec un stockage de rangées dans les deux colonnes (Test.PurchaseOrderColumnar)

Test.PurchaseOrderRow

CREATETABLE Test.PurchaseOrderRow (
    ReferenceINTEGER,
    Customer VARCHAR(225),
    PaymentDate DATE,
    Vat NUMERIC(10,2),
    Amount NUMERIC(10,2),
    StatusVARCHAR(10))

Test.PurchaseOrderColumnar

CREATETABLE Test.PurchaseOrderColumnar (
    ReferenceINTEGER,
    Customer VARCHAR(225),
    PaymentDate DATE,
    Vat NUMERIC(10,2),
    Amount NUMERIC(10,2) WITH STORAGETYPE = COLUMNAR,
    StatusVARCHAR(10) WITH STORAGETYPE = COLUMNAR)

Si vous téléchargez le projet Open Exchange et le déployez dans votre Docker local, vous pouvez accéder à l'instance Jupyter Notebook et examiner le fichier PerformanceTests.ipynb, qui sera responsable de la génération des données aléatoires que nous allons stocker en différentes étapes dans nos tables et enfin il nous montrera un graphique avec la performance des opérations d'interrogation.

Jetons un coup d'œil rapide à la configuration de notre projet:

docker-compose.yml

version:'3.7'services:# iris  iris:    init:true    container_name:iris    build:      context:.      dockerfile:iris/Dockerfile    ports:      -52774:52773      -51774:1972    volumes:    -./shared:/shared    environment:    -ISC_DATA_DIRECTORY=/shared/durable    command:--check-capsfalse--ISCAgentfalse# jupyter notebook  jupyter:    build:      context:.      dockerfile:jupyter/Dockerfile    container_name:jupyter    ports:      -"8888:8888"    environment:      -JUPYTER_ENABLE_LAB=yes      -JUPYTER_ALLOW_INSECURE_WRITES=true    volumes:      -./jupyter:/home/jovyan      -./data:/app/data    command:"start-notebook.sh --NotebookApp.token='' --NotebookApp.password=''"

Nous déployons les conteneurs IRIS et Jupyter dans notre docker, en configurant d'abord IRIS avec l'espace de noms "TEST" et les deux tables requises pour le test.

Pour que vous ne vous ennuyiez pas avec du code, vous pouvez consulter le fichier PerformanceTests.ipynb à partir duquel nous allons nous connecter à IRIS, générer les enregistrements à insérer et les stocker dans IRIS

Exécution du test

Les résultats ont été les suivants (en secondes):

Inserts:

Les inserts effectuées sont de type "bulk":

INSERTINTO Test.PurchaseOrderColumnar (Reference, Customer, PaymentDate, Vat, Amount, Status) VALUES (?, ?, ?, ?, ?, ?)

Le temps nécessaire pour chaque insert batch est le suivant:

Nombre total d'inserts

Stockage de rangéesStockage mixte
1000

0.031733

0.041677

5000

0.159338

0.185252

20000

0.565775

0.642662

50000

1.486459

1.747124

100000

2.735016

3.265492

200000

5.395032

6.382278

Sélections:

La sélection lancée inclut une fonction d'agrégation et une condition, toutes deux sur des colonnes avec stockage de colonnes:

SELECTAVG(Amount) FROM Test.PurchaseOrderColumnar WHEREStatus = 'SENT'

Nombre total de lignes

Stockage de rangéesStockage mixte
1000

0.002039

0.001178

5000

0.00328

0.000647

20000

0.005493

0.001555

50000

0.016616

0.000987

100000

0.036112

0.001605

200000

0.070909

0.002738

Conclusions

Comme vous pouvez le voir dans les résultats obtenus, l'opération correspond exactement à ce qui est indiqué dans la documentation. L'inclusion de colonnes avec stockage de colonnes pénalise légèrement les performances au cours des inserts (environ 18% plus lent pour notre exemple) alors que les requêtes sur ces mêmes colonnes améliorent considérablement le temps de réponse (258 fois plus rapide).

Il s'agit sans aucun doute d'un élément à prendre en compte lors de la planification du développement de toute application.

0
0 77
Article Pierre LaFay · Avr 10, 2024 2m read

Si l'un de vos package sur OEX fait l'objet d'une évaluation, OEX ne vous informe que de VOTRE propre package.   
L'évaluation reflète l'expérience de l'évaluateur avec le statut trouvé au moment de l'évaluation.   
Il s'agit en quelque sorte d'un instantané qui peut avoir changé entre-temps.   
Les évaluations par d'autres membres de la communauté sont marquées d'un * dans la dernière colonne.
J'ai également placé un certain nombre de Pull Requests sur GitHub lorsque j'ai trouvé un problème que je pouvais résoudre.    
Certaines ont été acceptées et fusionnées, d'autres ont été ignorées.     
Donc si vous avez fait un changement majeur et que vous attendez une révision modifiée, faites-le moi savoir.

0
0 44
Article Maria Nesterenko · Mars 15, 2024 8m read

L'intelligence artificielle (IA) attire beaucoup d'attention dernièrement car elle peut changer de nombreux domaines de nos vies. Une meilleure puissance informatique et plus de données ont aidé l'IA à réaliser des choses incroyables, comme l'amélioration des tests médicaux et la création de voitures autonomes. L'IA peut également aider les entreprises à prendre de meilleures décisions et à travailler plus efficacement, c'est pourquoi elle devient de plus en plus populaire et largement utilisée.

 

0
0 76
Article Iryna Mykhailova · Mars 7, 2024 8m read

Pourquoi connecter Flask à InterSystems IRIS ?

    La première chose qui nous vient à l'esprit lorsque nous envisageons de coupler Flask avec IRIS est un portail permettant d'interagir avec vos clients et partenaires. Un site web où les patients peuvent accéder à leurs examens cliniques en est un bon exemple. Bien entendu, ce cas nécessiterait une toute nouvelle couche de sécurité, que nous n'avons pas abordée dans notre dernier article. Cependant, nous pouvons l'ajouter sans effort avec Werkzeug, par exemple.
Les sites Web qui établissent un lien entre vos produits et vos clients sont, en effet, un excellent exemple de ce que vous pouvez réaliser en connectant ces technologies car Flask est flexible et vous pouvez facilement ajouter et modifier n'importe quelle fonctionnalité avec cette application ou même faire plus de choses si vous avez une certaine expérience avec CI/CD.
Examinons quelques-unes des astuces que vous pouvez réaliser. Si vous vous souvenez de la première application présentée initialement, vous vous rappellerez que Flask n'a pas besoin d'une structure complexe pour fonctionner, ce qui signifie que vous pouvez le construire à partir de zéro en quelques minutes de codage seulement. Ainsi, vous pouvez rapidement créer de multiples interfaces conviviales et des portails interactifs pour afficher et analyser les données. Par exemple, vous pouvez suivre séparément chaque élément d'une production. Vous pouvez également fournir toutes les fonctionnalités d'InterSystems IRIS que vous utilisez fréquemment sur une magnifique plate-forme sans code. 
    Je travaillais pour Innovatium depuis l'année dernière, et cette expérience m'a permis de rencontrer de nombreuses situations où il était utile de prendre en compte la mémoire utilisée dans les ensembles de résultats de requêtes, les requêtes et les tables, de temps en temps. Ce problème est facile à résoudre en créant un portail similaire à celui créé dans mon article précédent sur Django. Comme le développement avec Flask est plus rapide qu'avec Django, il serait facile de construire quelques plateformes différentes pour chaque projet et pour chaque table que nous souhaitons suivre. En outre, si vous avez un peu de temps libre, vous pouvez automatiser votre plateforme pour obtenir des mises à jour en direct avec Flask-SocktetIO.
Avoir un modèle pour démarrer vos projets peut considérablement accélérer le développement. Pour cette raison, nous allons présenter dans la section suivante un modèle de CRUD de Flask-IRIS publié sur OpenExchange (celui que nous avons construit dans la première partie de cette série d'articles). Autrement dit, si vous n'avez pas le temps d'étudier tous les détails abordés dans le dernier article, il vous suffit de télécharger l'application et de continuer à travailler en toute tranquillité sur votre projet, en vous appuyant sur les connaissances que vous avez déjà acquises.
 

L'application OpenExchange

J'ai décidé d'écrire cette série d'articles en m'inspirant de l'idée mentionnée dans l'article sur l'exemple d'application Flask avec SQLAlchemy Example of Flask application with SQLAlchemy IRIS. Cependant, puisque vous êtes déjà peut-être familier avec les frameworks web de Python et la logique de CRUD, je vais vous présenter une application qui vous permettra de prendre le taureau par les cornes. Ainsi, vous ne perdrez pas votre temps à lire avant la concrétisation de votre projet.
    Suivez les étapes ci-dessous pour télécharger et lancer l'application, commencez à l'utiliser et constatez à quel point elle est facile à mettre en œuvre. Il existe une version plus succincte du tutoriel très proche sur son utilisation sur le fichier README du référentiel GitHub associé. Vous pouvez également consulter tous les liens relatifs à l'application sur sa page Open Exchange.

Guide d'installation

    Avant de développer des projets avec Python, il est toujours préférable de configurer un environnement virtuel. Cela vous aidera à ajouter toutes les exigences, configurations et variables spécifiques à ce projet, sans affecter votre ordinateur et d'autres projets.
    Si vous utilisez Windows/Linux/macOS, ouvrez le terminal dans le répertoire où vous souhaitez démarrer votre projet et créez un environnement virtuel à l'aide de la commande suivante:
python -m venv .venv-folder
    La commande susmentionnée peut être décomposée comme suit : "python" définira un environnement Python pour les commandes suivantes, le drapeau -m lancera un module (dans ce cas, venv), et .venv-folder créera un dossier appelé venv-folder dans le répertoire courant (référencé par le point), où le module venv s'exécutera.
    La prochaine étape consistera à activer l'environnement créé avant de télécharger les prérequis et de lancer votre projet dans les règles de l'art.
    Si vous utilisez macOS ou Linux, vous devez taper “. .venv/bin/activate”. Pour Windows, la commande similaire “.venv\Scritps\activate” lancera le fichier approprié pour la tâche.
    Ensuite, vous pouvez cloner le référentiel avec la commande git clone.
git clone https://github.com/heloisatambara/flask-iris.git
    Enfin, installez la configuration requise à l'aide du paquet d'installation "Python Install Package", et vous serez prêt à commencer le codage.
pip install -r requirements.txt
    Comme vous pouvez le vérifier dans le fichier référencé, la commande ci-dessus installera au moins la version 2.3.3 de Flask, au moins la version 3.1.1 de Flask-SQLAlchemy, et au moins la version 0.10.5 de sqlalchemy-iris, par ^CaretDev.

Guide d'utilisation

    Tout d'abord, il faut connecter l'application à la base de données et à l'espace de noms souhaités. Comme vous avez sans doute appris dans l'article précédent, cette connexion se fait sur le fichier flaskr-iris/database.py, au format “iris://username:password@host:port/NAMESPACE”, selon les spécifications de la documentation SQLALchemy documentation pour la fonction create_engine(). Examinez l'exemple ci-dessous.
    engine = create_engine("iris://_SYSTEM:sys@localhost:1972/SAMPLE")
    Vous pouvez maintenant exécuter l'application web et constater que l'exemple développé fonctionne, après avoir vérifié que l'instance est en cours d'exécution, à l'aide de la commande mentionnée.
...\flask-iris> flask --app flaskr-iris run --debug
    Pour adapter l'application à vos besoins, commencez par modifier le fichier flaskr-iris/models.py pour refléter les données à transférer d'IRIS à Python. L'exemple cloné sur GitHub couvre déjà un grand nombre de cas, comme vous pouvez le vérifier dans l'article précédent, dans la section dédiée aux modèles. Si vous avez besoin d'autre chose, vous pouvez consulter la documentation Flask-SQLAlchemy ou SQLAlchemy oncernant respectivement la définition de modèles et les tables déclaratives.
    Ensuite, il est recommandé de poursuivre le développement en modifiant les fichiers dans flaskr-iris/templates, afin d'adapter l'affichage à vos données. La documentation de Jinja documentation contient toutes les options pour coder vos modèles.
    Ensuite, vous pouvez utiliser les exemples de auth.py et blog.py pour créer vos vues. N'oubliez pas d'enregistrer tous les nouveaux Blueprints dans la fabrique create_app(), dans le fichier __init__.py.
    Enfin, avec les fichiers à l'intérieur du dossier static, vous devriez gagner une longueur d'avance pour ajouter une touche de votre marque à la page web.
 

Section supplémentaire - Les erreurs que j'ai rencontrées et la façon de les corriger

  • Commençons par ce qui peut sembler être une erreur de débutant mais qui peut arriver à tout le monde : si vous avez oublié d'initialiser l'instance IRIS à laquelle vous vous connectez, vous risquez de recevoir le message suivant :
sqlalchemy.exc.OperationalError: (intersystems_iris.dbapi._DBAPI.OperationalError) [WinError 10061] No connection could be made because the target machine actively refused it.


Bien sûr, tout ce que vous avez à faire ici est d'appuyer sur " Start InterSystems IRIS " (démarrage d'InterSystems IRIS) et d'exécuter à nouveau votre application Flask.
 

  • L'erreur suivante peut sembler un peu plus difficile à résoudre :
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed an active HTTP request. Consult the documentation on testing for information about how to avoid this problem.

db.init_app(app)

    Plusieurs raisons peuvent provoquer ce type d'erreur. Si vous l'avez trouvé lors d'un test, utilisez test_client pour simuler une requête complète. Sinon, il vous faudra peut-être déplacer votre code dans une vue. Cependant, j'ai rencontré cette erreur dans une situation peu courante : Je n'avais pas initié la base de données avec l'application Flask. Pour y remédier, lorsque vous définissez votre base de données avec db = SQLAlchemy() ou quelque chose de similaire, vous pouvez vous connecter directement à l'application en faisant ce qui suit :

app = Flask(__name__)
db = SQLAlchemy(app)

Par ailleurs, si vous travaillez avec une fabrique d'applications, comme indiqué dans l'article précédent, vous pouvez connecter l'application plus tard en appelant init_app() :

db = SQLAlchemy()

defcreate_app(): app = Flask(name) db.init_app(app)

  • Si vous choisissez de suivre l'approche décrite dans la première partie de cet article, vous remarquerez peut-être qu'à chaque fois que vous exécutez votre application, celle-ci essayera de créer toutes les bases de données à partir des modèles que vous avez définis. Cela signifie que vous devrez peut-être traiter ce type d'erreur avec un bloc "try/except". Il est également possible d'ignorer l'erreur si la table existe déjà, mais il faut aussi régler d'autres problèmes. Toutefois, si vous choisissez cette solution, vous devrez peut-être supprimer toutes les tables manuellement chaque fois que vous y apporterez des modifications.  Une autre option consiste à utiliser l'attribut "checkfirst" lors de l'appel de la fonction create_all(). Cela permet d'ignorer les tables qui existent déjà, de sorte que les changements ne seront pas appliqués. Si cela correspond à vos besoins, profitez-en. Pour une mise en œuvre à plus grande échelle, vous pouvez utiliser SQLAlchemy afin de supprimer les tables précédemment créées avant d'exécuter create_all(). Attention : les tables seront créées automatiquement sous le format de nom DefaultSchema_snake_case_model_name. Pour illustrer cette idée, dans l'exemple que nous venons d'explorer les tables ont été construites dans IRIS sous les noms de SQLUser_user et SQLUser_post.
try:
with app.app_context():
db.create_all()
except DatabaseError as err:
if 'already exists' in err._sql_message():
print("Databases already exist.")
else:
print(err) 
  • Enfin, si vous placez les modèles dans un autre fichier par rapport à celui que vous avez utilisé pour exécuter la fonction create_all(), vous pouvez avoir l'impression que cette fonction échoue. Cela se produit parce les modèles que vous voulez assembler doivent être importés avant d'essayer de les fabriquer.
from .models import User, Post
db.init_app(app)
try:
with app.app_context():
db.create_all()
0
0 75
Article Iryna Mykhailova · Mars 4, 2024 24m read

Index

Partie 1

  • Présentation de Flask : une revue rapide des documents de Flask (Flask Docs), où vous trouverez toutes les informations dont vous avez besoin pour ce tutoriel;
  • Connexion à InterSystems IRIS : un guide détaillé étape par étape sur l'utilisation de SQLAlchemy pour se connecter à une instance d'IRIS;

Partie 2

  • Discussion sur cette forme de mise en œuvre : pourquoi nous devrions l'utiliser et les situations où elle est applicable.
  • L'application OpenExchange : si vous n'êtes pas intéressé par le développement de cet exemple, vous pouvez passer directement à cette section et apprendre à l'utiliser comme modèle pour votre application flask-iris.
  • Bonus : quelques erreurs commises lors du développement et comment je les ai résolues.

Présentation de Flask

Flask est un outil web écrit en Python et conçu pour vous faciliter la vie lors de la création d'une application web. Il utilise Werkzeug pour gérer l'interface Web Server Gateway Interface (WSGI) - la spécification standard de Python pour la communication avec les serveurs web. Il utilise également Jinja pour gérer les modèles HTML, et le Click CLI toolkit pour créer et gérer le code d'interface de ligne de commande.

Installation

La première étape est facultative. Cependant, c'est une bonne idée de configurer un environnement virtuel avant de commencer des projets. Vous pouvez le faire sur le terminal en modifiant le répertoire vers le dossier que vous voulez utiliser comme racine et en tapant la commande mentionnée ci-dessous.

> python -m venv .venv

Si vous optez pour un environnement virtuel, activez-le avec la commande suivante (sous Windows) avant d'installer les prérequis :

> .venv\Scripts\activate

Enfin, installez les paquets avec pip (paquetage d'installation Python).

> pip install Flask
> pip install Flask-SQLAlchemy
> pip install sqlalchemy-iris

Quickstart

Nous suivrons la structure présentée dans ce Tutoriel, en adaptant les connexions à l'IRIS. Cela minimisera vos problèmes lors de l'amélioration de votre application puisque vous pourrez consulter la Documentation de Flask sans conflits. Cependant, comme Flask est très flexible, il ne vous oblige pas à suivre des modèles, et vous pouvez considérer les étapes suivantes comme de simples suggestions.

L'approche présentée ici consiste à utiliser les applications comme des paquets et à définir une fabrique d'applications pour couvrir les grands projets. Cependant, vous pouvez toujours construire l'application Flask avec cinq lignes de code seulement, comme on le voit ci-dessous.

from flask import Flask

app = Flask(__name__)


@app.route('/')defhello():return'Hello, world!'

 

Une application modèle

Cette section présente les étapes à suivre pour créer l'application flask-iris. Ce tutoriel peut être suivi si vous n'avez jamais utilisé de framework web auparavant. Cependant, si vous voulez vraiment comprendre la théorie de ce type de flux de travail, lisez mon article précédent sur Exemples de travail avec IRIS à partir de Django, en prenant particulièrement en compte l'image au début de l'article. Vous constaterez avec satisfaction que les différents frameworks web ont une logique très similaire. Cependant, dans Flask, nous pouvons définir les URL et les vues ensemble en tant que groupes, appelés plans originaux (blueprints).

TLes conditions requises concernent Flask, Flask-SQLAlchemy et sqlalchemy-iris. Intuitivement, le pont entre l'application web et votre instance IRIS est construit !
 

Le paquet

Tout d'abord, créez ou sélectionnez le dossier que vous souhaitez utiliser comme racine. Appelons-le flaskr-iris. Nous avons besoin que Python comprenne ce dossier comme un paquet, nous devons donc créer un fichier __init_.py. C'est là que nous placerons notre fabrique d'applications.

Étape 1 - Création de la fabrique d'applications

La fabrique d'applications n'est rien de plus qu'une fonction. A l'intérieur de celle-ci, nous devons définir une instance Flask() (l'application), définir ses configurations, la connecter à la base de données, et enregistrer les blueprints si nous choisissons de les utiliser. Nous allons explorer plus en détail les blueprints plus tard, donc pour l'instant vous n'avez pas besoin de vous en préoccuper.

Cette fonction doit être appelée create_app(). Commencez par importer Flask et créez une instance avec l'argument \N_nom\N_ (consultez la documentation pour plus de détails). Ensuite, mappez la propriété config avec une clé secrète et l'URI de la base de données. Utilisez le format "dialect://username:password@host:port/NAMESPACE", en suivant les recommandations de SQLAlchemy. Dans ce cas, le dialecte devrait être 'iris', créé par CaretDev. Le nom d'utilisateur et le mot de passe sont ceux que vous utilisez pour vous connecter à l'instance InterSystems IRIS indiquée par l'hôte et le port, et l'espace de noms parle de lui-même.

# __init__.pyfrom flask import Flask

defcreate_app():# créer et configurer l'application
    app - Flask(__name__, instance_relative_config=True)

    app.config.from_mapping(
        SECRET_KEY = "dev", # remplacer celle-ci par une clé de génération aléatoire lors du déploiement
        SQLALCHEMY_DATABSE_URI = "iris://_SYSTEM:sys@loclhost:1972/SAMPLE"
    )

Les prochaines lignes de notre fabrique auront besoin de la base de données, alors réservons ce fichier pour un instant pendant que nous parlons de données et de modèles.
 

Étape 2 - Gestion des données

Nous utiliserons SQLAlchemy pour importer et gérer les données puisque nous pouvons utiliser Flask-SQLAlchemy et SQLAlchemy-IRIS pour résoudre les problèmes de connexion. Tout d'abord, il faut créer le fichier database.py dans lequel nous importerons la version Flask de SQLAlchemy et l'instancierons. Cette étape ne nécessite pas de fichier séparé. Cependant, elle peut être très utile plus tard pour développer d'autres méthodes pour gérer la base de données.

# database.pyfrom flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

Ensuite, il faut définir les modèles qui indiqueront à Python comment interpréter chaque enregistrement dans un tableau. Créez le fichier models.py, importez l'instance de SQLAlchemy et les fonctionnalités dont vous avez besoin pour traiter les données. En suivant l'exemple donné dans la documentation officielle de Flask, nous pouvons créer un blog nécessitant un modèle pour les utilisateurs et un autre pour les messages. Cette implémentation couvre un nombre substantiel de cas et vous donne une bonne longueur d'avance.

Nous allons utiliser le Mapping Objet-Relationnel (ORM) comme suggéré dans SQLAlchemy 2.0, en définissant des colonnes mappées et une relation de type Un-à-plusieurs (One-to-many). Vous pouvez vérifier comment modéliser d'autres types de relations dans le Guide de SQLAlchemy.

# models.pyfrom .database import db
from sqlalchemy.orm import Mapped, mapped_column
from typing import List, Optional
import datetime

classUser(db.Model):
    id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
    username: Mapped[str] = mapped_column(db.String(1000), unique=True, nullable=False)
    password: Mapped[str] = mapped_column(db.String(1000), nullable=False)
    posts: Mapped[List["Post"]] =  db.relationship(back_populates="user")

classPost(db.Model):
    id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
    author_id: Mapped[int] = mapped_column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    user: Mapped["User"] = db.relationship(back_populates="posts")
    created: Mapped[datetime.datetime] = mapped_column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP'))
    title: Mapped[str] = mapped_column(db.String(1000), nullable=False)
    body: Mapped[Optional[str]] = mapped_column(db.String(1000000))

Le format général à utiliser pour définir les colonnes dans la dernière version de SQLAlchemy est le suivant :

columnName: Mapped[type] = mapped_column(db.Type, arguments)

En ce qui concerne les relations, du côté des "nombreux", vous devrez également définir la clé étrangère.

Obs.: les noms des classes seront convertis de "CamelCase" en "snake_case" lors de la création des tableaux SQL.

Enfin, nous pouvons retourner à la fabrique sur _init_.py_ et faire les connexions. Importez la base de données et les modèles, assignez cette application à l'instance db, et créez toutes les tableaux à l'intérieur de la méthode create_app().

# __init__.pyfrom flask import Flask
from sqlalchemy.exc import DatabaseError

defcreate_app():# créer et configurer l'application
    app = Flask(__name__)

    app.config.from_mapping(
        SECRET_KEY="dev", # remplacer par un système aléatoire lors du déploiement
        SQLALCHEMY_DATABASE_URI = "iris://_SYSTEM:sys@localhost:1972/SAMPLE"
    )

    # avec cette application, flask initialise Alchemyfrom .database import db
    from .models import User, Post

    db.init_app(app)

    try:
        with app.app_context():
            db.create_all()
    except DatabaseError as err:
        if'already exists'in err._sql_message():
            print("Databases already exist.")
        else:
            print(err)

Ensuite, nous passerons à la création des vues.

Étape 3 - Les vues

Étape 3.1 - Les blueprints : l'authentification

Un objet Blueprint a été conçu pour organiser vos vues en groupes et les enregistrer dans l'application. Nous allons créer un Blueprint pour les vues qui traitent de l'authentification et un autre pour l'affichage, l'édition et la suppression, de sorte que cette partie du tutoriel couvrira la gestion CRUD et la gestion des sessions.
En commençant par le Blueprint d'authentification, créez le fichier auth.py et importez les utilitaires de Flask et Werkzeug, la base de données et le modèle Utilisateur. Ensuite, instanciez l'objet Blueprint, en spécifiant son nom et le préfixe de l'URL.

# auth.pyfrom flask import (
    Blueprint, request, g, redirect, url_for, flash, render_template, session
)
from werkzeug.security import generate_password_hash, check_password_hash
from .database import db
from .models import User
import functools

bp = Blueprint('auth', __name__, url_prefix='/auth')

Ensuite, nous pouvons utiliser des décorateurs pour définir des chemins pour l'enregistrement, la connexion et la déconnexion avec toutes les méthodes nécessaires. Dans notre exemple, nous utiliserons GET et POST et commencerons par l'enregistrement.

Le décorateur est accessible comme une méthode de notre Blueprint et possède un argument pour l'URL et un autre pour les méthodes qu'il accepte. À la ligne suivante, créez la fonction indiquant à l'application ce qu'elle doit faire lorsqu'elle reçoit une requête avec les paramètres correspondants. Dans l'exemple suivant, nous aurons accès à la fonction en GETtant ou POSTant l'URL http://host:port/auth/register.
 

# auth.py@bp.route('/register', methods=('GET', 'POST'))defregister():if request.method=='POST':
        pass

Si l'application reçoit un POST renvoyant à '/register', cela signifie qu'un utilisateur souhaite créer un compte. L'accès au nom d'utilisateur et au mot de passe choisis avec l'objet de contenu de la demande est géré par Flask. Ensuite, créez une instance du modèle Utilisateur, en stockant ses propriétés en tant que valeurs reçues. Vous pouvez également utiliser les méthodes werkzeug.security pour protéger le contenu sensible. Ensuite, utilisez la propriété de session de notre base de données, fournie par SQLAlchemy, pour ajouter un nouvel utilisateur au tableau et le valider. À ce stade, les informations ont déjà été envoyées au tableau correspondant dans l'instance IRIS mentionnée à la dernière étape. Enfin, redirigez l'utilisateur vers la page de connexion, que nous créerons à l'étape suivante. N'oubliez pas de traiter les erreurs telles que la réception d'entrées vides, l'intégrité de l'index et la connexion à la base de données. Vous pouvez utiliser flash() pour afficher les détails du problème à l'utilisateur. Nous pouvons également utiliser la même fonction register() pour rendre le modèle de la page d'enregistrement si GET est utilisé dans la requête.

# auth.py@bp.route('/register', methods=('GET', 'POST'))defregister():if request.method=='POST':
        username = request.form['username']
        password = request.form['password']
        error = Noneifnot username:
            error = "Username is required."elifnot password:
            error = "Password is required."if error isNone:
            try:
                user = User(
                    username=username,
                    password=generate_password_hash(password)
                )

                db.session.add(user)
                db.session.commit()
            except Exception as err: # TODO: remplacer par l'équivalent db.IntegrityError de sqlite3
                error = str(err)
            else:
                return redirect(url_for("auth.login"))

        flash(error)

    return render_template('auth/register.html')

Ensuite, nous répétons la même logique pour la page de connexion. Lorsque nous traitons un POST, nous recevons d'abord un nom d'utilisateur et un mot de passe, puis nous vérifions s'ils existent dans notre tableau IRIS. Cette fois, nous n'utiliserons pas la propriété session (bien que nous aurions pu le faire). Nous utiliserons plutôt la méthode one_or_404(). Nous devons le faire parce que le nom d'utilisateur doit être unique, comme nous l'avons défini dans notre modèle. Ainsi, si la requête ne renvoie pas précisément une ligne suite à notre demande, nous pouvons la considérer comme non trouvée. À l'intérieur de cette fonction, enchaîner des commandes SQL pour trouver le résultat requis, en utilisant les modèles comme des tableaux et leurs propriétés comme des colonnes. Enfin, on efface la session de Flask, on ajoute l'utilisateur si la connexion a été effective et on le redirige vers la page d'accueil. S'il s'agit d'un GET, envoyer l'utilisateur à la page de connexion.

#auth.py@bp.route('/login', methods=('GET', 'POST'))deflogin():if request.method=="POST":
        username = request.form['username']
        password = request.form['password']
        error = Nonetry:
            user = db.one_or_404(db.select(User).where(User.username==username))

            ifnot check_password_hash(user.password, password):
                error = "Incorrect password"except Exception as err: # TODO vérifier également cette erreur
            error = f"User {username} not found."if error isNone:
            session.clear()
            session['user_id'] = user.id
            return redirect(url_for('index'))

        flash(error)


    return render_template('auth/login.html')
    

Pour se déconnecter, il suffit d'effacer la session et de rediriger vers la page d'accueil. 

# auth.py@bp.route('/logout')deflogout():
    session.clear()
    return redirect(url_for('index'))

Pour les fonctions suivantes, nous allons traiter l'utilisateur qui se connecte sur différentes requêtes, qui ne sont pas nécessairement liées à l'authentification. L'objet 'g' de Flask est unique pour chaque demande, ce qui signifie que vous pouvez l'utiliser pour définir l'utilisateur actuel à partir de la base de données lorsque vous traitez des accès éventuellement interdits.

Heureusement, le Blueprint possède la propriété before_app_request. Elle peut être utilisée comme décorateur suivi d'une fonction pour déterminer ce qu'il convient de faire lors de la réception d'une requête avant de la traiter. Pour charger l'utilisateur connecté, nous devons à nouveau nous connecter, mais cette fois, nous obtiendrons des informations à partir de la session autres que la requête.

# auth.py@bp.before_app_requestdefload_logged_in_user():
    user_id = session.get('user_id')

    if user_id isNone:
        g.user = Noneelse:
        g.user = db.one_or_404(
            db.select(User).where(User.id==user_id)
        )

Enfin, pour notre dernière fonction d'authentification, il est possible de créer quelque chose qui traitera les vues qui doivent être interdites si l'utilisateur ne s'est pas connecté. Si vous ne voulez pas afficher un simple code 403, redirigez l'utilisateur vers la page de connexion.

# auth.pydeflogin_required(view):    @functools.wraps(view)defwrapped_view(**kwargs):if session.get('user_id') isNone:
            return redirect(url_for('auth.login'))

        return view(**kwargs)

    return wrapped_view

Étape 3.2 - Les blueprints: blog (CRUD)

Là encore, commencez par créer le fichier (appelons-le blog.py) et y importer tout ce qui est nécessaire. Cela peut sembler beaucoup de travail, mais chacune de ces importations prendra tout son sens au fur et à mesure que nous avancerons. Créez également une autre instance de Blueprint.

# blog.pyfrom flask import (
    Blueprint, flash, g, redirect, render_template, request, url_for, session
)
from werkzeug.exceptions import abort
from .auth import login_required
from .database import db
from .models import Post, User
from sqlalchemy import desc

bp = Blueprint('blog', __name__)

Tout d'abord, il faut commencer par créer l'URL par défaut, qui pointe vers la page d'accueil. Ici, nous afficherons les messages stockés dans IRIS, de sorte que la propriété de session de la base de données (qui est une instance SQLAlchemy() de Flask-SQLAlchemy) puisse être utilisée. Il y a plusieurs façons d'exécuter une requête avec le module SQLAlchemy. J'ai choisi d'utiliser la fonction scalars() avec la requête SQL comme argument, enchaînée avec la fonction all(). Vous avez peut-être vu un comportement similaire dans d'autres langages et plugins comme fetchall(). La prochaine étape sera de rendre le modèle de la page d'accueil, en passant la variable où nous avons stocké tous les messages comme argument afin de pouvoir y accéder dans les fichiers HTML. Regardez notre READ (cRud) ci-dessous :

# blog.py@bp.route('/')defindex():
    posts = db.session.scalars(
        db.select(Post).order_by(desc(Post.created))
    ).all()

    return render_template('blog/index.html', posts=posts)

Ensuite, la fonction de création (Crud) d'un nouveau message sera très similaire à l'enregistrement d'un utilisateur. Nous obtenons l'entrée de l'utilisateur à partir de la requête, définissons ses valeurs en fonction des propriétés du modèle de message Post, utilisons l'objet session de la base de données pour faire un ajout (équivalent à l'instruction SQL d'insertion) et validons. Ici, nous allons accéder à l'utilisateur actuel à partir de la requête avec l'objet g. Nous utiliserons également un second décorateur, référençant la fonction login_required(), pour rediriger l'utilisateur vers la page de connexion s'il ne s'est pas encore connecté.

# blog.py@bp.route('/create', methods=('GET', 'POST'))@login_requireddefcreate():if request.method == 'POST':
        title = request.form['title']
        body = request.form['body']
        error = Noneifnot title:
            error = 'Title is required.'if error isnotNone:
            flash(error)
        else:
            post = Post(
                title=title,
                body=body,
                author_id=g.user.id
            )
            db.session.add(post)
            db.session.commit()

            return redirect(url_for('blog.index'))

    return render_template('blog/create.html')

Pour effectuer une mise à jour (crUd), nous utiliserons une approche très similaire. Cependant, au lieu de créer une nouvelle instance de Post, nous la renverrons à partir d'une requête, puisqu'elle existe déjà dans la base de données. Nous pouvons utiliser l'URL pour recevoir un identifiant pour le message (Post). Une fois de plus, le login est nécessaire ici.

# blog.py@bp.route('//update', methods=('GET', 'POST'))@login_requireddefupdate(id):
    post = get_post(id)

    if request.method == 'POST':
        title = request.form['title']
        body = request.form['body']
        error = Noneifnot title:
            error = 'Title is required.'if error isnotNone:
            flash(error)
        else:
            post.title = title
            post.body = body

            db.session.commit()

            return redirect(url_for('blog.index'))

    return render_template('blog/update.html', post=post)

Puisque pour la suppression il nous faudra également accéder au message (Post) par l'ID, nous pouvons créer une fonction get_post(id) et l'utiliser sur les deux vues. De la même manière que pour les autres requêtes que nous avons faites jusqu'à présent, nous pouvons enchaîner les commandes SQL pour l'écrire. Puisque notre modèle pour l'utilisateur a une relation, nous pouvons sélectionner le message Post et le joindre à Utilisateur (User). De cette manière, nous pourrons accéder aux informations de l'utilisateur par le biais de l'objet résultat. Nous pouvons également utiliser abort() pour envoyer des réponses 404 (non trouvé) et 403 (interdit).

# blog.pydefget_post(id, check_author=True):
    post = db.one_or_404(
        db.select(Post).join(User).where(Post.id == id)
    )

    if post isNone:
        abort(404, f"Post id {id} doesn't exist.")

    if check_author and post.author_id != session['user_id']:
        abort(403)

    return post

Enfin, vous pouvez effectuer la suppression en utilisant simplement une fonction de suppression de la session de la base de données.

# blog.py@bp.route('//delete', methods=('POST',))@login_requireddefdelete(id):
    post = get_post(id)

    db.session.delete(post)
    db.session.commit()

    return redirect(url_for('blog.index'))

 

Étape 3.3 - Enregistrer vos blueprints

Enfin, nous pouvons achever notre fabrique d'applications en enregistrant les blueprints et en renvoyant l'application, comme indiqué ci-dessous.

# __init__.pyfrom flask import Flask
from sqlalchemy.exc import DatabaseError

defcreate_app():# créer et configurer l'application
    app = Flask(__name__)

    app.config.from_mapping(
        SECRET_KEY="dev", # remplacer par un système aléatoire lors du déploiement
        SQLALCHEMY_DATABASE_URI = "iris://_SYSTEM:sys@localhost:1972/SAMPLE"
    )

    # avec cette application, flask initialise Alchemyfrom .database import db
    from .models import User, Post
    db.init_app(app)
    try:
        with app.app_context():
            db.create_all()
    except DatabaseError as err:
        if'already exists'in err._sql_message():
            print("Databases already exist.")
        else:
            print(err)

    # enregistrer les blueprintsfrom . import auth
    app.register_blueprint(auth.bp)

    from . import blog
    app.register_blueprint(blog.bp)
    app.add_url_rule('/', endpoint='index')

    return app

 

Étape 4 - Les modèles

Vous devez avoir remarqué que chaque vue se termine par un retour redirect(), qui envoie l'utilisateur vers une autre vue ou renvoie render_template(), ce qui est explicite. Ces fonctions reçoivent des modèles HTML comme arguments, ainsi que tout autre objet que vous pourriez vouloir utiliser à l'intérieur. Cela signifie qu'à ce stade du tutoriel, vous apprendrez à accéder à votre base de données IRIS à partir d'un fichier HTML, ce qui vous permettra de gérer les données avec CSS et JavaScript, et d'évoluer vers d'autres outils de développement web.

Le chemin par défaut de votre application Flask intégrée dans un paquetage pour rechercher des modèles se trouve dans le dossier app/templates. À l'intérieur de ce dossier, il est d'usage d'ajouter un fichier base.html. Le modèle de ces fichiers est le Jinja's. Cela signifie que vous pouvez utiliser {% ... %} pour ajouter des instructions telles que des blocs, des "ifs" (si) et des "fors" (pour), en les terminant toujours (avec {% endblock %}, par exemple). Vous pouvez également utiliser {{ ... }} pour des expressions telles que l'accès aux objets que vous avez passés dans la fonction de rendu du modèle. Enfin, vous pouvez utiliser {# ... #} pour les commentaires. 

Outre les arguments passés dans les vues, vous pouvez accéder à des contextes tels que l'objet g, qui est unique pour chaque requête, et get_flashed_messages() pour afficher les arguments passés dans flash(). Étant donné que nous avons déjà vu dans les étapes précédentes comment effectuer des requêtes et passer le résultat dans le contexte de la requête, l'exemple suivant pour un fichier de base vous montrera comment accéder aux données d'IRIS en utilisant l'objet g. En plus de cela, l'exemple montrera également comment accéder aux données d'IRIS en utilisant l'objet g. En outre, il montre également comment afficher les messages flashés.
 

<!-- templates/base.html --><!DOCTYPE html><title>{% block title %}{% endblock %} - Flaskr</title><linkrel="stylesheet"href="{{ url_for('static', filename='style.css') }}"><nav><h1>Flaskr</h1><ul>
        {% if g.user %}
          <li><span>{{ g.user['username'] }}</span><li><ahref="{{ url_for('auth.logout') }}">Log Out</a>
        {% else %}
          <li><ahref="{{ url_for('auth.register') }}">Register</a><li><ahref="{{ url_for('auth.login') }}">Log In</a>
        {% endif %}
    </ul></nav><sectionclass="content"><header>
        {% block header %}{% endblock %}
    </header>
    {% for message in get_flashed_messages() %}
      <divclass="flash">{{ message }}</div>
    {% endfor %}
    {% block content %}{% endblock %}
</section>

La base étant maintenant définie, vous pouvez enfin créer d'autres pages en agrandissant ce fichier et en personnalisant les blocs. Explorez l'exemple suivant pour la page Create Posts.

<!-- templates/blog/create.html -->
{% extends 'base.html' %}

{% block header %}
    <h1>{% block title %}New Post{% endblock %}</h1>
{% endblock %}

{% block content %}
    <formmethod="post"><labelfor="title">Title</label><inputname="title"id="title"value="{{ request.form['title'] }}"required><labelfor="body">Body</label><textareaname="body"id="body">{{ request.form['body'] }}</textarea><inputtype="submit"value="Save"></form>
{% endblock %}

Le paramètre "name" (nom) de l'entrée sera la clé du dictionnaire request.form, accessible dans les vues. Les pages d'authentification (login et register) ont une syntaxe assez similaire puisqu'elles ne nécessitent qu'un seul formulaire. Cependant, vous pouvez les consulter sur mon dépôt GitHub si vous le souhaitez.

Maintenant, regardons la page d'accueil, appelée index.html.

<!-- templates/blog/index.html -->
{% extends 'base.html' %}

{% block header %}
 <h1>{% block title %}Posts{% endblock %}</h1>
 {% if g.user %}
    <aclass="action"href="{{ url_for('blog.create') }}">New</a>
 {% endif %}
{% endblock %}

{% block content %}
    {% for post in posts %}
        <articleclass="post"><header><div><h1>{{ post['title'] }}</h1><divclass="about">by {{ post.user.username }} on {{ post['created'].strftime('%Y-%m-%d') }}</div></div>
                {% if g.user['id'] == post['author_id'] %}
                    <aclass="action"href="{{ url_for('blog.update', id=post['id'] )}}">Edit</a>
                {% endif%}
            </header><pclass="body">{{ post['body'] }}</p></article>
        {% if not loop.last %}
            <hr>
        {% endif %}
    {% endfor %}
{% endblock %}

Voici quelques éléments qui valent la peine d'être examinés de plus près. Le lien pour créer un nouveau message n'apparaît que lorsque g.user confirme le vrai, ce qui signifie qu'un utilisateur s'est connecté. Il y a également une instruction "for" (pour), itérant à travers l'objet posts renvoyé par une requête sur la vue pour l'URL vide "" et transmis à ce fichier en tant qu'argument de render_template(). Pour chaque message, nous pouvons accéder au nom d'utilisateur lié à chaque utilisateur avec une syntaxe simple (post.user.username), grâce à la db.relationship ajoutée dans le modèle utilisateur User. Une autre façon d'accéder aux données est d'utiliser les messages comme des dictionnaires et d'afficher leurs propriétés avec une syntaxe d'index (comme post['title']). Portez une attention particulière à la façon dont le lien de mise à jour d'un article prend son ID comme argument et n'apparaît que si son utilisateur correspond à celui qui est actuellement connecté.

Enfin, nous avons la page de mise à jour, qui renvoie simultanément à la vue de suppression. Elle est analogue à la page Créer des messages, mais elle possède une logique particulière pour définir les valeurs par défaut à partir de la base de données. Je laisserai une illustration ci-dessous au cas où vous décideriez de l'explorer.

<!-- templates/blog/udpate.html -->
{% extends 'base.html' %}

{% block header %}
    <h1>{% block title %}Edit "{{ post['title'] }}"{% endblock %}</h1>
{% endblock %}

{% block content %}
    <formmethod="post"><labelfor="title">Title</label><inputname="title"id="title"value="{{ request.form['title'] or post['title'] }}"required><labelfor="body">Body</label><textareaname="body"id="body">{{ request.form['body'] or post['body'] }}</textarea><inputtype="submit"value="Save"></form><hr><formaction="{{ url_for('blog.delete', id=post['id']) }}"method="post"><inputtype="submit"class="danger"value="Delete"onclick="return confirm('Are you sure?');"></form>
{% endblock %}

 

Partie 5 - Ajout de fichiers statiques

Nous disposons à présent d'une interface interactive qui reçoit des informations depuis l'utilisateur jusqu'à la base de données et vice-versa, ainsi que d'objets IRIS accessibles en Python à l'aide de SQLAlchemy et de modèles créés avec la syntaxe des classes. Dans la dernière étape, nous avons également réussi à transformer ces objets en contenu d'éléments HTML, ce qui signifie que vous pouvez facilement les personnaliser et interagir avec eux à l'aide de CSS et de JavaScript.

Si l'on revient à la base HTML, on remarque la ligne contenant un lien renvoyant à l'élément stylesheet, juste au début :

Le premier argument de la fonction url_for() à l'intérieur de l'expression href est le dossier à l'intérieur de la racine où vous pouvez trouver les statiques. Le second, bien sûr, est le nom du fichier. A partir de maintenant, le concept est à vous ! Créez le fichier style.css et modifiez-le à votre guise.

C'est fait !

Avec tous les fichiers que nous avons créés, le dossier racine devrait ressembler à l'image ci-dessous :

Maintenant, rendez-vous dans le répertoire racine du terminal et tapez

flask --app flaskr-iris run --debug

Suivez ensuite le lien http://127.0.0.1:5000 pour voir comment tout fonctionne.  

Conclusion

Dans cet article, nous avons vu comment Flask rend l'apport d'informations depuis une instance IRIS vers une application web possible et facile, en la transformant en un CRUD entièrement personnalisable, avec la possibilité de se connecter à d'autres bases de données et à d'autres systèmes. Désormais, vous pouvez facilement créer, afficher, mettre à jour et supprimer des informations d'une base de données IRIS, via une interface qui vous permet non seulement de personnaliser son apparence, ainsi que de traiter les données avec n'importe quel outil Python sans difficulté.

Vous pouvez me contacter pour me faire part de vos doutes ou des idées que vous avez rencontrées après la lecture ! Dans le prochain article, j'aborderai plus en détail la théorie de cette implémentation et présenterai l'application OpenExchange développée ici. En prime, je révèlerai quelques erreurs que j'ai rencontrées et les solutions que j'ai réussi à trouver dans la dernière section.

0
0 408
Article Pierre LaFay · Mars 3, 2024 5m read

Comme la plupart d'entre vous le savent probablement déjà, depuis environ la fin de l'année 2022, InterSystems IRIS a inclus la fonctionnalité de stockage en colonnes dans sa base de données. Dans l'article d'aujourd'hui, nous allons la mettre à l'épreuve en la comparant au stockage en lignes habituel.

Stockage en colonnes

Quelle est la principale caractéristique de ce type de stockage ? Eh bien, si l'on consulte la documentation officielle nous verrons ce fantastique tableau qui explique les principales caractéristiques des deux types de stockage (par lignes ou par colonnes) :

0
0 89
Article Pierre LaFay · Mars 3, 2024 9m read

Intro

La plupart des communications serveur-client sur le web sont basées sur une structure de demande et de réponse. Le client envoie une demande au serveur et le serveur répond à cette demande. Le protocole WebSocket fournit un canal de communication bidirectionnel entre un serveur et un client, permettant aux serveurs d'envoyer des messages aux clients sans recevoir de demande au préalable. Pour plus d'informations sur le protocole WebSocket et son implémentation dans InterSystems IRIS, voir les liens ci-dessous.

Ce tutoriel est une mise à jour de ["Asynchronous Websockets -- a quick tutorial"] (https://community.intersystems.com/post/asynchronous-websockets-quick-tutorial) pour Caché 2016.2+ et InterSystems IRIS 2018.1+.

Fonctionnement asynchrone ou synchrone

Dans InterSystems IRIS, une connexion WebSocket peut être mise en œuvre de manière synchrone ou asynchrone. Le mode de fonctionnement de la connexion WebSocket entre le client et le serveur est déterminé par la propriété "SharedConnection" de la classe %CSP.WebSocket.

  • SharedConnection=1 : Fonctionnement asynchrone

  • SharedConnection=0: Fonctionnement synchrone

Une connexion WebSocket entre un client et un serveur hébergé sur une instance InterSystems IRIS comprend une connexion entre l'instance IRIS et la passerelle Web. En mode synchrone, la connexion utilise un canal privé. Dans le cas d'une opération WebSocket asynchrone, un groupe de clients WebSocket partage un pool de connexions entre l'instance IRIS et la passerelle Web. L'avantage d'une implémentation asynchrone des WebSockets est évident lorsque de nombreux clients se connectent au même serveur, car cette implémentation n'exige pas que chaque client soit traité par une connexion exclusive entre la passerelle Web et l'instance IRIS.

Dans ce tutoriel, nous mettrons en œuvre les WebSockets de manière asynchrone. Ainsi, toutes les fenêtres de chat ouvertes partagent un pool de connexions entre la passerelle Web et l'instance IRIS qui héberge la classe de serveur WebSocket.

Présentation de l'application Chat

Le "hello world" des WebSockets est une application de chat dans laquelle un utilisateur peut envoyer des messages qui sont diffusés à tous les utilisateurs connectés à l'application. Dans ce tutoriel, les composants de l'application de chat sont les suivants :

  • Serveur : implémenté dans une classe qui étend %CSP.WebSocket

  • Client: mis en œuvre par une page CSP

La mise en œuvre de cette application de chat permettra d'atteindre les objectifs suivants :

  • Les utilisateurs peuvent diffuser des messages à toutes les fenêtres de chat ouvertes

  • Les utilisateurs en ligne apparaissent dans la liste "Utilisateurs en ligne" de toutes les fenêtres de chat ouvertes.

  • Les utilisateurs peuvent changer leur nom d'utilisateur en composant un message commençant par le mot-clé "alias". Ce message ne sera pas diffusé mais mettra à jour la liste des "Utilisateurs en ligne".

  • Lorsque les utilisateurs ferment leur fenêtre de chat, ils sont retirés de la liste des "Utilisateurs en ligne".

Pour obtenir le code source de l'application de chat, veuillez consulter ce [dépôt GitHub] (https://github.com/intersystems/InterSystems-WebSockets).

Le Client

Le côté client de notre application de chat est mis en œuvre par une page CSP contenant le style de la fenêtre de chat, la déclaration de la connexion WebSocket, les événements et méthodes WebSocket qui gèrent la communication vers et depuis le serveur, et les fonctions d'aide qui regroupent les messages envoyés au serveur et traitent les messages entrants.

Tout d'abord, nous verrons comment l'application initie la connexion WebSocket à l'aide d'une bibliothèque Javascript WebSocket.

    ws = new WebSocket(((window.location.protocol === "https:")? "wss:":"ws:")
                    + "//"+ window.location.host + "/csp/user/Chat.Server.cls");

new crée une nouvelle instance de la classe WebSocket. Celle-ci ouvre une connexion WebSocket au serveur en utilisant le protocole "wss" (indique l'utilisation de TLS pour le canal de communication WebSocket) ou "ws". Le serveur est spécifié par le numéro de port du serveur web et le nom de l'hôte de l'instance qui définit la classe Chat.Server (cette information est contenue dans la variable window.location.host). Le nom de notre classe de serveur (Chat.Server.cls) est inclus dans l'URI d'ouverture de la WebSocket en tant que requête GET pour la ressource sur le serveur.

L'événement ws.onopen se déclenche lorsque la connexion WebSocket est établie avec succès, passant d'un état connecting à un état open.

    ws.onopen = function(event){
        document.getElementById("headline").innerHTML = "CHAT - CONNECTED";
    };

Cet événement met à jour l'en-tête de la fenêtre de chat pour indiquer que le client et le serveur sont connectés.

Envoi de messages

L'action d'un utilisateur qui envoie un message déclenche la fonction send. Cette fonction sert d'enveloppe à la méthode ws.send, qui contient les mécanismes d'envoi du message du client au serveur via la connexion WebSocket.

function send() {
	var line=$("#inputline").val();
	if (line.substr(0,5)=="alias"){
	    alias=line.split(" ")[1];
		if (alias==""){
		    alias="default";
		}
		var data = {}
		data.User = alias
		ws.send(JSON.stringify(data));
        } else {
	    var msg=btoa(line);
	    var data={};
	    data.Message=msg;
	    data.Author=alias;
	    if (ws && msg!="") {
		    ws.send(JSON.stringify(data));
	    }
	}
	$("#inputline").val("");
}

send compile les informations à envoyer au serveur dans un objet JSON, en définissant des paires clé/valeur en fonction du type d'information envoyée (mise à jour d'alias ou message général). btoa traduit le contenu d'un message général en une chaîne ASCII encodée en base 64.

Réception des messages

Lorsque le client reçoit un message du serveur, l'événement ws.onmessage est déclenché.

ws.onmessage = function(event) {
	var d=JSON.parse(event.data);
	if (d.Type=="Chat") {
	    $("#chat").append(wrapmessage(d));
            $("#chatdiv").animate({ scrollTop: $('#chatdiv').prop("scrollHeight")}, 1000);
	} else if(d.Type=="userlist") {
		var ul = document.getElementById("userlist");
		while(ul.firstChild){ul.removeChild(ul.firstChild)};
		$("#userlist").append(wrapuser(d.Users));
	} else if(d.Type=="Status"){
		document.getElementById("headline").innerHTML = "CHAT - connected - "+d.WSID;
	}
};

Selon le type de message reçu par le client ("Chat", "userlist" ou "status"), l'événement onmessage appelle wrapmessage ou wrapuser pour remplir les sections appropriées de la fenêtre de chat avec les données entrantes. Si le message entrant est une mise à jour d'état, l'en-tête d'état de la fenêtre de discussion est mis à jour avec l'ID WebSocket, qui identifie la connexion WebSocket bidirectionnelle associée à la fenêtre de discussion.

Composants supplémentaires du client

Une erreur dans la communication entre le client et le serveur déclenche la méthode WebSocket onerror, qui émet une alerte nous informant de l'erreur et mettant à jour l'en-tête d'état de la page.

ws.onerror = function(event) {
	document.GetElementById("headline").innerHTML = "CHAT - error";
	alert("Received error"); 
};

The onclose method is triggered when the WebSocket connection between the client and server is closed and updates the status header.

ws.onclose = function(event) {
	ws = null;
	document.getElementById("headline").innerHTML = "CHAT - disconnected";
}

Le Serveur

Le côté serveur de l'application de chat est implémenté par la classe Chat.Server, qui étend %CSP.WebSocket. Notre classe serveur hérite de diverses propriétés et méthodes de %CSP.WebSocket, dont certaines seront discutées ci-dessous. Chat.Server implémente également des méthodes personnalisées pour traiter les messages provenant du ou des client(s) et pour les diffuser.

Avant de démarrer le serveur

OnPreServer() est exécutée avant la création du serveur WebSocket et est héritée de la classe %CSP.WebSocket.

Method OnPreServer() As %Status
{
    set ..SharedConnection=1
    if (..WebSocketID '= ""){ 
        set ^Chat.WebSocketConnections(..WebSocketID)=""
    } else {
        set ^Chat.Errors($INCREMENT(^Chat.Errors),"no websocketid defined")=$HOROLOG 
    }
    Quit $$$OK
}

Cette méthode définit le paramètre de classe SharedConnection à 1, indiquant que notre connexion WebSocket sera asynchrone et supportée par plusieurs processus qui définissent les connexions entre l'instance InterSystems IRIS et la Web Gateway. Le paramètre SharedConnection ne peut être modifié que dans OnPreServer(). OnPreServer() stocke également l'identifiant WebSocket associé au client dans le global ^Chat.WebSocketConnections.

La méthode Server

L'essentiel de la logique exécutée par le serveur est contenu dans la méthode Server().``` Method Server() As %Status { do ..StatusUpdate(..WebSocketID) for { set data=..Read(.size,.sc,1) if ($$$ISERR(sc)){ if ($$$GETERRORCODE(sc)=$$$CSPWebSocketTimeout) { //$$$DEBUG("no data") } if ($$$GETERRORCODE(sc)=$$$CSPWebSocketClosed){ kill ^Chat.WebSocketConnections(..WebSocketID) do ..RemoveUser($g(^Chat.Users(..WebSocketID))) kill ^Chat.Users(..WebSocketID) quit // Client closed WebSocket } } else{ if data["User"{ do ..AddUser(data,..WebSocketID) } else { set mid=$INCREMENT(^Chat.Messages) set ^Chat.Messages(mid)=data do ..ProcessMessage(mid) } } } Quit $$$OK }

Cette méthode lit les messages entrants du client (en utilisant la méthode `Read` de la classe `%CSP.WebSockets`), ajoute les objets JSON reçus au global `^Chat.Messages`, et appelle `ProcessMessage()` pour transmettre le message à tous les autres clients de chat connectés. Lorsqu'un utilisateur ferme sa fenêtre de chat (mettant ainsi fin à la connexion WebSocket avec le serveur), l'appel à `Read` de la méthode `Server()` renvoie un code d'erreur qui évalue la macro `$$CSPWebSocketClosed` et la méthode procède à la gestion de la fermeture en conséquence.

### *Traitement et distribution des messages*

`ProcessMessage()` ajoute des métadonnées au message de chat entrant et appelle `SendData()`, en passant le message en paramètre.  

ClassMethod ProcessMessage(mid As %String) { set msg = ##class(%DynamicObject).%FromJSON($GET(^Chat.Messages(mid))) set msg.Type="Chat" set msg.Sent=$ZDATETIME($HOROLOG,3) do ..SendData(msg) }


`ProcessMessage()` récupère le message au format JSON dans le global `^Chat.Messages` et le convertit en un objet IRIS d'InterSystems en utilisant la méthode `%FromJSON` de la classe `%DynamicObject`. Cela nous permet d'éditer facilement les données avant de transmettre le message à tous les clients de chat connectés. Nous ajoutons un attribut `Type` avec la valeur "Chat", que le client utilise pour déterminer comment traiter le message entrant. `SendData()` envoie le message à tous les autres clients de chat connectés.```
ClassMethod SendData(data As %DynamicObject)
{
    set c = ""
    for {
        set c = $order(^Chat.WebSocketConnections(c))
        if c="" Quit
        set ws = ..%New()
        set sc = ws.OpenServer(c)
        if $$$ISERR(sc) { do ..HandleError(c,"open") } 
        set sc = ws.Write(data.%ToJSON())
        if $$$ISERR(sc) { do ..HandleError(c,"write") }
    }
}

SendData() convertit l'objet InterSystems IRIS en une chaîne JSON (data.%ToJSON()) et envoie le message à tous les clients du chat. SendData() récupère l'ID WebSocket associé à chaque connexion client-serveur dans le global ^Chat.WebSocketConnections et utilise l'ID pour ouvrir une connexion WebSocket via la méthode OpenServer de la classe %CSP.WebSocket. Nous pouvons utiliser la méthode OpenServer car nos connexions WebSocket sont asynchrones - nous puisons dans le pool existant de processus IRIS-Web Gateway et attribuons à l'un d'entre eux l'ID WebSocket qui identifie la connexion du serveur à un client de chat spécifique. Enfin, la méthode Write()%CSP.WebSocket` envoie la représentation JSON du message au client.

Conclusion

Cette application de chat montre comment établir des connexions WebSocket entre un client et un serveur hébergés par InterSystems IRIS. Pour en savoir plus sur le protocole et son implémentation dans InterSystems IRIS, consultez les liens dans l'introduction.

0
0 199
Article Sylvain Guilbaud · Fév 23, 2024 5m read

Dans cet article, je partagerai le thème que nous avons présenté lors du Global Summit 2023, dans la salle Tech Exchange. Moi et @Rochael Ribeiro

Lors de cette présentation, nous abordons les sujets suivants :

  • Outils Open Exchange pour des API rapides
  • Spécification de l'Open API
  • Développement d'API traditionnel ou Fast
  • API composite (interopérabilité)
  • Approche Spec-First ou Api-First
  • Gouvernance et surveillance des API
  • Démo (vidéo)

Outils Exchange ouverts pour des API Fast

0
2 113
Annonce Irène Mykhailova · Fév 7, 2024

Chers membres de la Communauté,

Les premiers mois de l'année sont le moment de faire le bilan de l'année précédente et de récompenser les participants qui ont le plus contribué au développement de notre Communauté et nos portails voisins. Dans l'annonce original, les meilleurs développeurs et les applications les plus téléchargées dans 2023 étaient remarqués ! Je suis extrêmement heureuse de constater que parmi les meilleurs il y a aussi des membres actifs de notre communauté francophone !

1
0 49
Article Pierre LaFay · Jan 13, 2024 3m read

ZPM est un gestionnaire de packages conçu pour un déploiement pratique d'applications et de modules sur la plateforme IRIS.

Les développeurs de modules, pour que leur module soit installé à l'aide de ZPM, doivent suivre une série d'étapes simples.

  • Écrire le code du module
  • Créez un fichier module.xml qui contient la méta description du module
  • A l'aide du registre de test, publiez le module, vérifiez qu'il est publié
  • Installez le module à partir du registre de test
  • Publier le module. Pour publier dans le registre public pm.community.intersystems.com, vous devez publier le module dans https://openexchange.intersystems.com, en spécifiant l'URL github de votre package et cochez la case « Publier dans le gestionnaire de packages ».

La création manuelle d'un fichier module.xml peut être fastidieuse, donc la commande generate sera désormais créée dans zpm (à partir de la version 0.2.3).

La commande generate sert à créer module.xml pour votre projet.

Mode d'emploi:##

Exécuter zpm dans le terminal Et puis entrer « generate »

USER>zpm
zpm: USER>generate /temp/zzz

En argument (dans ce cas /temp/zzz), spécifiez le chemin d'accès au répertoire contenant votre projet. Le fichier module.xml sera créé dans ce répertoire.

Répondre ensuite aux questions : zpm: USER>generate /temp/zzz

Enter module name: my-module
Enter module version: 1.0.0 => 1.0.1
Enter module description: module description
Enter module keywords: test,zpm,docker
Enter module source folder: src => 

Existing Web Applications:
    /csp/user
    /registry
    Enter a comma separated list of web applications or * for all: /csp/user
    Enter path to csp files for /csp/user:  web
Dependencies:
    Enter module:version or empty string to continue: sslclient:*  
    Enter module:version or empty string to continue: 
zpm: USER>
  • module source folder – chemin relatif vers votre code (classes, routines), généralement src. Toutes les classes et routines de ce dossier sont chargées dans l'espace de noms actuel.
  • Si votre module inclut des applications Web, indiquez quelles applications Web de l'espace de noms actuel doivent être ajoutées à module.xml
  • Si votre module contient des dépendances, précisez le module et sa version. Utilisez * pour la dernière version.

Si vous devez ajouter des informations sur l'auteur et la licence à module.xml, utilisez le modificateur -author (-a).

zpm: USER>generate -author /temp/zzz

La commande generate prend également en charge une option différente : utilisez le modificateur -template (-t). Le module.xml est créé avec les données fictives, que vous devez modifier manuellement.

zpm: USER>generate -template /temp/zzz

Cette vidéo montre l'usage de generate.

1
1 60
Article Pierre LaFay · Jan 9, 2024 1m read

AnalyzeThis est un outil permettant d'obtenir un aperçu personnalisé de vos propres données dans InterSystems BI. Cela vous permet d'acquérir une expérience directe d'InterSystems BI et de comprendre la puissance et la valeur qu'elle peut apporter à votre organisation. En plus d'obtenir un aperçu personnalisé d'InterSystems BI grâce à l'importation d'un fichier CSV avec vos données, les classes et les requêtes SQL sont désormais prises en charge comme sources de données dans la v1.1.0 !

0
0 45
Article Pierre LaFay · Jan 7, 2024 1m read

Si l'un de vos packages sur OEX reçoit un avis, vous êtes informé par OEX uniquement de VOTRE propre package.
La note reflète l'expérience de l'évaluateur avec le statut trouvé au moment de l'examen.
Il s'agit en quelque sorte d'un instantané et a peut-être changé entre-temps.
Les avis des autres membres de la communauté sont marqués d'un * dans la dernière colonne.

J'ai également placé un certain nombre de requêtes Pull sur GitHub lorsque j'ai trouvé un problème que je pouvais résoudre.
Certaines ont été acceptées et fusionnées, d’autres simplement ignorées.
Donc, si vous avez apporté un changement majeur et que vous attendez un avis modifié, faites-le-moi savoir.

0
0 33
Question Laurent Jouron · Déc 11, 2023

Bonjour,

Je suis en train de faire un test avec django sur notre base de données. Le but étant de créer une API pour voir la réactivité de celle-ci.

J'ai créé le projet sans problème, j'ai réussi à créer les 16 000 lignes de models avec inspect_db. Tout se passait bien jusqu'au moment où j'ai voulu testé mon projet, 'Accès refusé'.

De ce que j'ai pu voir, Il n'y aurait pas d'erreur de code, car les seules erreurs retournées sont les suivantes.

Je ne pense pas que ce soit un problème majeur, plutôt un manque de pratique sur votre système. Auriez-vous une idée à me soumettre?

3
0 116
Article Iryna Mykhailova · Oct 13, 2023 12m read

La série d'articles relatifs à l'application QuinielaML se poursuit. Dans cet article, nous verrons comment préparer les données brutes que nous avons capturées à l'aide de la fonctionnalité Embedded Python.

Bienvenue à toutes et à tous !

Happy Artist GIF by VIRTUTE - Find & Share on GIPHY

Introduction

Si vous vous souvenez de l'article précédent, nous avons capturé les données des résultats des matches de football de première et deuxième division pour les 23 dernières années en utilisant Embedded Python à partir d'un site web externe. Maintenant que nous disposons des données brutes, nous allons les transformer et les préparer pour faciliter la maintenance de l'application et l'utilisation de notre modèle de prédiction.

QUINIELA_Object.RawMatch

Voyons sous quelle forme se présentent les données que nous avons saisies dans notre base de données IRIS :

Comme vous le voyez dans la capture d'écran suivante, elles sont peu différentes des informations présentes sur le site web de BDFutbol :

 

Tableaux principaux :

Pour faciliter la maintenance ultérieure des données communes et améliorer les performances du modèle de prédiction, nous avons défini deux tableaux principaux pour stocker les équipes et les arbitres. Ces tableaux ne comprendront que la colonne contenant l'identifiant de l'enregistrement et le nom. Examinons les deux tableaux :

QUINIELA_Object.Referee:

Сorrespondance avec le tableau principal d'arbitres.

QUINIELA_Object.Team

Сorrespondance avec le tableau principal d'arbitres.

 

Préparation de données

Avec nos tableaux principaux et nos données brutes, nous pouvons maintenant entreprendre le processus de préparation de ces données en vue de la formation de notre modèle. Nous avons ici l'opération métier qui sera chargée de la préparation :

Class QUINIELA.BO.PrepareBO Extends Ens.BusinessOperation
{

Parameter INVOCATION = "Queue";
Method PrepareData(pRequest As QUINIELA.Message.PrepareRequest, pResponse As QUINIELA.Message.PrepareResponse) As%Status
{
    Set sc = $$$OKset pResponse = ##class(QUINIELA.Message.PrepareResponse).%New()
    set pResponse.Operation = pRequest.Operation
    
    set sqlTruncateTrain = "TRUNCATE TABLE QUINIELA_Object.MatchTrain"set statementTruncateTrain = ##class(%SQL.Statement).%New()
    set statusTruncateTrain = statementTruncateTrain.%Prepare(sqlTruncateTrain)
    if ($$$ISOK(statusTruncateTrain)) {
        set resultSetTruncateTrain = statementTruncateTrain.%Execute()
        if (resultSetTruncateTrain.%SQLCODE = 0) {
            set sqlMatchTrain = "INSERT INTO QUINIELA_Object.MatchTrain (Day, Division, Journey, LocalTeam, Referee, Result, VisitorTeam, IntDay) "_
                "SELECT "_
                "TO_DATE(RM.Day,'DD/MM/YYYY') AS DayTransformed, "_
                "RM.Division, "_
                "RM.Journey, "_
                "LT.ID as LocalTeam, "_
                "R.ID as Referee, "_
                "CASE WHEN CAST(RM.GoalsLocal As INTEGER) > CAST(RM.GoalsVisitor As INTEGER) THEN 1 WHEN CAST(RM.GoalsLocal As INTEGER) < CAST(RM.GoalsVisitor As INTEGER) THEN 2 ELSE 0 END as Result, "_
                "VT.ID as VisitorTeam, "_
                "CAST({fn CONCAT({fn CONCAT(SUBSTR(RM.Day,7,4),SUBSTR(RM.Day,4,2))},SUBSTR(RM.Day,1,2))} As INTEGER) as IntDay "_
                "FROM "_
                "QUINIELA_Object.RawMatch RM "_
                "LEFT JOIN QUINIELA_Object.Team LT ON UPPER(RM.LocalTeam) = UPPER(LT.Name) "_
                "LEFT JOIN QUINIELA_Object.Team VT ON UPPER(RM.VisitorTeam) = UPPER(VT.Name) "_
                "LEFT JOIN QUINIELA_Object.Referee R ON UPPER(RM.Referee) = UPPER(R.Name)"set statementMatchTrain = ##class(%SQL.Statement).%New()
            set statusMatchTrain = statementMatchTrain.%Prepare(sqlMatchTrain)
            if ($$$ISOK(statusMatchTrain)) {
                set resultSetMatchTrain = statementMatchTrain.%Execute()
                if (resultSetMatchTrain.%SQLCODE = 0) {
                    set sqlUpdateLocalStreak = "UPDATE QUINIELA_Object.MatchTrain SET QUINIELA_Object.MatchTrain.LocalStreak = "_
                        "(SELECT SUM(CASE WHEN IsVictory = 1 THEN 4-%VID ELSE 0 END) FROM "_
                        "(SELECT TOP 3 SubMatch.IntDay, "_
                        "CASE WHEN Result = 1 THEN 1 ELSE 0 END AS IsVictory "_
                        "FROM QUINIELA_Object.MatchTrain AS SubMatch "_
                        "WHERE "_
                        "UPPER(SubMatch.LocalTeam) = UPPER(QUINIELA_Object.MatchTrain.LocalTeam) "_
                        "AND SubMatch.IntDay < QUINIELA_Object.MatchTrain.IntDay "_
                        "ORDER BY SubMatch.IntDay DESC)) "set statementUpdateLocalStreak = ##class(%SQL.Statement).%New()
                    set statusUpdateLocalStreak = statementUpdateLocalStreak.%Prepare(sqlUpdateLocalStreak)
                    if ($$$ISOK(statusUpdateLocalStreak)) {
                        set resultSetUpdateLocalStreak = statementUpdateLocalStreak.%Execute()
                        if (resultSetUpdateLocalStreak.%SQLCODE = 0) {
                            set sqlUpdateVisitorStreak = "UPDATE QUINIELA_Object.MatchTrain SET QUINIELA_Object.MatchTrain.VisitorStreak = "_
                                "(SELECT SUM(CASE WHEN IsVictory = 1 THEN 4-%VID ELSE 0 END) FROM "_
                                "(SELECT TOP 3 SubMatch.IntDay, "_
                                "CASE WHEN Result = 2 THEN 1 ELSE 0 END AS IsVictory "_
                                "FROM QUINIELA_Object.MatchTrain AS SubMatch "_
                                "WHERE "_
                                "UPPER(SubMatch.VisitorTeam) = UPPER(QUINIELA_Object.MatchTrain.VisitorTeam) "_
                                "AND SubMatch.IntDay < QUINIELA_Object.MatchTrain.IntDay "_
                                "ORDER BY SubMatch.IntDay DESC)) "set statementUpdateVisitorStreak = ##class(%SQL.Statement).%New()
                            set statusUpdateVisitorStreak = statementUpdateVisitorStreak.%Prepare(sqlUpdateVisitorStreak)
                            if ($$$ISOK(statusUpdateVisitorStreak)) {
                                set resultSetUpdateVisitorStreak = statementUpdateVisitorStreak.%Execute()
                                set sc = statusUpdateVisitorStreak
                            }
                            else {
                                set sc = statusUpdateVisitorStreak
                            }
                        }
                    }
                    else {
                        set sc = statusUpdateLocalStreak
                    }
                }
            }
            else {
                set sc = statusMatchTrain
            }
        }
    }
    
    set pResponse.Status = "Finished"Return sc
}

XData MessageMap
{
"QUINIELA.Message.PrepareRequest">
    PrepareData
}

}

Examinons maintenant en détail chacune des instructions SQL que nous exécutons :

  1. Nous quittons le tableau de données d'apprentissage :

    TRUNCATETABLE QUINIELA_Object.MatchTrain
  2. Nous lançons une insertion massive dans notre tableau d'apprentissage QUINIELA_Object.MatchTrain

    INSERTINTO QUINIELA_Object.MatchTrain (Day, Division, Journey, LocalTeam, Referee, Result, VisitorTeam, IntDay)
    SELECTTO_DATE(RM.Day,'DD/MM/YYYY') AS DayTransformed,
    RM.Division,
    RM.Journey,
    LT.ID as LocalTeam,
    R.ID as Referee,
    CASEWHENCAST(RM.GoalsLocal AsINTEGER) > CAST(RM.GoalsVisitor AsINTEGER) THEN1WHENCAST(RM.GoalsLocal AsINTEGER) < CAST(RM.GoalsVisitor AsINTEGER) THEN2ELSE0ENDasResult,
    VT.ID as VisitorTeam,
    CAST({fn CONCAT({fn CONCAT(SUBSTR(RM.Day,7,4),SUBSTR(RM.Day,4,2))},SUBSTR(RM.Day,1,2))} AsINTEGER) as IntDay
    FROM
    QUINIELA_Object.RawMatch RM
    LEFTJOIN QUINIELA_Object.Team LT ONUPPER(RM.LocalTeam) = UPPER(LT.Name)
    LEFTJOIN QUINIELA_Object.Team VT ONUPPER(RM.VisitorTeam) = UPPER(VT.Name)
    LEFTJOIN QUINIELA_Object.Referee R ONUPPER(RM.Referee) = UPPER(R.Name)
    Pour y parvenir, nous remplaçons le libellé par le nom de l'arbitre et les équipes par leur référence dans les tableaux principaux. Nous obtenons également le résultat à partir des scores du match, 0 pour le match nul, 1 pour la victoire à domicile et 2 pour la victoire à l'extérieur. La colonne
**Résultat** est celle qui définit notre modèle de prédiction comme un modèle de classification, c'est-à-dire que chaque correspondance est classée dans l'une des trois classes (1, X ou 2).  
  1. Nous calculons les séries pour chaque équipe selon qu'elle joue à domicile ou à l'extérieur. Nous avons ajouté ces colonnes pour améliorer, autant que possible, la performance du modèle prédictif. Nous avons supposé qu'une équipe qui a plusieurs victoires consécutives à domicile ou à l'extérieur a plus de facilité à poursuivre les victoires en étant "sur une série". Le calcul se fait de la manière suivante : on obtient les 3 derniers matchs (à domicile pour l'équipe qui joue à domicile ou à l'extérieur pour celle qui joue à l'extérieur), si elle a gagné le dernier match on lui attribue 3 points, si elle a gagné le match avant-dernier on lui attribue 2 points et si elle a gagné le match précédent avant-dernier on lui attribue 1 point, enfin on additionne les points obtenus ce qui donne une valeur numérique à la série. Série à domicile :
UPDATE QUINIELA_Object.MatchTrain SET QUINIELA_Object.MatchTrain.LocalStreak = 
    (SELECTSUM(CASEWHEN IsVictory = 1THEN4-%VID ELSE0END) FROM
        (SELECT TOP 3 SubMatch.IntDay, 
            CASEWHENResult = 1THEN1ELSE0ENDAS IsVictory 
        FROM QUINIELA_Object.MatchTrain AS SubMatch 
        WHEREUPPER(SubMatch.LocalTeam) = UPPER(QUINIELA_Object.MatchTrain.LocalTeam) 
            AND SubMatch.IntDay < QUINIELA_Object.MatchTrain.IntDay 
        ORDERBY SubMatch.IntDay DESC
        )
    )

Série à l'extérieur:

UPDATE QUINIELA_Object.MatchTrain SET QUINIELA_Object.MatchTrain.VisitorStreak = 
    (SELECTSUM(CASEWHEN IsVictory = 1THEN4-%VID ELSE0END) 
    FROM
        (SELECT TOP 3 SubMatch.IntDay, 
            CASEWHENResult = 2THEN1ELSE0ENDAS IsVictory 
        FROM QUINIELA_Object.MatchTrain AS SubMatch 
        WHEREUPPER(SubMatch.VisitorTeam) = UPPER(QUINIELA_Object.MatchTrain.VisitorTeam) 
            AND SubMatch.IntDay < QUINIELA_Object.MatchTrain.IntDay 
            ORDERBY SubMatch.IntDay DESC
        )
    )

Voyons quel est le résultat de cette série d'insertions et de mises à jour consultant le tableau QUINIELA_Object.MatchTrain :

Comme vous voyez, nous avons transformé les champs de texte en valeurs numériques... ou non ? Examinons la définition de la classe :

Class QUINIELA.Object.MatchTrain Extends (%Persistent, %JSON.Adaptor) [ DdlAllowed ]
{

/// Jour du matchProperty Day As%Date;/// Équipe localeProperty LocalTeam As%String;/// Équipe jouant à l'extérieurProperty VisitorTeam As%String/// Série localeProperty LocalStreak As%Integer;/// Série de victoires de l'équipe jouant à l'extérieurProperty VisitorStreak As%Integer/// ArbitreProperty Referee As%String;/// RésultatProperty Result &As%String/// DivisionProperty Division As%String;/// ItinéraireProperty Journey As%String;/// Nombre entier de joursProperty IntDay As%Integer;
}

Comme vous voyez, les références aux tableaux principaux sont toujours de type %String. Pourquoi ? Sur cette page vous trouverez l'explication de la documentation, mais en résumé, c'est parce que, bien qu'elles soient réellement numériques, elles ne correspondent pas à des valeurs quantifiables, mais à des identifiants.

Parfait, nous avons maintenant tout ce qu'il faut pour créer et former notre modèle prédictif.

Création et formation du modèle prédictif

Grâce à la fonctionnalité d'IntegratedML, cette étape est très simple pour nous, puisqu'il nous suffit d'exécuter deux commandes simples dans notre base de données. Examinons la transaction métier que nous avons créée à cette fin :

Class QUINIELA.BO.TrainBO Extends Ens.BusinessOperation
{

Parameter INVOCATION = "Queue";/// Description
Method CreateAndTrainModel(pRequest As QUINIELA.Message.TrainRequest, pResponse As QUINIELA.Message.TrainResponse) As%Status
{
        Set tSC = $$$OKset pResponse = ##class(QUINIELA.Message.TrainResponse).%New()
        set pResponse.Operation = pRequest.Operation
        set pResponse.Status = "In Process"set sql = "SELECT MODEL_NAME FROM INFORMATION_SCHEMA.ML_MODELS WHERE MODEL_NAME = 'QuinielaModel'"set statement = ##class(%SQL.Statement).%New()
        set status = statement.%Prepare(sql)
        $$$TRACE(status)
        if ($$$ISOK(status)) {
            set resultSet = statement.%Execute()
            $$$TRACE(resultSet.%SQLCODE)
            if (resultSet.%SQLCODE = 0) {
                while (resultSet.%Next() '= 0) {
                    if (resultSet.%GetData(1) '= "") {
                        set sqlDrop = "DROP MODEL QuinielaModel"set statementDrop = ##class(%SQL.Statement).%New()
                        set statusDrop = statementDrop.%Prepare(sqlDrop)
                        if ($$$ISOK(statusDrop)) {
                            set resultSetDrop = statementDrop.%Execute()
                            if (resultSetDrop.%SQLCODE = 0) {
                                set tSC = statusDrop                                                                
                            }
                        }
                    }
                }
            }            
        }
        $$$TRACE("Creating model")
        set sqlCreate = "CREATE MODEL QuinielaModel PREDICTING (Result) FROM QUINIELA_Object.MatchTrain"set statementCreate = ##class(%SQL.Statement).%New()
        set statusCreate = statementCreate.%Prepare(sqlCreate)
        if ($$$ISOK(statusCreate)) {
            $$$TRACE("Model created")
            set resultSetCreate = statementCreate.%Execute()
            if (resultSetCreate.%SQLCODE = 0) {
                set tSC = statusCreate                                
            }
        }
        else
        {
            set tSC = statusDrop
        }

        $$$TRACE("Training model")
        set sqlTrain = "TRAIN MODEL QuinielaModel"set statementTrain = ##class(%SQL.Statement).%New()
        set statusTrain = statementTrain.%Prepare(sqlTrain)
        if ($$$ISOK(statusTrain)) {
            set resultSetTrain = statementTrain.%Execute()
            if (resultSetTrain.%SQLCODE = 0) {
                // VALIDATION OF THE MODEL WITH THE PRE-LOADED MATCHESset sqlValidate = "VALIDATE MODEL QuinielaModel FROM QUINIELA_Object.MatchTrain"set statementValidate = ##class(%SQL.Statement).%New()
                set statusValidate = statementValidate.%Prepare(sqlValidate)
                set resultSetValidate = statementValidate.%Execute()
                set tSC = statusValidate                                    
            }
        }
        else {
            set tSC = statusTrain
        }
        
        set pResponse.Status = "Finished"Return tSC
}

XData MessageMap
{
"QUINIELA.Message.TrainRequest">
    CreateAndTrainModel
}

}

Analysons ce que fait notre BO :

  1. Création du modèle prédictif et définition de la valeur à prédire en indiquant la colonne de notre tableau d'entraînement correspondant.

    CREATEMODEL QuinielaModel PREDICTING (Result) FROM QUINIELA_Object.MatchTrain
  2. Formation de notre modèle nouvellement créé.

    TRAIN MODEL QuinielaModel
  3. Validation du modèle créé sur la base du tableau d'entraînement utilisé.

    VALIDATE MODEL QuinielaModel FROM QUINIELA_Object.MatchTrain

Avec ces trois étapes très simples, notre modèle est prêt à générer des prédictions. Examinons la qualité de notre modèle. Pour ce faire, exécutons la requête suivante :

SELECT * FROM INFORMATION_SCHEMA.ML_VALIDATION_METRICS

Avec cette requête, nous obtiendrons les mesures suivantes :

Eh bien, pas si mal, pour la victoire au niveau local, le taux de réussite est de 52%, pour la victoire au niveau des visiteurs de 41% et pour les matchs nuls de 37%, nous dépassons le taux de réussite de 33% dû au pur hasard !

<img alt="Boxing Memes on X: "Le compatriote de Golovkin réagit à sa victoire... #GolovkinGeale http://t.co/MDW6F5eJlz" / X" src="https://pbs.twimg.com/media/BthSZmaIcAAsIXU.jpg">

0
0 91
Article Iryna Mykhailova · Oct 6, 2023 5m read

Bienvenue chers membres de la Communauté à la présentation et au premier article d'un petit projet qui présentera les capacités d'InterSystems IRIS à fournir une fonctionnalité de sauvegarde complète pour une application web développée en Angular. Dans cet article, nous nous contenterons de présenter le concept ainsi que les fonctionnalités d'InterSystems IRIS utilisées de manière générale, en allant plus en détail dans les articles suivants.

Bienvenue à QuinielaML !

Introduction

Peut-être avez-vous déjà entendu parler des fonctionnalités d'InterSystems IRIS comme Embedded Python et IntegratedML, mais certainement n'avez-vous pas eu l'occasion de les utiliser ou vous ne savez tout simplement pas comment intégrer ces fonctionnalités dans votre quotidien. Profitant du début de la saison de football en Espagne, j'ai pensé que ce serait une excellente occasion d'expliquer toutes ces fonctionnalités d'InterSystems IRIS en développant une application qui nous aide à prédire les résultats du football et à devenir millionnaires avec le Quiniela.

Qu'est-ce que Quiniela ?

Lord Of The Rings Smeagol GIF - Lord Of The Rings Smeagol Gollum - DDécouvrez et partagez des

Pour ceux d'entre vous qui ne connaissent pas ce terme, la Quiniela est un type de pari sportif très célèbre en Espagne car, pendant plusieurs années, il s'agissait du seul format de pari sportif légal.

Grosso modo, la Quiniela est un type de pari sportif qui consiste à deviner qui sera le vainqueur de 15 matchs à chaque tour (10 matchs de première division et 5 matchs de deuxième division). La victoire de l'équipe locale est marquée par un 1, celle de l'équipe visiteuse par un 2 et l'égalité par un X.

Voici un billet de la Quiniela.

Quiniela Elige8, el nuevo juego asociado a la quiniela. - Loteria Cano

Comment prédire les résultats du Quiniela ?

Nous ne pouvons pas vraiment prédire un résultat, mais nous pouvons estimer la probabilité de chaque résultat en fonction de certaines variables. Ici, nous avons pris en compte les éléments suivants :

  1. Résultats historiques : résultats des matches entre deux équipes depuis 2000.
  2. Série de victoires de l'équipe locale : L'équipe qui reçoit a gagné les 3 derniers matchs à domicile.
  3. Série de victoires de l'équipe jouant à l'extérieur : Victoire de l'équipe jouant à l'extérieur lors des derniers matches joués à l'extérieur.
  4. Arbitre : résultat des équipes selon l'arbitre.

Comment obtenir toutes ces données pour construire notre modèle de prédiction ?

Le web scraping à la rescousse ! Toutes ces données historiques sont accessibles sur le web, il nous suffira donc d'implémenter à partir de notre IRIS un moyen d'obtenir ces données depuis un site web particulier, pour notre exemple nous avons utilisé BDFutbol, qui nous fournit des données concernant tous les matchs joués historiquement à la fois en première et en deuxième division.

Comment pouvons-nous effectuer un tel web scraping ? Très simplement, avec Embedded Python, il nous suffit d'importer les bibliothèques Python beautifulsoup4 et requests dans notre serveur IRIS et nous serons en mesure d'obtenir les informations nécessaires à partir du site web en question.

Architecture du projet

En tant qu'ancien développeur, j'ai choisi Angular pour développer la partie interface utilisateur et ainsi éviter de trop me compliquer la vie. Il est évident que le choix du backend se portera sur InterSystems IRIS avec la fonctionnalité IntegratedML incluse dans sa version communautaire.

Voici un petit schéma de l'architecture choisie :

Comment le déployer et le former :

L'ensemble du projet est Dockerisé, donc il vous suffit de télécharger le code source depuis GitHub sur votre ordinateur local, d'installer Docker et Docker Compose et d'exécuter les instructions suivantes depuis le terminal, dans le chemin d'accès où vous avez téléchargé le projet :

docker-compose build
docker-compose up -d

Une image IRIS d'InterSystems sera automatiquement déployée sur le port 52774 (en utilisant l'accès habituel au portail de gestion) et l'application Angular directement à cette URL.

Accès à QuinielaML

Une fois la page de connexion ouverte, il faut saisir le nom d'utilisateur et le mot de passe :

superuser / SYS

Celle-ci sera redirigée directement vers l'écran des prédictions, mais il est nécessaire d'afficher le menu latéral en cliquant sur l'icône de l'application en haut à gauche :

Et choisir **Gestion des données ** dans le menu :

Nous accédons ainsi à l'écran à partir duquel nous pouvons importer les données du site web BDFutbol, les préparer pour calculer les stries et modifier les valeurs textuelles en format numérique, et enfin créer le modèle de données et le former à l'aide des données préparées.

Vous devez commencer par la première option à gauche et vous déplacer dans la direction des flèches, en attendant que l'étape précédente soit terminée :

Génération de prédictions :

Une fois le modèle formé, il ne nous reste plus qu'à entrer les matchs de la journée que nous voulons prédire. Pour ce faire, nous cliquerons sur l'icône de l'application en haut à gauche et choisirons Prédiction de résultats

Sur cet écran, il suffit de remplir les champs en haut pour générer une prédiction adéquate, il suffit d'ajouter les données des équipes pour générer la prédiction, mais plus il y a de données, mieux c'est.

La partie frontend n'a pas été entièrement revue, donc vous pouvez trouver un bug, n'hésitez pas à me le faire savoir pour que je puisse l'améliorer.

Pour chaque match que vous enregistrez, vous verrez automatiquement la prédiction du résultat fournie par le modèle. Une fois la ronde terminée, vous pouvez entrer le résultat pour avoir une idée de la prédiction approximative en cliquant sur le match en question.

C'est bien ! Vous avez déjà tout pour devenir millionnaire avec la Quiniela et InterSystems IRIS. Dans le prochain article, nous expliquerons comment ouvrir une session depuis Angular avec InterSystems IRIS via JWT.

À la prochaine fois !

2
0 184
Article Lorenzo Scalese · Oct 4, 2023 8m read

Description du cas

Imaginons que vous soyez un développeur en Python ou que vous disposiez d'une équipe bien formée et spécialisée en Python, mais que le délai qui vous est imparti pour analyser certaines données dans IRIS soit serré. Bien sûr, InterSystems offre de nombreux outils pour toutes sortes d'analyses et de traitements. Cependant, dans le scénario donné, il est préférable de faire le travail en utilisant le bon vieux Pandas et de laisser IRIS pour une autre fois.
    Dans la situation décrite ci-dessus et dans bien d'autres cas, il se peut que vous souhaitiez extraire des tables d'IRIS pour gérer des données en dehors des produits d'InterSystems. Cependant, vous pouvez également avoir besoin de faire les choses dans l'autre sens lorsque vous avez un tableau externe dans n'importe quel format, à savoir CSV, TXT ou Pickle, que vous avez besoin d'importer et d'utiliser les outils d'IRIS sur celui-ci.
Indépendamment du fait que vous ayez ou non à faire face à un problème décrit ci-dessus, Innovatium m'a appris qu'il est toujours utile de connaître plusieurs façons de résoudre un problème de codage. La bonne nouvelle, c'est qu'il n'est pas nécessaire de passer par le processus laborieux de création d'un nouveau tableau, de transfert de toutes les lignes et d'ajustement de chaque type lorsque l'on importe un tableau d'IRIS.
    Cet article vous montrera comment transformer rapidement un tableau IRIS en une trame de données Pandas et inversement avec seulement quelques lignes de code. Vous pouvez consulter le code à partir de mon GitHub, où vous trouverez Jupiter Notebook avec toutes les étapes de ce tutoriel.

Importation du tableau d'IRIS

Bien entendu, vous devez commencer par importer les bibliothèques nécessaires à ce projet.

import pandas as pd
import sqlalchemy as db

L'étape suivante consiste à créer la connexion entre le fichier Python et l'instance IRIS. Pour ce faire, nous utiliserons la fonction create_engine() de SQLAlchemy, avec une chaîne en tant que paramètre. Cette chaîne doit contenir des informations sur le dialecte de l'opération, le nom d'utilisateur et le mot de passe, l'hôte et le port de l'instance, ainsi que l'espace de noms de destination. Pour plus d'informations sur les concepts de base de l'utilisation de sqlalchemy-iris, consultez l'un de mes articles précédents, SQLAlchemy - la façon la plus simple d'utiliser Python et SQL avec les bases de données d'IRIS.

engine = db.create_engine("iris://_system:SYS@localhost:1972/SAMPLE")
connection = engine.connect()

Ensuite, nous pouvons déclarer une variable qui contiendra la trame de données et appeler la fonction read_sql_table() de Pandas sur cette connexion, en spécifiant le nom du tableau sous la forme d'une chaîne avec le schéma. Vous pouvez également indiquer le schéma dans un autre argument, ce qui est, en fait, préférable car le fait d'avoir un point sur la chaîne de nom peut provoquer des erreurs dans certains cas.

df = pd.read_sql_table("NameAge", connection, schema="PD")

C'est une bonne pratique de vérifier si le tableau avec lequel nous travaillons existe dans le schéma que nous voulons utiliser et, bien sûr, s'il y a un schéma dont nous avons besoin au départ. Dans la dernière section de cet article, vous apprendrez comment le faire ainsi que quelques autres conseils. À partir de maintenant, si vous avez l'habitude d'utiliser Pandas, vous pouvez effectuer toutes les modifications et analyses que vous souhaitez puisque vous savez quoi faire. Explorez l'exemple suivant pour voir comment cela fonctionne.

Envoi d'un tableau à IRIS

Avant de commencer, modifions un peu notre trame de données, à titre d'exemple. Nous pouvons adapter les valeurs d'une colonne à nos besoins (par exemple, ajouter des lignes et des colonnes, etc.). Après avoir joué un peu, j'ai mis les noms en minuscules et j'ai ajouté une nouvelle personne et une colonne sur la base des données existantes. Vous pouvez consulter l'illustration suivante pour voir le résultat.

Nous pouvons maintenant le renvoyer à IRIS par une seule ligne de code. Il suffit de spécifier le moteur et le nom du tableau.

df.to_sql("NameAge", con=engine, schema="PD", if_exists="replace")

Une fois de plus, nous devons placer le schéma dans un argument séparément du nom du tableau afin d'éviter certaines erreurs et un comportement indésirable. En outre, l'argument if_exists spécifie ce qu'il faut faire s'il existe déjà un tableau portant le même nom dans le schéma concerné. Les valeurs possibles sont : "replace" (remplacer), "fail" (échouer, la valeur par défaut) et "append" (ajouter). Bien entendu, l'option "replace" supprime le tableau et en crée un nouveau à l'aide d'une commande SQL, tandis que l'option "append" ajoute les données au tableau existant. N'oubliez pas que cette méthode ne vérifie pas les valeurs répétées ; soyez donc prudent lorsque vous utilisez cet attribut. Enfin, la valeur "fail" provoque l'erreur suivante :

Gardez à l'esprit que si vous spécifiez un nom de tableau qui n'existe pas, la fonction le créera.

Vous pouvez maintenant lancer une requête dans IRIS pour voir ce qu'il y a de nouveau ou aller dans le Portail de gestion dans la partie consacrée à SQL. N'oubliez pas que si vous avez utilisé la valeur "replace", vous devez consulter le code source de la classe, car la méthode la réécrit complètement. Cela signifie que si vous avez implémenté des méthodes, vous devez les laisser dans une superclasse.

Plus d'astuces sur sqlalchemy-iris

Si vous rencontrez quelques problèmes que vous n'avez pas pu résoudre avec les informations partagées dans d'autres communautés ou forums liés au code de votre application, vous trouverez peut-être ici l'aide dont vous avez besoin. Vous y découvrirez une liste d'astuces pour trouver des détails sur le moteur et le dialecte.

Caractéristiques spécifiques au dialecte

SQL Alchemy travaille avec des dialectes qui sont automatiquement choisis en fonction de votre moteur. Lorsque vous utilisez la fonction create_engine() pour vous connecter à une base de données IRIS, le dialecte choisi est sqlalchemy-iris by Dmitry Maslennikov.
Vous pouvez accéder à ses caractéristiques et les modifier à l'aide de la propriété de dialecte de votre moteur.

engine = db.create_engine("iris://_system:SYS@localhost:1972/SAMPLE")
engine.dialect

Avec l'extension IntelliCode de VSCode, vous pouvez rechercher toutes les options de cette propriété ou consulter le code source sur CaretDev's GitHub.

Vérification des schémas disponibles dans un moteur

Une fonction spéciale du dialecte digne d'être soulignée est la fonction get_schema_names(). Faites attention ! Les informations suivantes peuvent être cruciales pour vous si vous voulez éviter les erreurs dans votre code et pour l'itération.

connection = engine.connect()
engine.dialect.get_schema_names(connection)

 

Vérification des tableaux disponibles dans un schéma

Examinons une situation semblable. Il se peut que vous ayez besoin de connaître les tableaux disponibles à partir d'un schéma. Dans ce cas, vous pouvez utiliser l'inspection. Exécutez la fonction inspect() sur le moteur et enregistrez-la dans une variable. Cette même variable sera utilisée pour accéder à une autre fonction, get_table_names(). Elle renverra une liste des noms de tableaux dans le schéma spécifié ou dans la valeur par défaut "SQLUser".

inspection = db.inspect(engine)
inspection.get_table_names(schema="Sample")

De plus, si vous souhaitez utiliser plus de fonctionnalités de SQL Alchemy sur vos données, vous pouvez déclarer une base et faire en sorte que ses métadonnées reflètent un schéma du moteur.

b = db.orm.declarative_base()
b.metadata.reflect(engine, schema="Sample")

Si vous avez besoin de plus d'informations pour résoudre ce problème, consultez la Documentation SQL Alchemy et le dépôt sqlalchemy-iris GitHub Repository. Vous pouvez également m'envoyer un message ou laisser un commentaire, et nous essaierons de découvrir le secret ensemble.

Considérations finales

L'approche de mise en œuvre présentée dans cet article met l'accent sur l'utilisation des instances IRIS en tant que fournisseurs de services en nuage et permet d'effectuer une analyse sur différentes bases. Elle facilite la surveillance simultanée de toutes les instances dans toutes leurs qualités et la comparaison de leurs performances et de leur utilisation. Si vous combinez ces connaissances avec le développement décrit dans un autre article à propos d'un portail réalisé avec Django, vous pouvez rapidement construire un gestionnaire puissant pour autant de fonctionnalités et d'instances que vous le souhaitez.
    Cette implémentation est également un moyen efficace de transférer des données de l'extérieur d'IRIS vers une classe bien construite. Comme vous êtes peut-être familier avec d'autres fonctions trouvées dans Pandas pour traiter de nombreux langages différents, à savoir CSV, JSON, HTML, Excel et Pickle, il vous sera facile de changer read_sql\table en read_csv, read_json, ou toute autre option. Certes, je dois vous avertir que l'intégration avec InterSystems à partir de certains types de données n'est pas une fonctionnalité intégrée et qu'elle n'est donc pas toujours facile à mettre en œuvre. Cependant, l'union de SQL Alchemy et de Pandas sera toujours utile pour exporter des données depuis IRIS.
    Ainsi, dans cet article, nous avons appris qu'IRIS possède tous les outils dont vous avez besoin pour vous aider à développer et à intégrer facilement les dispositifs existants de votre système ou les dispositifs de votre domaine d'expertise.
 

0
0 146
Article Iryna Mykhailova · Sept 25, 2023 6m read

FHIR a transformé le secteur des soins de santé en fournissant un modèle de données normalisé pour la création d'applications de soins de santé et en favorisant l'échange de données entre les différents systèmes de soins de santé. La norme FHIR est basée sur des approches modernes axées sur les API, ce qui la rend plus accessible aux développeurs mobiles et web. Cependant, l'interaction avec les API FHIR peut encore s'avérer difficile, en particulier lorsqu'il s'agit de requêter des données à l'aide du langage naturel.

Nous présentons l'application Chaîne OpenAPI et IA - FHIR une solution qui permet aux utilisateurs d'interagir avec les API FHIR à l'aide de requêtes en langage naturel. Conçue avec OpenAI, LangChain et Streamlit, cette application simplifie le processus d'interrogation des API FHIR et le rend plus facile à utiliser.

 

Quelles sont les spécifications OpenAPI de FHIR ?

Les spécifications OpenAPI (anciennement connues sous le nom de "Swagger" et faisant actuellement partie de l'" Initiative OpenAPI " (https://www.openapis.org/)) sont devenues un outil essentiel dans le monde du développement logiciel, permettant aux développeurs de concevoir, de documenter et d'interagir avec les API de manière plus efficace. Les spécifications OpenAPI définissent un format normalisé, lisible par une machine, pour décrire les API RESTful, offrant ainsi un moyen clair et cohérent de comprendre leurs capacités et de les utiliser de manière efficace.

Dans le domaine des soins de santé, FHIR s'est imposé comme une norme de premier plan pour l'échange de données et l'interopérabilité. Pour améliorer les capacités d'interopérabilité de FHIR, HL7 a officiellement documenté les spécifications OpenAPI de FHIR, qui permettent aux développeurs d'intégrer de manière transparente les ressources et les opérations FHIR dans leurs solutions logicielles.

 

Avantages des spécifications OpenAPI de FHIR :

  1. Description normalisée de l'API : Les spécifications OpenAPI fournissent une description complète et normalisée des ressources, des opérations et des interactions FHIR. Les développeurs peuvent facilement comprendre la structure et les capacités des API basées sur FHIR, ce qui facilite la création d'intégrations et l'interaction avec les systèmes de santé.
  2. Promotion de l'interopérabilité : La collaboration entre les développeurs est encouragée, ce qui favorise l'adoption des normes et des meilleures pratiques FHIR. Les spécifications fournissent un langage et un cadre communs pour discuter des intégrations et des implémentations basées sur FHIR, ce qui favorise la collaboration entre les développeurs.
  3. Documentation et tests améliorés : Documentation interactive et séries de tests pour une meilleure compréhension et une meilleure validation. Les développeurs peuvent créer une documentation détaillée sur les API, ce qui permet aux autres développeurs de comprendre et d'utiliser plus facilement les API basées sur FHIR. Les séries de tests basées sur les spécifications permettent d'effectuer des tests complets et de valider les intégrations d'API, garantissant ainsi la fiabilité et la précision des échanges de données de santé.
  4. Expérience améliorée pour les développeurs : Génération automatique de bibliothèques client et de SDK pour une intégration transparente. Cela simplifie le processus d'intégration et réduit le temps et les efforts nécessaires pour incorporer la fonctionnalité FHIR dans leurs applications.

 

Comment les chaînes FHIR, OpenAI et OpenAPI fonctionnent-elles ensemble ?

L'application Chaîne OpenAPI et IA - FHIR s'appuie sur LangChain pour charger et analyser les spécifications OpenAPI (Chaîne OpenAPI). Ensuite, sur la base de ces spécifications, la chaîne d'invites fournies par OpenAI vise à comprendre les requêtes en langage naturel et à les convertir en demandes d'API FHIR appropriées. Les utilisateurs peuvent poser des questions en langage naturel et l'application interagira avec l'API FHIR choisie pour récupérer les informations pertinentes.

Par exemple, un utilisateur peut demander : "Quelle est la dernière mesure de la tension artérielle du patient John Doe (ID 111) ?" L'application traduira alors cette requête en une demande d'API FHIR, récupérera les données requises et les présentera à l'utilisateur dans un format facilement compréhensible.

 

Avantages de l'application Chaîne OpenAPI et IA - FHIR

  1. Interactions faciles à utiliser : L'application permet aux utilisateurs d'interagir avec les API FHIR à l'aide de requêtes en langage naturel, ce qui facilite l'accès et l'analyse des données de santé pour les utilisateurs non techniques.
  2. Amélioration de l'efficacité : L'application rationalise le processus d'interrogation des API FHIR, réduisant ainsi le temps et les efforts nécessaires pour obtenir des informations pertinentes. Elle permet également de réduire le nombre de clics (temps passé) pour trouver une information particulière à partir de l'application.
  3. Personnalisable : Les normes FHIR simplifient la récupération de données cohérentes à partir de n'importe quel serveur FHIR, ce qui permet une personnalisation aisée. Il peut être configuré sans effort pour s'intégrer de manière transparente à n'importe quelle API FHIR, offrant ainsi une solution flexible et adaptable aux diverses exigences en matière de données de santé.

 

Premiers pas avec l'application Chaîne OpenAPI et IA - FHIR

Pour commencer à utiliser l'application Chaîne OpenAPI et IA - FHIR, suivez les étapes suivantes :

  1. Obtenez une clé API d'OpenAI auprès de la Plate-forme OpenAI.
  2. Obtenez un point de terminaison API du serveur FHIR. Vous pouvez utiliser votre propre exemple de serveur FHIR (accès non authentifié nécessaire) ou créer un exemple de serveur temporaire en suivant les instructions données dans la Plate-forme d'apprentissage de FHIR pour InterSystems IRIS.
  3. Essayez l'application en ligne ou ou configurez-la localement en suivant les instructions fournies.

Grâce à l'intégration de capacités d'IA et de traitement du langage naturel, l'application haîne OpenAPI et IA - FHIR offre un moyen plus intuitif pour interagir avec les API FHIR, rendant les données de santé plus accessibles et plus faciles à analyser pour les utilisateurs de tous niveaux techniques.

Votez pour notre application dans le cadre du concours Grand Prix si vous la trouvez pertinente !

Si vous pensez à des applications qui pourraient utiliser cette implémentation, n'hésitez pas à les partager dans le fil de discussion.

0
0 73