#Ensemble

0 Abonnés · 86 Publications

InterSystems Ensemble est une plateforme d'intégration complète et facile à utiliser qui permet aux utilisateurs de connecter les personnes, les processus et les applications en un temps record.

En savoir plus

Documentation

Article Sylvain Guilbaud · Oct 29, 2025 14m read

Aperçu

Cette interface Web est conçue pour faciliter la gestion des tables de recherche de données (Data Lookup Tables) via une page Web conviviale. Elle est particulièrement utile lorsque les valeurs de votre table de recherche sont volumineuses, dynamiques et changeantes. Les utilisateurs finaux peuvent gérer efficacement les données de la table de recherche en fonction de leurs besoins grâce à un accès contrôlé à cette interface Web (autorisations de lecture, d'écriture et de suppression limitées à cette page).

Les données gérées via cette interface peuvent être utilisées de manière transparente pour les règles HealthConnect ou les transformations de données, ce qui élimine le besoin d'une surveillance et d'une gestion manuelles constantes des tables de recherche et permet ainsi un gain de temps considérable.

Remarque:
Si la table de recherche de données classique ne répond pas à vos besoins en matière de mappage, vous pouvez créer une table personnalisée et adapter cette interface Web ainsi que sa classe de support avec un minimum de modifications. Un exemple de code de classe est disponible sur demande.

Conditions préalables

Avant d'utiliser l'interface Web, veillez à avoir créé une table de recherche de données vide dans HealthConnect:

  1. Accédez à Interoperability → Configure → Data Lookup Tables.
  2. Cliquez sur New pour ouvrir la fenêtre contextuelle "Create New Lookup Table" (Créer une nouvelle table de recherche).
  3. Saisissez le nom souhaité pour votre table de recherche et cliquez sur OK.
  4. Cliquez sur Save pour finaliser la création de la table.
  5. Vérifiez la création de la table de recherche en cliquant sur Open dans la même fenêtre. Votre nouvelle table devrait apparaître dans la liste.

Dans cette documentation, la table de recherche de données utilisée à titre d'exemple est intitulée:
"Exemple de table de recherche de données"

Mode d'emploi

Le processus de configuration est simple:

  1. Obtention du code:Téléchargez le code fourni à partir du référentiel GitHub ou copiez-le à partir du lien communautaire.
  2. Création d'une page CSP:Créez une nouvelle page CSP dans votre environnement HealthConnect et insérez tout le code du fichier DataLookupWebApp.
  3. Création d'une classe:Copiez et insérez le code de classe fourni dans la documentation ou dans le référentiel.

Configuration

Avant la compilation et l'exécution:

  1. Indiquez le nom de votre table de recherche de données sur la page Web en remplaçant l'espace réservé indiqués par le cadre rouge dans la capture d'écran ci-dessous par le nom réel de votre table de recherche.

  1. Vérifiez si le nom de la classe dans le code correspond au nom de votre classe personnalisée.

  1. Attribuez un nom à votre table de recherche dans la classe, comme indiqué par myDtName = 'votre table de recherche'. Consultez la capture d'écran ci-dessus.
  1. Compilez la classe et la page CSP pour finaliser la configuration.

Mise à l'essai de l'application

Ajout d'enregistrements

  • Saisissez la clé et la paire clé-valeur correspondante dans les champs du formulaire.
  • Cliquez sur Add Record pour insérer les données dans la table de recherche.

Capture d'écran 1: Ajout d'enregistrements (122 – Radiographie de la colonne vertébrale)

Mise à jour de l'enregistrement

  • Sélectionnez un enregistrement existant et modifiez la paire clé-valeur si nécessaire.

  • Cliquez sur Update pour enregistrer les modifications. Exemple : Modification de  122 "Radiographie de la colonne vertébrale" en "Radiographie abdominale".

Suppression de l'enregistrement

  • Sélectionnez un enregistrement à supprimer (144 – IRM)

  • Cliquez sur le bouton Delete pour supprimer l'enregistrement de la table de recherche. Exemple : Suppression de "144 - IRM".

Vérification de la table de recherche de données dans HealthConnect

Accédez à Interoperability → Configure → Data Lookup Tables à Open

Recherche de l'enregistrement

Code / Ressources

  • La version complète du code source est également disponible pour téléchargement et consultation sur GitHub.

https://github.com/pandeySR/Reusable-Web-Interface-for-Data-Lookup-Table

<!DOCTYPE html>
<!--
This web application is designed and developed to insert, update, and delete records (key–value pairs) in the Data Lookup Table through a web interface.
Author: Sanjib Pandey
Date: 16/10/2025
-->
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="author" content="Sanjib Pandey" />
  <title>YOUR TITLE : Data Lookup Table - Data Record </title>
  <!-- Bootstrap CSS CDN, jQuery, Datatable -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> 
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"> 
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
  <link rel="stylesheet" href="https://cdn.datatables.net/1.13.5/css/dataTables.bootstrap5.min.css" />
  <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
  <script src="https://cdn.datatables.net/1.13.5/js/jquery.dataTables.min.js"></script>
  <script src="https://cdn.datatables.net/1.13.5/js/dataTables.bootstrap5.min.js"></script>
  <style>
    h2 {
      text-align: center;
      color: #fff;
      background-color: #00b300;
      padding: 15px 10px;
      border-radius: 5px;
      margin-bottom: 5px;
      margin-top: 0px;
    }
    html, body {
      height: 100%;
      margin: 0;
    }
    body {
      display: flex;
      min-height: 100vh;
      background-color: #f8f9fa;
      padding-top: 10px;
      flex-direction: column;
      align-items: center;
    }
    .container {
      max-width: 1100px;
      background: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0015px rgba(0,0,0,0.2);
      margin-top: 5px;
      width: 100%;
    }
 
    .table-scroll-vertical
    {
 	 max-height: 450px;
 	 overflow-y: auto;
  	 border: 1px solid #dee2e6;
  	 border-radius: 5px;
  	 margin-top: 0; 
	}
	
	.small-italic 
	{
  	 font-size: 0.85em; 
  	 font-style: italic; 
  	 color: #C0C0C0; 
	}
	
	.dataTables_filter label 
	{
  	 font-weight: bold;
  	 color: #333;
  	 color: red;
  	 float: left;
	}

	.dataTables_filter input
	{
  	 border: 2px solid #993399;
  	 border-radius: 5px;
  	 padding: 6px 10px;
  	 outline: none;
   	 width: 250px;
	}
	
	.page-footer
	{
  	 text-align: center;
  	 padding: 10px 5px;
  	 font-size: 0.95rem;
 	 color: #809fff;
 	 background-color: #f8f9fa;
  	 border-top: 1px solid #993399;
  	 margin-top: 5px;
	}
  </style>
  <style>
  @keyframes blink
  {
    50%
    {
      opacity: 0;
    }
  }
</style>
</head>
<body>
<div class="container">
<div style="overflow: hidden;">
  <div style="float: left; font-size: smaller; font-weight: bold;color:#b3ffff;animation: blink 1s infinite;">
    Environment : DEV
  </div>
  <h2 style="text-align: center; margin: 0;">
    Your Organization Name or Company Name<br>
    <span style="font-size: smaller; color: yellow;text-align: center;">Data Lookup Table</span>
  </h2>
</div> 
 <form id="recordForm"class="form-horizontal" action="" method="POST">
 	<div class="form-group">
        <!--for any other information if you want> -->
       </div>
      <div class="row mb-3">
        <label for="key"class="col-sm-3 col-form-label fw-bold">Key :</label>
        <div class="col-sm-9">
          <input type="text"class="form-control" id="key" name="key" placeholder="Enter the Key data !" required />
        </div>
      </div>
      <div class="row mb-3">
        <label for="kvalue"class="col-sm-3 col-form-label fw-bold">Key Pair Value</label>
        <div class="col-sm-9">
          <input type="text"class="form-control" id="kvalue" name="kvalue" placeholder="Enter the key paris value !" required />
        </div>
      </div>
	<div class="d-flex justify-content-between align-items-center mt-4 flex-wrap">
		<p class="mb-2 mb-md-0 text-primary">
    		<i>Click the edit icon to modify a record, then press "Update" to save. To delete, press the "Delete" button.</i> 
  		</p> 
  		
	<div class="d-flex flex-wrap justify-content-end">
		<button class="btn btn-success me-2" id="Add" type="submit" name="Add">
			<i class="fa fa-plus me-1" style="font-size:18px; color:white;"></i> Add Record
		</button>
	
		<button class="btn btn-primary me-2" type="submit" name="Update">
			<i class="fa fa-edit me-1" style="font-size:18px;"></i> Update
    	</button>

		<button class="btn btn-danger me-2" id="Delete" type="submit" name="Delete">
			<i class="fa fa-remove me-1" style="font-size:18px;"></i> Delete
		</button>
		
		<button class="btn btn-info" id="Cancel" type="submit" name="Cancel">
  			<i class="glyphicon glyphicon-refresh" style="font-size:18px;"></i> Cancel
		</button>
  	   </div> 
    </div>
    <div></div>
	</form>
<script language=SQL name="query">
  SELECT KeyName, DataValue FROM Ens_Util.LookupTable WHERE TableName='Data Lookup Table Example'
</script>

<script language=cache runat=server>
 S myKeyName=$Get(%request.Data("key",1))
 S myKeyValue=$Get(%request.Data("kvalue",1))
 S myDtName="Data Lookup Table Example"
 I ($Data(%request.Data("Add",1)))
 {
	I ((myKeyName '="") && (myKeyValue '="") && (myDtName '=""))
	{	
		I ##Class(SANJIB.DataLookup.Methods).ChkLookupKeyValue(myDtName,myKeyName)="F"
		{
			D##Class(SANJIB.DataLookup.Methods).InsertLookUpValues(myDtName,myKeyName,myKeyValue)
		}
		else
		{	W"The key has already been inserted.."&html<<divstyle=color:red>#(myKeyName)#</div>> }
		
	}
 }
 I ($Data(%request.Data("Update",1)))
 {
	I ((myKeyName '="") && (myKeyValue '="") && (myDtName '=""))
	{
		D##Class(SANJIB.DataLookup.Methods).UpdateLookUpValues(myDtName,myKeyName,myKeyValue)
	}
 }
 I ($Data(%request.Data("Delete",1)))
 {
	 I ((myKeyName '="") && (myKeyValue '="") && (myDtName '=""))
	 {
		D##Class(SANJIB.DataLookup.Methods).DeleteLookUpValues(myDtName,myKeyName)		
	 }
 }	
</script>
 <div class="table-responsive table-scroll-vertical"> 
    <table class="table table-bordered border-primary table table-hover mt-2" id="dataTable" style="min-width: 1000px;">
      <thead class="table-warning">
        <tr>
          <th>Key Data</th>
          <th>Key Pair Value</th>
          <th style="text-align:center;">Actions</th> 
        </tr>
      </thead>
      <tbody id="tableRecordset">
 		</tr>
 		<csp:while counter=myQueryRow condition=query.Next()>
 			<tr class='#($S(myQueryRow#2:"LightRow",1:"LightRow"))#'>
  				<csp:while counter=myQueryColumn condition="(myQueryColumn<query.GetColumnCount())">
      				<td style="background-color:#e6ffff">#(query.GetData(myQueryColumn))#</td>
  						</csp:while>
 							<td style="text-align:center;">
          						<button class="btn btn-sm btn-danger me-2 edit-delete-btn" data-id="#(query.GetData(0))#">
    								<i class="fa fa-edit"></i>
    								<i class="fa fa-trash"></i>
  								</button>
        					</td> 
 						</tr>
 				</csp:while>
      		</tbody>
       </table>
    </div>
  </div>
  
<script language=javascript>
  document.addEventListener('DOMContentLoaded', () => 
  {
    const editButtons = document.querySelectorAll('.edit-delete-btn');
    editButtons.forEach(button =>
    {
      button.addEventListener('click', () => 
      {
        const row = button.closest('tr');
        document.getElementById("Add").disabled=true
        const kID=row.cells[0].textContent.trim();
        const pairVal = row.cells[1].textContent.trim();
        document.getElementById('key').value = kID;
        document.getElementById('kvalue').value = pairVal;
        document.getElementById('key').focus();
      });
    });
  });
</script>
 <script language=javascript>
    document.getElementById('Cancel').addEventListener('click', () => 
    {
    	event.preventDefault();
    	document.getElementById('recordForm').reset();
    });
</script>

<script language=javascript>
  $(document).ready(function()
  {
    $('#dataTable').DataTable(
    {
      "order": [[0, "asc"]],
      "paging": true,
      "lengthChange": false,
      "searching": true,
      "info": true,
      "autoWidth": false
    });
  		$('#dataTable_filter input').css('font-size', '12px').attr('placeholder', 'Type to search..?');
  });
</script>

</body> 

<script language="javascript">
  document.addEventListener('DOMContentLoaded', () =>
  {
  	const updateBtn = document.querySelector('button[name="Update"]');
  	const deleteBtn = document.querySelector('button[name="Delete"]');
  	const addBtn = document.getElementById('Add');
  	const cancelBtn = document.getElementById('Cancel');
  	updateBtn.style.display = 'none';
  	deleteBtn.style.display = 'none';
  	addBtn.style.visibility = 'visible';  
  	addBtn.disabled = false;
  document.querySelectorAll('.edit-delete-btn').forEach(editBtn =>
  {
    editBtn.addEventListener('click', () =>
    {
      updateBtn.style.display = 'inline-block';
      deleteBtn.style.display = 'inline-block';
      addBtn.style.display = 'none';
      addBtn.style.visibility = 'visible'; 
      addBtn.disabled = true;
    });
  });
  updateBtn.addEventListener('click', (e) =>
  {
    updateBtn.style.display = 'none';
    deleteBtn.style.display = 'none';
    addBtn.style.display = 'inline-block';
    addBtn.style.visibility = 'visible';
    addBtn.disabled = false;
  });
  deleteBtn.addEventListener('click', (e) =>
  {
    updateBtn.style.display = 'none';
    deleteBtn.style.display = 'none';
    addBtn.style.display = 'inline-block';
    addBtn.style.visibility = 'visible';
    addBtn.disabled = false;
  });
  cancelBtn.addEventListener('click', (e) =>
  {
    e.preventDefault();  
    document.getElementById('recordForm').reset();
    updateBtn.style.display = 'none';
    deleteBtn.style.display = 'none';
    addBtn.style.display = 'inline-block';
    addBtn.style.visibility = 'visible';  
    addBtn.disabled = false;              
  });
});
</script>

<footer class="page-footer">
  <a href="https://sanjibpandey.wixsite.com/pandey/" target="_blank" rel="noopener noreferrer" style="color: #6c757d; text-decoration: none;"> https://sanjibpandey.wixsite.com/pandey/</a>
</footer>
</html>

 

/// Cette classe est conçue et créée pour insérer, mettre à jour et supprimer des enregistrements (clé & valeur)/// dans la table de recherche de données à partir d'une application Web. /// Ensuite, cela peut être utilisé dans des règles ou des transformations de données à l'aide de la fonction de recherche./// Auteur : Sanjib Pandey/// Date : 16/10/2025Class SANJIB.DataLookup.Methods Extends%Persistent
{

/// Avec cette méthode, on ajoute une valeur à la table de recherche. Les paramètres obligatoires sont:/// dtTableName : Le nom de votre table de recherche de données/// keyData     : La clé/// keyValue    : La valeur ( la valeur de paire de clés)	ClassMethod InsertLookUpValues(dtTable As%String = "", keyData As%String = "", keyValue As%String = "") As%Status
{
	S tSC = $$$OKTry
	{
		I (dtTable '="") && (keyData '="") && (keyValue '="")
		{
			S mySQLStatement = "INSERT into Ens_Util.LookupTable (KeyName,DataValue,TableName) values ('"_keyData_"','"_keyValue_"','"_dtTable_"')"S myRecordSet = ##class(%SQL.Statement).%ExecDirect(,mySQLStatement)
			S tSC={"InserRecorded":(myRecordSet)}
		}
	}
	Catch (Exception)
	{
		Throw Exception	
	}
	Q tSC
}

/// Cette méthode vérifie si la valeur existe déjà dans la table de recherche de données.ClassMethod ChkLookupKeyValue(dtTable As%String, keyData As%String) As%Status
{
	S tSC = $$$OKTry
	{
		I (dtTable '="") && (keyData '="")
		{
			S mySQLStatement="SELECT KeyName FROM Ens_Util.LookupTable WHERE TableName='"_dtTable_"' and KeyName='"_keyData_"'"S myRecordSet = ##class(%SQL.Statement).%ExecDirect(,mySQLStatement)
			D myRecordSet.%Next()
			I (myRecordSet.%SQLCODE=0)
			{ 
				S tSC= "T"
			}
			else
			{
				S tSC="F"
			}
		}
		else
		{
			S tSC= "Invalid Parameters - missing table name or key !"
		}
	}
	Catch (Exception)
	{
		Throw Exception	
	}
	Q tSC
}

/// Cette méthode met à jour uniquement la valeur clé dans la table de recherche de données.ClassMethod UpdateLookUpValues(dtTable As%String = "", keyData As%String = "", keyValue As%String = "") As%Status
{
	S tSC = $$$OKTry
	{
		I (dtTable '="") && (keyData '="") && (keyValue '="")
		{
			S mySQLStatement = "UPDATE Ens_Util.LookupTable SET DataValue='"_keyValue_"' WHERE TableName='"_dtTable_"' AND KeyName='"_keyData_"'"S myRecordSet = ##class(%SQL.Statement).%ExecDirect(,mySQLStatement)
			S tSC={"Updated Record":(myRecordSet)}
		}
	}
	Catch (Exception)
	{
		Throw Exception	
	}
	Q tSC
}

/// Cette méthode est utilisée pour supprimer un enregistrement de la table de recherche de données.ClassMethod DeleteLookUpValues(dtTable As%String, keyData As%String) As%Status
{
	S tSC = $$$OKTry
	{
		I (dtTable '="") && (keyData '="") 
		{
			S mySQLStatement = "DELETE FROM Ens_Util.LookupTable WHERE  TableName='"_dtTable_"' And KeyName='"_keyData_"'"S myRecordSet = ##class(%SQL.Statement).%ExecDirect(,mySQLStatement)
			S tSC={"Deleted Record":(myRecordSet)}
		}
	}
	Catch (Exception)
	{
		Throw Exception	
	}
	Q tSC
}

Storage Default
{
<Data name="MethodsDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
</Data>
<DataLocation>^SANJIB.DataLookup.MethodsD</DataLocation>
<DefaultData>MethodsDefaultData</DefaultData>
<IdLocation>^SANJIB.DataLookup.MethodsD</IdLocation>
<IndexLocation>^SANJIB.DataLookup.MethodsI</IndexLocation>
<StreamLocation>^SANJIB.DataLookup.MethodsS</StreamLocation>
<Type>%Storage.Persistent</Type>
}

}

Conclusion

Cette interface Web réutilisable et cette classe offrent un moyen simple mais efficace pour la gestion des tables de recherche de données dans HealthConnect, en améliorant l'efficacité et la flexibilité. Grâce à l'accès contrôlé dont bénéficient les utilisateurs finaux, cette interface réduit les frais administratifs traditionnellement associés à la maintenance des tables de recherche.

0
0 17
Article Sylvain Guilbaud · Sept 25, 2025 7m read

artisan cover

Si vous avez jamais observé un véritable artisan, qu'il s'agisse d'un potier transformant de l'argile en chef-d'œuvre ou d'un luthier donnant vie à un morceau de bois brut pour en faire une magnifique guitare, vous savez que la magie ne réside pas dans les matériaux, mais dans le soin, le savoir-faire et le traitement. Je le sais d'expérience : ma guitare électrique faite à la main est une source d'inspiration quotidienne, mais je dois avouer que créer quelque chose de ce genre est un don qui me manque.

Pourtant, dans le monde numérique, je vois souvent des gens qui espèrent que l'IA générative leur apporte une "solution miracle" en leur proposant des instructions vagues et hors contexte telles que "créez une application". Les résultats sont généralement décevants, sans aucune finesse ni créativité. Trop de gens attendent de l'IA qu'elle fasse des miracles sans contexte ni structure. Voilà ce qui nous a poussés à créer dc-artisan, un outil destiné aux artisans du prompt numérique. Notre objectif est de permettre à quiconque de transformer des prompts approximatifs et vagues en chefs-d'œuvre efficaces, fonctionnels et riches en contexte..

Tout comme lorsqu'on observe un grand artisan transformer des matières premières en œuvres d'art, créer avec GenAI est une question d'intention, de préparation et de travail minutieux. Le problème ne réside pas dans l'IA en soi, mais dans la manière dont nous l'utilisons. Tout comme un luthier doit sélectionner et façonner chaque morceau de bois avec soin, une ingénierie efficace des prompts nécessite un contexte, une structure et une intention bien définis.

Nous pensons que le monde mérite mieux que des "suggestions magiques" qui mènent à la déception. Une IA générative puissante est le fruit d'un accompagnement humain minutieux : un contexte précis, des objectifs concrets et une structure élaborée. Aucun artisan ne crée de la beauté par hasard : pour être fiables, les résultats d'une IA doivent être préparés avec soin.

dc-artisan aborde l'ingénierie rapide comme un véritable artisanat : de manière systématique, didactique et vérifiable. Il offre une boîte à outils complète pour aller au-delà des essais, des erreurs et des conjectures.

La première chose que fait dc-artisan est de chercher à comprendre votre prompt comme le ferait un collaborateur attentif. Lorsque vous commencez à rédiger, l'outil interagit directement avec vos entrées:

  • Questions de clarification: dc-artisan analyse votre demande initiale et vous pose des questions pertinentes afin de déterminer votre objectif principal, votre audience cible, le format souhaité et tout élément manquant. Par exemple:
    • “Quel type de résultat attendez-vous : un résumé textuel, un code ou des données structurées?”
    • “Quelle est l'audience cible?”
    • “Avec quel type de données ou d'informations ce prompt sera-t-il utilisé?”

prompt enhance

Ces interactions vous aident à clarifier non seulement ce que vous voulez que votre prompt dise, mais aussi pourquoi il le fait.

Une fois votre intention claire, dc-artisan examine la structure et propose des suggestions personnalisées afin d'améliorer la clarté, le ton et de compléter les détails manquants essentiels à un résultat riche en contexte et prêt à l'emploi.

Le meilleur dans tout ça? Vous pouvez utiliser toutes ces fonctionnalités directement dans votre éditeur préféré, VS Code ! Vous pouvez insérer des variables directement dans votre prompt (comme {task} ou {audience}) pour plus de flexibilité et de réutilisabilité, et prévisualiser instantanément le résultat final avec différentes substitutions. Vous voyez ainsi exactement comment cela fonctionnera dans la pratique.

Mais ce n'est pas tout. dc-artisan prend en charge le réglage rapide des prompts pour des performances optimales. Téléchargez un fichier CSV contenant des cas de test afin d'évaluer automatiquement la cohérence, la qualité des résultats et l'impact de la structure de vos prompts sur des entrées variées. dc-artisan évalue chaque réponse et génère des rapports complets avec des scores de qualité et des mesures de similarité, afin que vous puissiez mesurer et optimiser l'efficacité de vos prompts en toute confiance.

testing

Promouvoir sans contexte n'est pas un art, c'est du chaos

L'ingénierie des prompts sans structure revient à sculpter du bois les yeux bandés. Vous obtiendrez peut-être quelque chose, mais cela ne produira probablement pas un air mélodieux.

De nombreuses personnes ont recours à des prompts vagues ou surchargés, c'est-à-dire des commandes courtes et ambiguës ou des pages de contenu brut sans structure. Soit le modèle n'a aucune idée de ce que vous voulez, soit il se perd dans un marécage de bruit.

Lorsque le contexte du prompt devient trop long ou trop confus, même les LLM avancés peuvent se perdre. Au lieu de raisonner ou de générer de nouvelles stratégies, ils se laissent souvent déconcentrer, répétant le contenu précédent ou s'en tenant à des schémas familiers issus du début de l'historique des prompts. Ironiquement, les modèles plus volumineux avec des fenêtres contextuelles plus grandes (comme 32 000 tokens) sont encore plus sensibles à ce phénomène. Le simple fait de fournir plus de contexte (plus de documents, des prompts plus longs, des bases de connaissances entières) se retourne souvent contre vous, entraînant une surcharge contextuelle, des objectifs manqués et des résultats confus.

C'est précisément cette lacune que le RAG ( Génération augmentée par la récupération) vise à remplir : non pas en donnant plus d'informations aux LLM, mais en leur fournissant les connaissances les plus pertinentes au bon moment.

Comment dc-artisan et le mode pipeline RAG peuvent vous aider

dc-artisan unifie la création rapide de prompts et la gestion du contexte. Il vous aide non seulement à rédiger de meilleurs prompts, mais garantit également que votre IA reçoit des informations pertinentes et sélectionnées, et non un flot incessant d'informations futiles.

Avec le mode pipeline RAG vous pouvez:

  • 📄 Téléchargement et fragmentation des documents: PDF, DOCX, Markdown, TXT — à intégrer facilement dans votre base de données vectorielle.
  • 🧬 Inspection des fragments: à visualiser avec précision chaque unité atomique du texte intégré.
  • 🗑️ Nettoyage intelligent: à supprimer directement les contenus indésirables ou obsolètes depuis l'extension, afin que la base de connaissances de votre IA reste organisée et pertinente.

rag

Ce flux de travail est inspiré par le portail InterSystems Ideas Portal (see DPI-I-557)

Voici comment vous pouvez intégrer en toute simplicité une nouvelle section sur l'architecture backend de dc-artisan juste avant la section "Conclusion", en mettant en avant l'intégration avec l'interopérabilité InterSystems IRIS et notre adaptateur liteLLM personnalisé.

Ce qui distingue vraiment dc-artisan, c'est son backend robuste, conçu pour offrir à la fois interopérabilité et flexibilité. Le moteur de l'extension fonctionne sur L'interopérabilité InterSystems IRIS, en utilisant un adaptateur liteLLM personnalisé que nous avons développé.

Cette architecture signifie que vous n'êtes pas lié à un seul fournisseur de modèles linguistiques de grande taille (LLM). Au contraire, vous pouvez vous connecter et passer de manière transparente entre une large gamme de plateformes LLM de premier plan, notamment OpenAI, Gemini, Claude, Azure OpenAI, et bien d'autres, toutes gérées à partir d'un backend unifié de niveau entreprise.

Conclusion

De plus en plus de développeurs découvrent que la suggestion ne consiste pas à deviner les "mots magiques". Il s'agit plutôt de définir des objectifs réfléchis, d'utiliser un langage clair et de fournir un contexte pertinent, en rédigeant des prompts comme des ingénieurs, et non comme des magiciens. Tout comme les luthiers façonnent le bois pour créer des instruments dotés d'une âme, vous pouvez façonner des prompts pour créer des flux de travail IA à la fois fiables et riches en contexte à l'aide d'outils conçus spécialement pour votre métier.

dc-artisan est plus qu'un outil, c'est un changement de mentalité qui passe du codage intuitif à la clarté, la précision et au véritable art numérique.

🎸 Prêt à créer vos propres prompts?
⚙️ Lancez VS Code, installez dc-artisan et commencez à façonner votre IA comme un artisan, pas comme un magicien.

🗳️ Et si vous aimez ce que nous avons créé, votez pour nous dans le cadre du concours InterSystems IRIS Dev Tools Contest. Votre soutien compte beaucoup pour nous!

dc-artisan

0
0 21
Article Lorenzo Scalese · Sept 23, 2025 8m read

Mes clients me contactent régulièrement à propos du dimensionnement de la mémoire lorsqu'ils reçoivent des alertes indiquant que la mémoire libre est inférieure à un seuil ou lorsqu'ils constatent que la mémoire libre a soudainement diminué. Existe-t-il un problème? Leur application va-t-elle cesser de fonctionner parce qu'elle manque de mémoire pour exécuter les processus système et applicatifs? La réponse est presque toujours non, il est inutile de s'inquiéter. Mais cette réponse simple n'est généralement pas suffisante. Que se passe-t-il?

Considérez le graphique ci-dessous. Il montre le résultat de la métrique free dans vmstat. Il existe d'autres moyens d'afficher la mémoire libre d'un système, par exemple la commande free -m. Parfois, la mémoire libre disparaît progressivement au fil du temps. Le graphique ci-dessous est un exemple exagéré, mais il illustre bien ce qui se passe.

image

Comme vous pouvez le constater, vers 2 heures du matin, une partie de la mémoire est récupérée, puis chute soudainement à près de zéro. Ce système exécute l'application IntelliCare EHR sur la base de données InterSystems IRIS. Les informations vmstat proviennent d'un fichier HTML ^SystemPerformance qui collecte les métriques vmstat, iostat et plusieurs autres métriques système. Que se passe-t-il d'autre sur ce système ? Comme nous sommes en pleine nuit, je ne m'attends pas à ce qu'il se passe grand-chose à l'hôpital. Examinons iostat pour les volumes de la base de données.

image

On constate une augmentation soudaine des lectures au moment où la mémoire libre diminue. La baisse de la mémoire libre signalée correspond à un pic des lectures en gros blocs (taille de requête de 2048 Ko) indiqué dans iostat pour le disque de la base de données. Il s'agit très probablement d'un processus de sauvegarde ou d'une copie de fichiers. Bien sûr, corrélation n'est pas synonyme de causalité, mais cela vaut la peine d'être examiné et, en fin de compte, cela explique ce qui se passe.

Examinons d'autres résultats de ^SystemPerformance. La commande free -m est exécutée à la même fréquence que vmstat (par exemple, toutes les 5 secondes) et est accompagnée de la date et de l'heure, ce qui nous permet également de représenter graphiquement les compteurs dans free -m.

Les compteurs:

  • Memtotal – Total de RAM physique.
  • used – RAM activement utilisée (applications + système d'exploitation + cache).
  • free – RAM complètement inutilisée.
  • shared – Mémoire partagée entre les processus.
  • buf/cache – RAM utilisée pour les tampons et le cache, récupérable si nécessaire.
  • available – RAM disponible sans swap.
  • swaptotal – Espace de swap total sur le disque.
  • swapused – Espace de swap actuellement utilisé.
  • swapfree – Espace de swap inutilisé.

Pourquoi la mémoire libre diminue-t-elle à 2 heures du matin?

  • Les lectures séquentielles de grande taille remplissent le cache de page du système de fichiers, consommant temporairement de la mémoire qui apparaît comme "utilisée" dans free -m.
  • Linux utilise de manière agressive la mémoire inexploitée pour la mise en cache des E/S afin d'améliorer les performances.
  • Une fois la sauvegarde terminée (≈ 03h00), la mémoire est progressivement récupérée au fur et à mesure que les processus en ont besoin.
  • Vers 6 heures du matin, l'hôpital commence à s'activer et la mémoire est utilisée pour IRIS et d'autres processus.

Une mémoire libre insuffisante ne constitue pas une pénurie, mais plutôt une utilisation de la mémoire "libre" par le système à des fins de mise en cache. Il s'agit d'un comportement normal sous Linux! Le processus de sauvegarde lit de grandes quantités de données, que Linux met agressivement en cache dans la mémoire tampon/cache. Le noyau Linux convertit la mémoire "libre" en mémoire "cache" afin d'accélérer les opérations d'E/S.

Résumé

Le cache du système de fichiers est conçu pour être dynamique. Si la mémoire est requise par un processus, elle sera immédiatement récupérée. Il s'agit d'un élément normal de la gestion de la mémoire sous Linux.


Les Huge Pages ont-elles un impact?

Pour optimiser les performances et réserver de la mémoire pour la mémoire partagée IRIS, la meilleure pratique pour les déploiements IRIS en production sur des serveurs dotés d'une mémoire importante consiste à utiliser les Huge Pages de Linux. Pour IntelliCare, j'utilise généralement 8 Go de mémoire par noyau et environ 75 % de la mémoire pour la mémoire partagée d'IRIS (tampons Routine et Global, GMHEAP et autres structures de mémoire partagée). La répartition de la mémoire partagée dépend des exigences de l'application. Vos exigences peuvent être complètement différentes. Par exemple, en utilisant ce rapport CPU/mémoire, 25 % suffisent-ils pour les processus IRIS et les processus du système d'exploitation de votre application?

InterSystems IRIS utilise l'E/S directe pour les fichiers de base de données et les fichiers journaux, ce qui contourne le cache du système de fichiers. Ses segments de mémoire partagée (globales, routines, gmheap, etc.) sont alloués à partir de Huge Pages.

  • Ces pages immenses (huge pages) sont dédiées à la mémoire partagée IRIS et n'apparaissent pas comme "libres" ou "cache" dans free -m.
  • Once allocated, huge pages are not available for filesystem cache or user processes.

Cela explique pourquoi les métriques free -m semblent "insuffisantes" même si la base de données IRIS elle-même ne manque pas de mémoire.


Comment la mémoire libre pour un processus est-elle calculée?

À partir de ce qui précède, dans free -m, les lignes pertinentes sont les suivantes:

  • free – RAM totalement inutilisée.
  • available – RAM encore utilisable sans échange.

La disponibilité est un bon indicateur: elle inclut la mémoire cache et les tampons récupérables, indiquant ce qui est réellement disponible pour les nouveaux processus sans échange. Quels processus? Pour plus d'informations, consultez InterSystems Data Platforms and Performance Part 4 - Looking at Memory . Voici une liste simple: système d'exploitation, autres processus d'application non-IRIS et processus IRIS.

Examinons un graphique de la sortie free -m.

image

Bien que la valeur de la mémoire libre (free) chute à près de zéro pendant la sauvegarde, la valeur de la mémoire disponible (available) reste beaucoup plus élevée (plusieurs dizaines de Go). Cela signifie que le système pourrait fournir cette mémoire aux processus si nécessaire.

A quel endroit apparaissent les pages immenses dans la mémoire libre?

Par défaut, free -m n'affiche pas directement les pages immenses. Pour les voir, vous avez besoin des entrées /proc/meminfo telles que HugePages_Total, HugePages_Free et Hugepagesize.

Puisque le système d'exploitation réserve des pages immenses au démarrage, elles sont effectivement invisibles pour free -m. Elles sont verrouillées et isolées du pool de mémoire général.

Résumé

  • La "mémoire disponible" insuffisante constatée vers 02h00 est due au remplissage du cache de pages Linux par des lectures de sauvegarde. Il s'agit d'un comportement normal qui n'indique pas une pénurie de mémoire.
  • Les pages immenses réservées à IRIS ne sont pas affectées et continuent à servir efficacement la base de données.
  • La mémoire réellement disponible pour les applications est mieux mesurée par la colonne disponible, qui montre que le système dispose encore d'une marge suffisante.

Mais attendez, que se passe-t-il si je n'utilise pas les Huge Pages?

Généralement, on n'utilise pas les Huge Pages sur les systèmes non productifs ou à mémoire limitée. Les gains de performances des Huge Pages ne sont généralement pas significatifs en dessous de 64 Go, bien qu'il soit toujours recommandé d'utiliser les Huge Pages pour protéger la mémoire partagée IRIS.

A propos. J'ai vu des sites rencontrer des problèmes en allouant des pages immenses moins grandes que la mémoire partagée, ce qui oblige IRIS à essayer de démarrer avec des tampons globaux très petits ou à échouer au démarrage si memlock est utilisé (envisagez memlock=192 pour les systèmes de production).

Sans Huge Pages, les segments de mémoire partagée IRIS ( globales, routines, gmheap, etc.) sont alloués à partir de pages de mémoire normales du système d'exploitation. Cela apparaîtrait sous la mémoire "utilisée" dans free -m. Cela contribuerait également à réduire la mémoire "disponible", car cette mémoire ne peut pas être facilement récupérée.

  • utilisée – Beaucoup plus élevée, reflétant la mémoire partagée IRIS + le noyau + d'autres processus.
  • libre – Probablement moins suffisante, car plus de RAM est allouée en permanence à IRIS dans le pool régulier.
  • buf/cache – Augmenterait toujours pendant les sauvegardes, mais la marge apparente pour les processus semblerait plus restreinte, car la mémoire IRIS se trouve dans le même pool.
  • disponible – Plus proche de la véritable “mémoire libre + cache récupérable” moins la mémoire IRIS. Cela semblerait plus petit que dans votre configuration Huge Pages.

Alors, faut-il utiliser Huge Pages dans des systèmes de production?

OUI!

Pour la protection de la mémoire. La mémoire partagée IRIS est protégée contre:

  • Remplacement en cas de sollicitation de la mémoire.
  • Concurrence avec les opérations du système de fichiers telles que les sauvegardes et les copies de fichiers, comme nous l'avons vu dans cet exemple.

Autres remarques - trop profondément dans les détails...

Comment les données sont-elles collectées?

La commande utilisée dans ^SystemPerformance pour une collecte de 24 heures (17 280 secondes) avec des coches toutes les 5 secondes est la suivante:

free -m -s 5 -c 17280 | awk '{now=strftime(""%m/%d/%y %T""); print now "" "" $0; fflush()}' > ","/filepath/logs/20250315_000100_24hours_5sec_12.log

0
0 22
Article Sylvain Guilbaud · Août 29, 2025 1m read

Rubrique FAQ InterSystems

Par défaut, l'ordre des colonnes d'une table est déterminé automatiquement par le système. Pour modifier cet ordre, définissez explicitement l'ordre de chaque propriété à l'aide du mot-clé SqlColumnNumber lors de la définition de la classe.

Exemple :

Property Name As %String [SqlColumnNumber = 2];

Veuillez consulter la documentation ci-dessous.

SqlColumnNumber

Si vous souhaitez modifier le nom de la table SQL, spécifiez SqlTableName. Si vous souhaitez modifier le nom de la colonne (nom du champ), spécifiez SqlFieldName.

0
0 16
Article Lorenzo Scalese · Août 11, 2025 4m read

Mon intention est de montrer à quel point il est simple de générer un tableau de recherche en tenant compte des informations qui arrivent dans notre messagerie HL7. Certes, le tableau de recherche de messages HL7 fourni par IRIS est suffisant pour la plupart des recherches que nous souhaitons effectuer, mais nous avons toujours ce champ spécial de notre HIS, LIS, RIS, etc. dans lequel nous aimerions rechercher. Mais il se trouve dans un segment en dehors de cette table. Ce champ nous oblige à générer une recherche spécifique en utilisant les critères de recherche avancés. Nous aurons certainement beaucoup de messages et nous devrons également filtrer par date et heure pour éviter un délai d'expiration.
 

Comment résoudre ce problème?

En créant notre propre table de recherche.

Et comment créer notre table de recherche?

Comme nous l'avons toujours fait, EN COPIANT! Dans notre vie, nous rencontrerons 3 ou 4 génies, ce seront ceux qui inventeront, créeront, visualiseront l'au-delà, etc. Si vous êtes l'un d'entre eux, vous savez déjà comment faire. Vous serez dans le top 100 du classement mondial, vous aurez plus de 500 000 points et tout un arsenal de produits InterSystems chez vous. Les autres feront comme nous avons fait toutes ces années avant le CHAT GPT, copier sans aucune honte, la tête bien haute. Alors, commençons.

Première étape

Nous allons générer notre classe dans Visual Studio Code, ouvrir la classe EnsLib.HL7.SearchTableque fournie par IRIS , et copier tout le contenu de la classe CTRL+C. Nous allons ensuite dans notre classe et CTRL+V.
 

Très important: nous copierons également les Extends, les ClassType, Inheritance. Nous ne laissons rien de côté, à l'exception du Copyright, qui ne nous intéresse pas.  Nous n'avons pas assez d'ego pour laisser notre empreinte sur un travail remarquable.

Si vous êtes d'ancienne génération, cet écran vous semblera très familier. 😉

Deuxième étape

Maintenant nous faisons opérer la magie: nous ajoutons nos champs, supprimons ceux qui ne nous intéressent pas, et pouvons même les traduire en espagnol pour paraître plus compétents.
 

Dans ce cas, j'ai ajouté la source, la destination, l'événement, le service et le dossier patientau message, et c'est là que vous intervenez. Ajoutez tous les champs que vous souhaitez/devez ajouter. Comme vous le voyez, vous pouvez ajouter le segment, le champ et le composant sous forme numérique. Pour moi, c'est plus facile que d'ajouter le nom en anglais, mais gardez à l'esprit que nous ne pouvons garantir que le segment 1 sera le MSH ; le reste dépendra de chaque message. Donc, dans le cas des segments, il est préférable d'utiliser le code (PID, PV1).

Après tout ce travail fastidieux, nous compilons et avons maintenant notre table de recherche. Il ne nous reste plus qu'à l'attribuer aux composants de notre production, évidemment les composants HL7. Passons à la suite.

Troisième étape

Nous ouvrons notre production et recherchons les composants HL7, nous allons dans les paramètres supplémentaires et nous trouvons notre table de recherche, nous la sélectionnons et procédons à l'application des modifications. À partir de ce moment, tous les messages qui entrent par ce composant seront stockés dans notre table de recherche. Si nous ajoutons ultérieurement d'autres champs à la table de recherche, ils seront enregistrés à partir de la compilation de celle-ci, et pour les messages précédents, ce champ sera vide.

Qu'ils soient entrants ou sortants, dans les opérations de type HL7, nous avons également la table de recherche. Normalement, dans les composants de sortie, rien n'est activé par défaut, mais si nous souhaitons contrôler la sortie, cette option est également disponible.

Grâce à ces étapes simples, notre production est prête à enregistrer les données qui nous intéressent. Il ne nous reste plus qu'à générer les requêtes, et pour cela, nous allons dans la visionneuse de messages.

Démonstration

Dans la messagerie, dans les critères, lorsque nous sélectionnons les tables de recherche, nous retrouvons ce que nous avons fait. Lorsque nous le sélectionnons, nous pouvons maintenant commencer à jouer avec nos champs

Je vais vous donner plusieurs exemples, mais ne limitez pas votre imagination. Je me suis laissé emporter. Les champs du tableau de recherche vous indiqueront les limites.


1. Recherche sans condition. Nous voulons uniquement voir l'événement du message entrant et l'identifiant du message.

2. Recherche par événement affichant les codes du patient et de l'épisode


3. Recherche par épisode montrant le service, le nom du patient et le type de message HL7


À partir de là, c'est à vous de jouer, profitez-en bien 😋

0
0 30
Article Lorenzo Scalese · Mai 28, 2025 6m read

Cet article présente une analyse du cycle de solution pour l'application Open Exchange TOOT ( application Open Exchange)

L'hypothèse

Un bouton sur une page Web permet de capturer la voix de l'utilisateur. L'intégration IRIS permet de manipuler les enregistrements afin d' extraire la signification sémantique que la recherche vectorielle d'IRIS peut ensuite proposer pour de nouveaux types de solutions d'IA.

La signification sémantique amusante choisie concernait la recherche vectorielle musicale, afin d'acquérir de nouvelles compétences et connaissances en cours de route.

À la recherche de motifs simples

La voix humaine qui parle, siffle ou fredonne a des contraintes qui se sont exprimées à travers de nombreux encodages de données historiques à faible bande passante et de supports d'enregistrement.

Quelle quantité minimale d'informations est nécessaire pour distinguer un son musical d'un autre en relation avec une entrée vocale musicale?

Considérez la séquence des lettres de l'alphabet musical:

   A, B, C, E, A

Like in programming with ASCII values of the characters:
* B est supérieur d'une unité à A
* C est supérieur d'une unité à B
* E est supérieur de deux unités à C
* A est inférieur de quatre unités à E
Représenté sous forme de progression numérique entre deux nombres:

 +1, +1, +2, -4

On a besoin d'une information de moins que le nombre initial de notes.
Si l'on teste logiquement après le premier café du matin, le fredonnement devient:

  B, C, D, F, B

Notez que la séquence numérique correspond toujours à cette hauteur élevée.
Cela démontre qu'une progression numérique de la différence de hauteur semble plus flexible pour correspondre à l'entrée utilisateur que des notes réelles.

Durée des notes

Le sifflement a une résolution inférieure à celle représentée par les manuscrits musicaux traditionnels.
Une décision a été prise de ne résoudre que DEUX types de durée de note musicale:

  • Une note longue qui dure 0,7 seconde ou plus
  • Une note courte qui dure moins de 0,7 seconde.

Vides entre les notes

Les vides ont une résolution assez faible, nous n'utilisons donc qu'un seul point d'information.
Il a été décidé de définir un vide entre deux notes comme suit:

une pause de plus d'une demi-seconde entre deux notes distinctes.

Plage de changement des notes

Une décision a été prise afin de limiter la transition maximale enregistrable entre deux notes de 45 hauteurs différentes.
Tout changement de note saisi par l'utilisateur qui dépasse cette limite est tronqué à +45 ou -45, selon que la hauteur augmente ou diminue. Contrairement aux notes réelles, cela affecte en rien l'utilité d'une séquence de recherche de mélodie continue.

   +1 0 +2 -4 +2 +1 -3

Possibilité d'entraînement pour obtenir une correspondance sémantique proche de la séquence de changements indiquée en rouge.

+1 1 +2 -4 +2 +1 -3

Saisie monocanal

Une voix ou un sifflement est un instrument simple qui ne produit qu'une seule note à la fois.
Cependant, cela doit correspondre à une musique composée généralement de:
* Plusieurs instruments qui jouent simultanément
* Des instruments qui jouent des accords (plusieurs notes à la fois)
En général, un sifflement tend à suivre UNE voix ou un instrument spécifique pour représenter une musique de référence.
Lors d'enregistrements physiques, les voix et les instruments individuels peuvent être pistes distinctes qui sont ensuite "mixés" ensemble.
De même, les utilitaires d'encodage/décodage et les formats de données peuvent également préserver et utiliser des "pistes" par voix/instrument.

Il en résulte que les entrées fredonnées/sifflées doivent être recherchées en fonction de l'impression laissée par chaque piste vocale et instrumentale.

Plusieurs modèles d'encodage "musicaux" / formats linguistiques ont été envisagés.
L'option la plus simple et la plus aboutie consistait à utiliser le traitement au format MIDI pour déterminer les encodages de référence pour la correspondance et la recherche de sifflements.

Récapitulatif du vocabulaire

Outre les séquences habituelles de symboles de début, de fin et de remplissage, les points d'information sont les suivants

  • 45 notes longues dont la durée diminue selon une amplitude spécifique
  • 45 notes courtes dont la durée diminue selon une amplitude spécifique
  • Répétition de la même note d'une durée courte
  • Répétition de la même note d'une durée longue
  • 45 notes longues dont la durée augmente selon une amplitude spécifique
  • 45 notes courtes dont la durée augmente selon une amplitude spécifique
  • Un vide entre les notes

Données synthétiques

Les globales IRIS sont très rapides et efficaces pour identifier les combinaisons et leur fréquence dans un grand ensemble de données.

Le point de départ des données synthétiques était des séquences valides.

Celles-ci ont été modifiées de différentes manières et classées en fonction de leur écart:

  • SplitLongNote - Une note longue est divisée en deux notes courtes, dont la seconde est une répétition
  • JoinLongNote - Deux notes courtes, dont la seconde est une répétition, sont fusionnées en une seule note longue.
  • VaryOneNote ( +2, +1, -1 or -2 )
  • DropSpace - Suppression de l'espace entre les notes
  • AddSpace - Ajout d'un espace entre les notes

Ensuite, ces scores sont superposés de manière efficace dans une globale pour chaque résultat.

Cela signifie que lorsqu'une autre zone de séquence de changement de note dans un flux de piste est plus proche d'une valeur mutée, le score le plus élevé est toujours sélectionné.

Flux de travail Dev

Flux de travail de recherche

Flux de travail DataLoad

Des intégrations vectorielles ont été générées pour plusieurs pistes d'instruments (22 935 enregistrements) et pour des échantillons mélodiques (6 762 enregistrements)

Flux de travail d'entraînement

Deux essais d'entraînement:

Sans supervision - 110 000 enregistrements maximum (7 heures de traitement)

Score de similarité sous supervision - 960 000 enregistrements maximum (1,3 jour de traitement)

Autres exigences à explorer

Meilleure mesure de la similarité

La version actuelle de l'implémentation trie les résultats en fonction des scores de manière trop stricte.

Il convient de réexaminer le seuil d'inclusion des séquences à faible et à forte occurrence dans l'ensemble de données.

Filtrage du bruit de fond

Au format MIDI, le volume des voix ou des instruments est important en termes d'utilisation réelle et de bruit de fond. Cela pourrait permettre de nettoyer/filtrer une source de données. On pourrait peut-être exclure les pistes qui ne seraient jamais référencées par une entrée humaine. Actuellement, la solution exclut les « percussions » par piste instrumentale, par titre et par analyse de certaines répétitions de progression.

Instruments MIDI synthétiques

L'approche actuelle pour faire correspondre la voix aux instruments consistait à essayer de contourner les incompatibilités entre les caractéristiques des instruments, afin de voir si cela donnait un résultat satisfaisant.

Une expérience intéressante serait d'ajouter certaines caractéristiques à partir des données fournies par l'utilisateur, tout en modifiant les données d'apprentissage synthétiques afin d'obtenir des caractéristiques plus humaines.

Le MIDI encode des informations supplémentaires avec des variations de hauteur afin d'obtenir une progression plus fluide entre les notes.

Ce serait une piste à explorer pour étendre et affiner la manière dont la conversion WAV vers MIDI est effectuée.

Conclusion

J'espère que vous avez trouvé cet article intéressant et que vous apprécierez l'application. Peut-être vous inspirera-t-elle de nouvelles idées.

0
0 30
Article Corentin Blondeau · Avr 28, 2025 5m read

Bonjour à tous,
Cet article fait suite à la question que j'avais posée à la communauté L'adaptateur UDP ne fonctionne pas
Dans cet article, je vais vous présenter les points suivants
1) Qu'est-ce que "UDP"?
2) L'état actuel d'Iris avec UDP
3) Ma solution avec l'adaptateur UDP


1) Qu'est-ce que "UDP"?

L'acronyme UDP signifie User Datagram Protocol (protocole de datagramme utilisateur). Il s'agit de l'un des principaux protocoles composant la suite IP (Internet Protocol), utilisé pour la transmission de données sur un réseau. Voici quelques fonctionnalités clés de l'UDP:

  1. Sans connexion : L'UDP n'établit pas de connexion avant d'envoyer des données, ce qui signifie qu'il peut envoyer des messages (datagrammes) sans échange préalable.
  2. Peu fiable : Il n'y a aucune garantie que les messages envoyés via l'UDP arriveront à destination. Il n'y a pas de récupération des erreurs ni de retransmission des paquets perdus.
  3. Vitesse : Étant donné que l'UDP est sans connexion et qu'il ne nécessite pas de vérification ou de récuperation des erreurs, il est généralement plus rapide que le TCP (Transmission Control Protocol), ce qui le rend approprié pour les applications où la vitesse est cruciale.
  4. Constrruit autour des datagrammes : L'UDP envoie des messages sous forme de paquets discrets, qui peuvent être de longueur variable. Chaque paquet est traité indépendamment.
  5. Cas d'utilisation : L'UDP est couramment utilisé dans les applications où la vitesse est plus importante que la fiabilité, telles que la diffusion vidéo en continu, les jeux en ligne, la voix sur IP (VoIP) et les communications en temps réel.

En général, l'UDP est un protocole léger qui est utile pour des applications spécifiques où une faible latence est essentielle.


2) L'état actuel d'Iris avec UDP

Bien entendu, InterSystems IRIS permet d'utiliser ce protocole pour envoyer et recevoir des données.
En tant que protocole REST, il y a deux façons de le faire :
- avec ##class(%Net.UDP).%New().
- avec EnsLib.UDP.OutboundAdapter et EnsLib.UDP.InboundAdapter

##class(%Net.UDP).%New()

Même si la documentation de la classe et très détaillée, voici le lien de la documentation d'InterSystems sur la façon de l'utiliser.
Pour envoyer/recevoir des données, il faut utiliser une instance de class(%Net.UDP).%New() et une méthode associée.
En résumé, pour envoyer des données (sur localhost avec le port 3001) :

SET client = ##class(%Net.UDP).%New()
SET addrbin = ##class(%Net.UDP).GetHostAddr("127.0.0.1")
Set status = client.Send("message text", addrbin, 3001)

Pour recevoir des données (sur localhost avec le port 3001) :

Set sobj = ##class(%Net.UDP).%New(3001,"127.0.0.1")
Set data = sobj.Recv()

 

EnsLib.UDP.OutboundAdapter and EnsLib.UDP.InboundAdapter

Ce dernier est plus simple : c'est un adaptateur.
La documentation : EnsLib.UDP.OutboundAdapter et EnsLib.UDP.InboundAdapter
Pour envoyer des données :

Set status = ..Adapter.SendStream(stream)

Pour obtenir des données :

Set status = ..Adapter.Receive(stream)


Cependant, cela ne fonctionne pas. J'ai posé ma question à la communauté "L'adaptateur UDP ne fonctionne pas" et j'ai créé un ticket pour le WRC.
La réponse a été formulée comme suit :

Cet exécutable sous-jacent n'est plus installé dans le produit depuis Ensemble 2018.1.

J'ai vérifié au niveau interne et le JIRA DP-437486 a été soumis pour mettre à jour ces adaptateurs afin d'utiliser la classe %Net.UDP, mais cela sera soumis à l'approbation de la gestion des produits et aux ressources de développement disponibles.

Malheureusement, la seule option possible actuellement est de créer votre propre adaptateur personnalisé en utilisant la classe %Net.UDP.

Voici les deux principales différences entre la classe (%Net.UDP) et l'adaptateur EnsLib.UDP.OutboundAdapter 

  • La classe %Net.UDP utilise la classe système $System.UDP, elle utilise donc le code du noyau Cache/IRIS pour envoyer/recevoir les messages UDP, alors que l'adaptateur UDP utilise un tuyau de commande pour appeler des exécutables externes afin d'envoyer/recevoir le message UDP.
  • La classe %Net.UDP envoie/lit une chaîne de caractères alors que l'adaptateur UDP utilise un flux pour envoyer/lire les messages.

3) Ma solution avec l'adaptateur UDP

J'ai donc écrit ma propre méthode (approuvée par le service d'assistance) pour envoyer des données :
 

/// Adaptateur pour l'envoi de données avec une connexion UDPClass USER.UDP.OutboundAdapter Extends Ens.Adapter
{

/// Hôte du serveur UDPProperty Host As%String [ Required ];/// Port du serveur UDPProperty Port As%Integer [ Required ];/// si 1, le texte qui sera envoyé est affichéProperty UDPTrace As%Integer(VALUELIST = ",0,1") [ InitialExpression = 0, Required ];Parameter SETTINGS = "Host:Basic,Port:Basic,UDPTrace:Basic";/// Envoi de "texte" par le biais de la connexion UDP Method SendDataText(text As%String) As%Status { Try { Set status = $$$OKIf..UDPTrace=1 { Do..ShowText(text) }

    <span class="hljs-keyword">Set</span> udpClient = <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%Net.UDP</span>).<span class="hljs-built_in">%New</span>()
    <span class="hljs-keyword">Set</span> addrbin = <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%Net.UDP</span>).GetHostAddr(<span class="hljs-built_in">..Host</span>)

    <span class="hljs-keyword">Set</span> sentBytes = udpClient.Send(text, addrbin, <span class="hljs-built_in">..Port</span>)
}
<span class="hljs-keyword">Catch</span> exception {
    <span class="hljs-keyword">Set</span> status = exception.AsStatus()
}    
<span class="hljs-keyword">Return</span> status

}

/// Conversion du "stream" en texte et son envoi via la connexion UDP Method SendDataStream(stream As%Stream.Object) As%Status { Try { Do stream.Rewind() Set text = ""While 'stream.AtEnd{ Set text = text _ stream.Read() }

    <span class="hljs-keyword">Set</span> status = <span class="hljs-built_in">..SendDataText</span>(text)
}
<span class="hljs-keyword">Catch</span> exception {
    <span class="hljs-keyword">Set</span> status = exception.AsStatus()
}    
<span class="hljs-keyword">Return</span> status

}

/// Conversion de l'"objet" en json et son envoi via la connexion UDP Method SendDataJSONObject(object As%RegisteredObject, format As%String = "iw") As%Status { Try { Set status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(.stream,object,,,,format) $$$ThrowOnError(status)

    <span class="hljs-keyword">Set</span> status = <span class="hljs-built_in">..SendDataStream</span>(stream)
}
<span class="hljs-keyword">Catch</span> exception {
    <span class="hljs-keyword">Set</span> status = exception.AsStatus()
}    
<span class="hljs-keyword">Return</span> status

}

/// Un texte est pris en entrée,/// Les traces de l'objet associé sont affichées Method ShowText(text As%String) { Set nbParty = $SYSTEM.SQL.CEILING($LENGTH(text)/1100) For ii=1:1:nbParty { $$$TRACE($EXTRACT(text,ii,ii+1100)) } }

}

J'espère que cet article a été, sinon utile, du moins intéressant.


Je n'ai pas testé EnsLib.UDP.InboundAdapter, donc n'hésitez pas à ajouter plus d'informations à la discussion.
Corentin

2
0 39
Article Sylvain Guilbaud · Avr 22, 2025 3m read

Rubrique FAQ InterSystems

Les variables globales temporaires stockées dans les bases de données IRISTEMP/CACHETEMP sont utilisées lorsqu'un processus n'a pas besoin de stocker des données indéfiniment, mais requiert les performances élevées des variables globales. Les bases de données IRISTEMP/CACHETEMP ne sont pas journalisées ; leur utilisation ne crée donc pas de fichiers journaux.

Le système utilise les bases de données IRISTEMP/CACHETEMP pour le stockage temporaire et les utilisateurs peuvent y accéder à cette fin.

0
0 30
InterSystems officiel Adeline Icard · Mars 6, 2025

À partir de la version 2025.1 de la plateforme de données InterSystems IRIS®, InterSystems abandonne officiellement MultiValue et l'inclut dans la liste des fonctionnalités obsolètes et abandonnées. Bien qu'InterSystems continue de prendre en charge les clients existants qui utilisent MultiValue, cette fonctionnalité n'est pas recommandée pour les nouvelles applications.

Ce que cela signifie pour vous :

0
0 31
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 Guillaume Rongier · Jan 24, 2025 6m read

Dans le cadre du concours Open Exchange, l'hôpital Salford Royal (Dean White et Mark O'Reilly) a développé une API REST pour SharePoint, un modèle qui fonctionne mais qui peut aussi servir de point de départ à vos propres applications REST 

Conditions préalables

Lorsque vous utilisez la v1 du service REST de l'API de Sharepoint, vous avez besoin d'un identifiant locataire, d'un identifiant client, d'un code secret client et d'un nom de locataire 

Configuration 

Configuration d'un serveur OAuth

 

Le code au milieu est l'identifiant locataire 

Créez un nom de config client comme vous le souhaitez 

Configurer votre client oauth en remplaçant l'adresse IP de votre serveur par l'adresse IP du serveur sur lequel vous vous trouvez (pas l'adresse VIP - si vous ne faites pas partie d'un VIP, l'adresse locale peut fonctionner) 

Ajouter les informations d'identification client 

modifiez les paramètres sur SharepointRESTConnector comme HTTPSERVER,SHAREPOINT-SITENAME- SHAREPOINT FILEPATH- SSL (vierge jusqu'à la v. 1.3) les paramètres remplacent le nom locataire et l'identifiant locataire. 

Code 

SharePointOnlineRESTOperation

OAuth Scope n'est pas utilisateur dans cet exemple  mais est laissé ici comme modèle si vous en avez besoin pour d'autres implémentations rest 

Il utilise et s'appuie sur rest par défaut   Set tSC=..AddAccessToken(.tHttpRequest) qui gère le jeton et transmet toutes les propriétés supplémentaires requises pour l'API. Pour l'API SharePoint, une ressource est nécessaire et cette dernière est ajoutée dans les paramètres dans les notes de commentaires 

/// Pour SPO, les paramètres doivent être {"resource":"00000003-0000-0ff1-ce00-000000000000/{TennantName}.sharepoint.com@{TennantID}"} <p>/// 00000003-0000-0ff1-ce00-000000000000 est l'identifiant ResourceID attribué à SPO par Microsoft et ne doit pas être modifié <p>/// {TennantName} doit être modifié pour être identique à celui du serveur HTTP, par exemple intersystems.sharepoint.com <p>/// {TennantID} est l'identifiant de votre nom de serveur 

Obtention d'une liste de fichiers 

Appelle la liste des fichiers dans le répertoire dont vous disposez. Cette fonction peut indiquer le temps écoulé depuis le dernier téléchargement ou la durée totale des fichiers Elle interroge l'en-tête

Elle appelle GetFolderByServerRealativeURL

Set..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files"_filter Set..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files"_filter

 La réponse est lue par le processeur. 

Il envoie des messages http comme le ferait POSTMAN 

Une méthode de réponse Constuct a été tirée de l'opération générique écrite par intersystems pour renvoyer des réponses http 

Suppression du fichier

Appelle une demande d'envoi de suppression à getfolderbyserverrelativeurl/files getfolderbyserverrelativeurl/files 

lignes clés ci-dessous 

Set..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files('"_$$$URLENCODE(pRequest.FileName)_"')"Set tSC=..AddAccessToken(.tHttpRequest)
  	s tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)
    Quit..constructResponse(.tHttpResponse,.pResponse)

Téléchargement du fichier

Si c'est un Ens.StringContainer (vous pourriez en faire un message sur mesure qui l'étendrait, comme Messages.DownloadSharpointFile), il lit le nom et l'envoie dans l'url de l'api. Il lit le paquet de réponses et ajoute le flux binaire à un steamcontainer. Comme toujours, il faut créer le flux et l'empaqueter dans le streamcontainer. 

Code clé ci-dessous (quelques s ont été modifiés pour être affichés ici) 

set binaryStream =##Class(%Stream.FileBinary).%New()
  Set tSC=..AddAccessToken(.tHttpRequest)
  Set..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files('"_$$$URLENCODE(pRequest.StringValue)_"')/OpenBinaryStream()"Set tHttpResponse = ##class(%Net.HttpResponse).%New()
  set send="GET"set tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)
  set pDownloadResponse =##Class(Ens.StreamContainer).%New(binaryStream)
  set pDownloadResponse.OriginalFilename=pRequest.StringValue
	

Ajout du fichier

GetFolderByServerRelativeUrl/filepath/Files/add(url=filename,overwrite?)

Lignes clées 

Set..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files/add(url='"_fn_"',overwrite="_$$$URLENCODE(..OverwriteExistingFile)_")"Set tSC=..AddAccessToken(.tHttpRequest)
  s tHttpRequest.EntityBody=##Class(%Stream.FileBinary).%New()
	s sc=tHttpRequest.EntityBody.CopyFromAndSave(pFileToUpload.Stream)
	Set tHttpResponse = ##class(%Net.HttpResponse).%New()
	S send="POST"s tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)

Envoi de la demande 

Cette fonction permet d'envoyer toute requête qui attend une réponse http. 

Assure le transfert des réponses et l'envoi de ENSLIB.HTTP.GenericMessage. De nombreux en-têtes sont renvoyés et une case à cocher permet de simplifier la réponse pour qu'elle ne contienne qu'un code d'erreur et des données. 

Construction de la réponse

Utilisé ailleurs dans l'EIT et non dans le code original de cette méthode

AddAccessToken

C'était le véritable apprentissage. il s'agit d'un code par défaut pour utiliser les paramètres OAuth Intersystems et non pas un code en dur à chaque fois que nous avons besoin de l'utiliser. 

Tout est construit autour de trois appels 

est autorisé et 

Set isAuthorised = ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..OAuthClientApplicationName,sessionId,..OAuthScope,.accessToken,,.responseProperties,.error)

 Obtenez un jeton d'accès

Set tSC = ##class(%SYS.OAuth2.Authorization).GetAccessTokenClient(..OAuthClientApplicationName,..OAuthScope,.properties,.error,.sessionId)

et un jeton d'ajout qui l'ajoute à l'en-tête - malheureusement, il ne semble pas qu'il puisse l'ajouter au corps du message si l'identifiant est requis par d'autres API

;La valeur par défaut de sslConfiguration provient de l'instance OAuth2.Client.        Set tSC  = ##class(%SYS.OAuth2.AccessToken).AddAccessToken(pHttpRequest,sendType,,..OAuthClientApplicationName,sessionId)

En outre, l'API Sharepoint nécessite une ressource. Nous avons généralisé l'utilisation de JSON, et si vous avez besoin d'autres paramètres, nous avons pensé à les ajouter en JSON afin de pouvoir réutiliser le modèle à l'avenir.

il l'ajoute à l'objet chaîne de caractères utilisé par les propriétés. il s'agit d'une chaîne de caractères sérialisée sous forme de tableau ou similaire 

s paramsarr = [].%FromJSON(..Params)
            s iterator = paramsarr.%GetIterator()
            s properties=""While iterator.%GetNext(.key,.value)
            {
                s properties(key)=value
            }

Exemples de traces

 

Obtention de la liste des fichiers

Téléchargement de fichiers

suppression de fichiers

si vous cochez cette case 

Ajout de fichiers

Remerciements à @Dean White 
 

https://youtu.be/485dTXYp2BU

Mise à jour - ajout d'un lien YouTube et correction du lien d'échange ouvert;

0
0 57
Article Lorenzo Scalese · Jan 22, 2025 5m read

Mise en œuvre de l'idée DPI-I-456

Idée

Le rôle de cet échantillon

Cet exemple a été cloné à partir de la version iris-interoperability-template. J'ai reconfiguré la production d' interopérabilité Production avec un adaptateur Inbound HTTP Adapter qui est utilisé par un service métier HTTP Business Service. Les détails de la configuration du service métier sont spécifiés dans la rubrique des paramètres par défaut du système System Default Settings. J'ai configuré le paramètre de l'intervalle d'appel pour appeler le serveur HTTPS une fois par heure. Vous pouvez modifier l'URL et la fréquence dans les paramètres du service. Screenshot

À l'origine, le service HTTP avait deux cibles. Le corps de réponse de chaque appel était envoyé en tant que message générique HTTP à un processus métier BPL et à une opération de fichier qui sauvegardait les données dans un dossier iris-http-calls.

Le service HTTP envoie un message générique HTTP à une opération de fichier. Ensuite, un service de fichiers envoie le fichier à un processus métier BPL.

Conditions préalables

Assurez-vous d'avoir installé git et Docker desktop.

Installation: ZPM

Ouverture de l'espace de noms IRIS avec l'interopérabilité activée. Ouvrez le terminal et appelez: USER>zpm "install iris-http-calls"

Installation: Docker

Clone/git extrait le référentiel dans n'importe quel répertoire local.

git clone https://github.com/oliverwilms/iris-http-calls.git

Ouvrez le terminal dans ce répertoire et lancez:

docker-compose build
  1. Lancez le conteneur IRIS avec votre projet:
docker-compose up -d

Comment exécuter l'échantillon

Ouvrez la production et lancez-la si elle n'est pas déjà en cours d'exécution. Il effectue des appels HTTP vers le serveur HTTPS à l'aide d'une URL.

Comment modifier le modèle

Ce référentiel est prêt à être codé dans VSCode avec le plugin ObjectScript. Installez VSCode, Docker et le pluginObjectScript et ouvrez le dossier dans VSCode.

Utilisez le menu pratique VSCode pour accéder à l'éditeur de règles de production et de règles métier et lancez un terminal: Screenshot 2020-10-29 at 20 15 56

utilisation des variables d'environnement

Cet exemple montre la façon dont vous pouvez introduire des variables env dans votre environnement dev. Supposons que vous ayez besoin de configurer la production avec un jeton secret pour accéder à une API à accès limité. Bien sûr, vous ne voulez pas exposer le secret à GitHub. Dans ce cas, le mécanisme des variables Env peut être utile. Tout d'abord, introduisez le fichier .env et configurez .gitignore pour filtrer .env à partir de git.

Ajoutez ensuite le jeton secret dans .env sous la forme ENV_VARIABLE="TOKEN VALUE"

L'introduction suivante consiste à faire importer les variables d'environnement dans dockerfile. Pour que cela fonctionne, ajoutez la section environnement dans [docker-compose.yml] (https://github.com/intersystems-community/iris-interoperability-template/blob/d2d7114de7c551e308e742359babebff5d535821/docker-compose.yml), par exemple:

environnement:
      - SAMPLE_TOKEN=${SAMPLE_TOKEN}

Ensuite, vous pourrez initialiser le conteneur en cours d'exécution avec les données des variables env, par exemple avec l'appel suivant, qui utilise la valeur du fichier .env comme paramètre de la production:

USER> d ##class(dc.Demo.Setup).Init($system.Util.GetEnviron("SAMPLE_TOKEN"))

paramètres de production du gestionnaire de paquets

Les utilisateurs de ce module peuvent utiliser des paramètres pour transmettre des données au module lors de l'installation et personnaliser le chemin d'accès au fichier pour l'opération de fichier et le service de fichier, ainsi que modifier l'URL. Il peut être utile lorsque les paramètres de configuration sont des jetons secrets permettant d'accéder à une API particulière. En tant que spécialiste, vous pouvez fournir de tels paramètres avec une balise par défaut dans module.xml.

<Default Name="FilePath" Value="iris_http_calls" />
<Default Name="UrlModify" Value="/Patient?_id=egqBHVfQlt4Bw3XGXoxVxHg3" />

Ces paramètres par défaut permettent aux utilisateurs d'appeler l'installation du paquet avec la possibilité de transmettre des paramètres. Par exemple, l'appel à l'installation peut être exécuté sous la forme suivante:

zpm "install iris-http-calls -D FilePath=iris_http_calls -D UrlModify=/MedicationStatement?patient=egqBHVfQlt4Bw3XGXoxVxHg3"
USER>zpm "install iris-http-calls -D FilePath=iris_http_calls -D UrlModify=/MedicationStatement?patient=egqBHVfQlt4Bw3XGXoxVxHg3"

[USER|iris-http-calls]        Reload START (/usr/irissys/mgr/.modules/USER/iris-http-calls/0.3.37/)
[USER|iris-http-calls]        Reload SUCCESS
[iris-http-calls]       Module object refreshed.
[USER|iris-http-calls]        Validate START
[USER|iris-http-calls]        Validate SUCCESS
[USER|iris-http-calls]        Compile START
[USER|iris-http-calls]        Compile SUCCESS
[USER|iris-http-calls]        Activate START
[USER|iris-http-calls]        Configure START
[USER|iris-http-calls]        Configure SUCCESS
[USER|iris-http-calls]        Activate SUCCESS

Les paramètres par défaut sont utilisés pour configurer la production dans l'appel suivant:

<Invoke Class="dc.Demo.Setup" Method="Init" >
  <Arg>${FilePath}</Arg>
  <Arg>${UrlModify}</Arg>
</Invoke>

La méthode Init de la classe dc.Demo.Setup configure le service et l'opération de fichier à l'aide du paramètre FilePath. Le paramètre UrlModify est utilisé pour modifier l'URL du service HTTP.

La production appelle le serveur HTTPS à l'aide de l'URL modifiée selon CallInterval. Le corps de réponse est envoyé dans un StreamContainer à une FileOperation. Un service de fichiers lit le fichier et transmet un conteneur de flux à un processus BPL.

0
0 34
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
Article Robert Cemper · Sept 15, 2024 3m read

Vous connaissez probablement cette situation :
il y a quelque temps, vous avez trouvé une fonction $ZU très spéciale pour
un type de problème spécifique. Une sorte de formule mystique.
Elle est devenue populaire et a été utilisée par de nombreux programmeurs
dans tout votre code et toutes vos installations .

Plusieurs versions et updates plus tard, vous êtes informé par ISC que
votre $ZU mystique est déprécié et n'est plus supporté. Et on vous conseille
de le remplacer par un nouveau $something(). 

0
0 56
Article Lorenzo Scalese · Août 8, 2024 3m read

Parfois, nous devons convertir le message FHIR en HL7 V2, par exemple pour enregistrer un patient dans le système PACS.
Dans cet article, les étapes à suivre pour obtenir les résultats souhaités en utilisant la production du serveur IRIS FHIR seront expliquées.

Voici les étapes à suivre:

  1. Assurez-vous que la production du serveur FHIR est démarrée.
  2. Enregistrez le service métier avec le point de terminaison FHIRServer.
  3. Définissez les processus métier pour convertir les messages FHIR en SDA, puis convertissez SDA en HL7 v2.
  4. Publiez la ressource JSON sur le point de terminaison FHIRServer et obtenez la réponse HL7 V2.

Examinons les étapes en détail.
 

Étape 1. Assurez-vous que la production du serveur FHIR est démarrée

Ouvrez la page de production et assurez-vous que la Production est démarrée. À l'étape suivante, nous devons nous assurer que le service commercial HS.FHIRServer.Interop.Service est enregistré auprès de FHIRServer


Step 2. Étape 2. Enregistrez le service métier avec le point de terminaison FHIRServer.

Depuis le portail de gestion, cliquez sur l'onglet Health (Santé)

Cliquez ensuite sur Configuration FHIR dans la liste, puis cliquez sur Server Configuration (configuration du serveur)

Sélectionnez le point de terminaison et assurez-vous que HS.FHIRServer.Interop.Service (service commercial défini dans la production) est défini sous le nom Service Config Name.

Étape 3. Définissez les processus métier pour convertir les messages FHIR en SDA, puis convertissez SDA en HL7 v2.

Définissez le rpocessus métier (le processus Solution.BP.Process est déjà défini dans l'application).
Veuillez noter que nous appliquons ici une condition selon laquelle le point de terminaison doit contenir une augmentation hl7 pour procéder à la conversion, sinon il est considéré comme une demande FHIR normale.


Transmettez ensuite le message au processus FHIR_SDA qui le convertira en SDA.
FHIR_SDA est dérivé d'une classe Solution.BP.Process définie par l'utilisateur.
Après conversion FHIR_SDA, le processus transmet le message au processus SDA_HL7
Le processus SDA_HL7 est dérivé d'une classe Solution.BP.SDATransformProcess définied  par l'utilisateur qui convertit le message SDA en message HL7 V2.


Définissez les processus de production comme suit:


Étape 4. Publiez la ressource JSON sur le point de terminaison FHIRServer et obtenez la réponse HL7 V2.

Depuis Postman, appelez le point de terminaison FHIRServer à l'aide de la méthode Post.
Notre point de terminaison FHIRServer est ci-dessous:
http://localhost:32783/csp/fhirserver/fhir/r4/hl7

REMARQUE:Notre point de terminaison FHIRServer est http://localhost:32783/csp/fhirserver/fhir/r4/, mais nous passons hl7 comme argument pour détecter à partir du processus métier de production qu'il ne s'agit pas d'une demande Post FHIR normale mais d'une demande de transformation du message FHIR.

Il s'agit de la même fonctionnalité que celle que nous pouvons utiliser à partir de nos applications Web. 
Sélectionnez la ressource patient, puis cliquez sur la ressource dans la liste, sélectionnez l'onglet HL7 FHIR ou Détails de la ressource, et cliquez sur le bouton "Transformer FHIR en HL7 V2"

L'application obtiendra le message de transformation HL7 V2 à l'aide de la production du serveur FHIR.



Transformation de HL7 V2 à FHIR

Sélectionnez "HL7 to FHIR" dans le menu et entrez les données HL7 V2. Cliquez sur le bouton de conversion pour transformer le message HL7 en message FHIR

La transformation de HL7 en FHIR utilise également la production pour convertir le message HL7 V2 en message FHIR.

Le service métier HL7_Http_Service envoie le message HL7 au processus HL7_SDA, puis HL7_SDA envoie les données SDA au processus SDA_FHIR, qui les convertit finalement en FHIR

Pour plus de détails et une révision du code, veuillez visiter la page d'application de l'échange ouvert iris-fhir-lab .
Merci!

0
0 69
Article Iryna Mykhailova · Juil 31, 2024 2m read

Je me suis retrouvé dans la situation peu confortable de travailler avec un système Linux sur lequel quelqu'un avait accidentellement désactivé l'accès utilisateur au shell Linux. HealthConnect était en cours d'exécution, assurant la maintenance de centaines d'interfaces. Pour résoudre le problème d'accès, cependant, nous devions arrêter l'hôte pour l'application d'un correctif.

Sans le shell, la commande iris n'est pas disponible pour contrôler l'instance, nous étions donc confrontés au risque d'arrêter le serveur de manière inélégante. Nous voulions éviter cela si possible...

0
0 68
InterSystems officiel Adeline Icard · Juil 15, 2024

Du 15 octobre 2024, la prise en charge de Caché & Ensemble sur MacOS sera obsolète.

Caché & Ensemble 2018.1.9 continuera d'être pris en charge, mais il n'y aura pas d'autres versions de maintenance pour MacOS. Cela signifie que Caché & Ensemble 2018.1.9 sera la version finale de ces produits sur MacOS.

Pour rappel, les versions de maintenance pour Caché et Ensemble sur les autres plateformes prises en charge prendront fin le 31 mars 2027.  Plus de détails à ce sujet peuvent être trouvés dans l'annonce de l'année dernière.

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

InterSystems FAQ rubric

Le type TIMESTAMP correspond au type de données %Library.TimeStamp (=%TimeStamp) dans les produits InterSystems, et le format est YYYY-MM-DD HH:MM:SS.nnnnnnnnn.

Si vous souhaitez modifier la précision après la virgule, définissez-la à l'aide de la méthode suivante.

1) Définir la précision à l'échelle du système

Portail de gestion : [Administration du système] > [Configuration] > [Paramètres SQL et objets] > [Paramètres SQL généraux] 
Précision de l'heure par défaut pour GETDATE(), CURRENT_TIME, CURRENT_TIMESTAMP. Vous pouvez spécifier le nombre de chiffres entre 0 et 9.

0
0 45
Article Pierre LaFay · Juin 26, 2024 1m read

InterSystems FAQ rubric

Pour désactiver le délai d'attente, réglez le délai d'attente de la requête sur désactivé dans les paramètres DSN :

Panneau de configuration de Windows > Outils d'administration > Sources de données (ODBC) > Configuration DSN du système

Si vous cochez la case Désactiver le délai d'attente des requêtes, le délai d'attente sera désactivé.

Si vous souhaitez le modifier du côté de l'application, vous pouvez le définir au niveau de l'API ODBC.

0
0 53
Article Pierre LaFay · Juin 26, 2024 3m read

Contexte

Dans les versions >=2021.2 d'InterSystems IRIS, nous pouvons utiliser le [binaire irispython pour écrire directement du code python au-dessus de nos instances IRIS] (https://docs.intersystems.com/iris20212/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON#AEPYTHON_runpython_script). Cela nous permet d'utiliser des paquets python, d'appeler des méthodes, de faire des requêtes SQL et de faire à peu près tout ce qui se fait en Objectscript mais en python.

Par exemple, ci-dessous, je vérifie si un espace de noms est présent :

#!/usr/irissys/bin/irispython
import iris
# call arbitrary class methods
result = iris.cls('%SYS.Namespace').Exists('USER')
if result == 1:
    print(f"Namespace USER is present")

Mais que se passe-t-il si ma méthode dans IRIS a des paramètres spéciaux tels que les paramètres Output et ByRef ? Comment utiliser les paramètres Output dans irispython ?

Par exemple, Ens.Director a beaucoup de paramètres de sortie sur ses méthodes, comment puis-je utiliser ces paramètres en python ?

Ens.Director:GetProductionStatus

// An example method stub from Ens.Director
ClassMethod GetProductionStatus(Output pProductionName As %String, Output pState As %Integer...

Essayer les méthodes de variables normales

À première vue, vous pouvez essayer ce qui suit :

import os
# Set namespace the manual way
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'

import iris

# TEST 1 avec variables de sortie
productionName, productionState = None, None
status = iris.cls('Ens.Director').GetProductionStatus(productionName, productionState) 

print("Success? -- {}".format(productionState != None))

Mais les deux tests ne renvoient pas les variables de sortie ! Vous pouvez essayer vous-même sur n'importe quel espace de noms Ensemble

Utilisation de iris.ref

L'utilitaire irispython iris.ref peut être utilisé pour capturer les variables Output et ByRef.

  1. Créer un objet iris.ref().
  2. Appelez votre méthode ObjectScript
  3. Utiliser la variable .value pour obtenir le résultat de ce paramètre
import os
# Définir l'espace en dur
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'

import iris

# TEST 2 avec des variables de sortie
productionName, productionState = iris.ref('productionName'), iris.ref('productionState')
status = iris.cls('Ens.Director').GetProductionStatus(productionName, productionState) 

print("Status: {}".format(status))
# see .value
print("Production: {}".format(productionName.value))
# see .value
print("Production State: {}".format(productionState.value))

image

0
0 50
Article Pierre LaFay · Juin 12, 2024 1m read

InterSystems FAQ rubric

Si vous souhaitez exécuter un fichier exécutable du système d'exploitation, une commande ou un programme créé dans un produit InterSystems au démarrage de ce dernier, écrivez le traitement dans la routine SYSTEM^%ZSTART. (La routine %ZSTART est créée dans l'espace de noms %SYS).

Avant d'écrire du code dans la routine SYSTEM^%ZSTART, assurez-vous qu'il fonctionne correctement dans toutes les conditions.

0
0 39
InterSystems officiel Sylvain Guilbaud · Juin 4, 2024

À partir de la sortie de la plateforme de données InterSystems IRIS® 2022.3, InterSystems a corrigé le mécanisme d'application des licences pour inclure les requêtes REST et SOAP. En raison de ce changement, les environnements dotés de licences non basées sur le cœur qui utilisent REST ou SOAP peuvent connaître une plus grande utilisation des licences après la mise à niveau. Pour déterminer si cet avis s'applique à votre licence InterSystems, suivez les instructions de la FAQ liée ci-dessous.

Ce tableau résume l'application :

0
0 71
Article Iryna Mykhailova · Mai 29, 2024 4m read

Lorsque nous utilisons InterSystems IRIS comme moteur d'interopérabilité, nous savons et aimons tous à quel point il est facile d'utiliser le Message Viewer pour examiner les traces des messages et voir exactement ce qui se passe dans votre production. Lorsqu’un système traite des millions de messages par jour, vous ne savez peut-être pas exactement par où commencer votre enquête.

Au cours de mes années de soutien aux productions IRIS, je me retrouve souvent à enquêter sur des choses comme...

0
0 47
Article Iryna Mykhailova · Mai 13, 2024 1m read

Dans Studio, vous pouviez ouvrir une classe directement par son nom, sans avoir à parcourir l'arborescence du paquetage par de multiples clics jusqu'à ce que vous arriviez à la classe souhaitée.

Vous pouvez faire Ctrl + O ou (File -> Open) et taper simplement le nom de la classe, par exemple :

Appuyez sur la touche "Enter" et la classe est ouverte.

Comment y parvenir en VSCode ?

C'est assez facile en fait, il suffit d'appuyer sur Ctrl + T (pour Windows par exemple), ou Go -> Go to Symbol in Workspace..., tapez le nom de la classe et vous y êtes.

Par exemple :

Cette solution a été mentionnée par @Dmitry Maslennikov comme une suggestion pour le rapport de problème GitHub (désigné comme une demande d'améliorationpour ces fonctionnalités - "Ouverture d'une classe par le nom à partir du serveur".

Voici un petit GIF pour la démonstration :

 

0
0 171
Article Iryna Mykhailova · Mai 10, 2024 2m read

Aimeriez-vous avoir accès au terminal Web directement à partir de votre VSCode ?

Voici une nouvelle entrée dans la rubrique "Trucs et astuces de VSCode" - et elle ressemble beaucoup à la précédente à propos de l'assistant SOAP Wizard.

Même principe et même résultat, bien que le cas d'utilisation soit différent.

Supposons donc que vous désiriez ouvrir le Terminal Web (et pour ceux d'entre vous qui ne sont pas encore familiers avec cet excellent outil créé par l'incroyable @Nikita Savchenko consultez sapage d'accueil) à partir de VSCode - vous pouvez adopter une approche similaire à celle que j'ai décrite dans l'article précédent.

Je reprendrai les étapes -

  • Ouvrez les paramètres JSON de l'extension ObjectScript
  • Ajouter un objet "links" dans l'objet "conn".
  • Ajouter la ligne suivante à l'intérieur de "links"
            "$(terminal) WebTerminal": "${serverUrl}/terminal/?ns=${ns}${serverAuth}"

Il se présentera comme suit -

 

Une fois que vous avez fait cela, vous pouvez trouver Web Terminal dans le menu en cliquant sur Connexion dans la barre d'état inférieure de VSCode.

Ceci est mentionné dans la discussion this VSCode ObjectScript's GitHub Issues (à propos de variables ${...} utilisées dans l'URL ci-dessus), par @John Murray 


Voici un court GIF pour illustrer ce processus (en commençant par le menu standard et en terminant par l'option permettant de lancer le terminal Web). -

 

0
0 65