Rechercher

Digest
· Apr 1

Résumé de la communauté des développeurs d'InterSystems, Mars 2025

Bonjour, voici la newsletter de la communauté des développeurs de Mars 2025.
Statistiques générales
✓ Nouvelles publications 20 publiées le Mars :
 9 nouveaux articles
 9 nouvelles annonces
 2 nouvelles questions
✓ Nouveaux membres 2 ayant rejoint le Mars
✓ Publications 1,133 publiées depuis le début
✓ Membres 166 ayant rejoint depuis le début
Meilleures publications
Les meilleurs auteurs du mois
Articles
Annonces
#InterSystems IRIS
#Communauté des développeurs officielle
Questions
Mars, 2025Month at a GlanceInterSystems Developer Community
Article
· Apr 1 1m read

Cómo obtener información del servidor/instancia

Hola a todos,

Como parte del desarrollo de una API para saber a qué instancia de IRIS está conectada, he encontrado algunos métodos para obtener información sobre el servidor que pueden ser útiles.

Obtener el nombre del servidor: $SYSTEM.INetInfo.LocalHostName()

Obtener la IP del servidor: $SYSTEM.INetInfo.HostNameToAddr($SYSTEM.INetInfo.LocalHostName())

Obtener el nombre de la instancia: $PIECE($SYSTEM,":",2)

Entonces, he creado el siguiente código como clase BS:

Class St.Common.Api Extends (%CSP.REST, Ens.BusinessService)
{
{

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
	<Route Url="/check" Method="GET" Call="Check"/>
</Routes>
}

ClassMethod Check() As %Status
{
	set serverInfo = {}
	set serverInfo.ServerName = $SYSTEM.INetInfo.LocalHostName()
	set serverInfo.ServerIP = $SYSTEM.INetInfo.HostNameToAddr($SYSTEM.INetInfo.LocalHostName())
	set serverInfo.Instance = $PIECE($SYSTEM,":",2)
	
	write serverInfo.%ToJSON()
	quit $$$OK
}
}

Llamando al método:

localhost:52773/common/api/check

{
  "ServerName": "LAPTOP-KURRO-3",
  "ServerIP": "11.52.197.99",
  "Instance": "HEALTHCONNECT"
}

Espero que te sea tan útil como a mí.

Saludos cordiales.

Discussion (0)1
Log in or sign up to continue
Article
· Apr 1 1m read

How to get server/instance info

Hi all,

As part of the development an API to know what is the instance of IRIS is connected, I've found some methods to know information about the server that can help you.

Get the server name: $SYSTEM.INetInfo.LocalHostName()

Get the server IP: $SYSTEM.INetInfo.HostNameToAddr($SYSTEM.INetInfo.LocalHostName())

Get the instance name: $PIECE($SYSTEM,":",2)

So, I have created the following code as BS class:

Class St.Common.Api Extends (%CSP.REST, Ens.BusinessService)
{
{

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
	<Route Url="/check" Method="GET" Call="Check"/>
</Routes>
}

ClassMethod Check() As %Status
{
	set serverInfo = {}
	set serverInfo.ServerName = $SYSTEM.INetInfo.LocalHostName()
	set serverInfo.ServerIP = $SYSTEM.INetInfo.HostNameToAddr($SYSTEM.INetInfo.LocalHostName())
	set serverInfo.Instance = $PIECE($SYSTEM,":",2)
	
	write serverInfo.%ToJSON()
	quit $$$OK
}
}

Calling the method:

localhost:52773/common/api/check

{
  "ServerName": "LAPTOP-KURRO-3",
  "ServerIP": "11.52.197.99",
  "Instance": "HEALTHCONNECT"
}

I hope it is as useful to you as it has been to me.

Best regards

2 Comments
Discussion (2)3
Log in or sign up to continue
Article
· Apr 1 2m read

Hey chat, what's up with my Interoperability

What if you could speak in a chat to check what happens in Interoperability, is there any errors, and even solve some types of issues.

With MCP server, you can connect any of your MCP Client, for instance Claude, to IRIS, and ask to check on Interoperability

What you need is a simple configuration of Claude.

Claude settings in Developer section, can help to find a config file

With simple setting, like here, it only requires access to IRIS, nothing needs to be installed in IRIS.

{
  "mcpServers": {
    "iris": {
      "command": "uvx",
      "args": [
        "mcp-server-iris"
      ],
      "env": {
        "IRIS_HOSTNAME": "localhost",
        "IRIS_PORT": "1972",
        "IRIS_NAMESPACE": "USER",
        "IRIS_USERNAME": "_SYSTEM",
        "IRIS_PASSWORD": "SYS"
      }
    }
  }
}

After Claude restart, it should display that some MCP tools are available now, click there will display all the tools available

Claude knowing about the tools available, and by prompt you provide, can select which tool best suite to be used to help with the query.

Guess, it works fine, let's check for errors.

We are able to see the actual response from the tool. And Claude analyzed the output and extracted errors it found. Suggesting why the errors may happen. And even offers a ways to solve them.

Currently the implementation of this MCP Server does not offer any code editing capabilities, we are not going to ask to fix the code. But we can try to recover production.

Restart should help

Here we are, all good now.

Well, since our production is working fine now. Let's have a look at the data we may already collected.

To help with it, Claude will use tool which can execute SQL Query.

Even though, I put class name instead of table name, and it discovered that there is no such table, but it did not give up, and in one session, managed to find out the real name for the table, and fetch some data.

When it tries to get some more understanding in the data it collected, and tried to even guess the column names.

Found the real columns, but struggled with reserved keywords, and did not try to use "FOUND"

And with a final attempt

It decided to keep it simple, but using knowledge about column names, it got it right and gave some summary

 

At this stage, the MCP seems to be in the very beginning of its journey, but still we have quite a good tool.

If you like this tool, please vote on the current OpenExchange Contest

1 Comment
Discussion (1)1
Log in or sign up to continue
Article
· Apr 1 5m read

d[IA]gnosis: searching for similarities in our vector database and using LLM to extract diagnoses

I just realized I never finished this serie of articles!

GIF de Shame On You Meme | Tenor

In today's article, we'll take a look at the production process that extracts the ICD-10 diagnoses most similar to our text, so we can select the most appropriate option from our frontend.

Looking for diagnostic similarities:

From the screen that shows the diagnostic requests received in HL7 in our application, we can search for the ICD-10 diagnoses closest to the text entered by the professional.

To speed up the search process, we stored the vectorized text of the diagnosis received at the time of capturing the HL7 message in our database. To do this, we implemented a simple BPL that extracts the diagnosis code from the message and sends it to a method to generate the vector:

And here is the code that vectorizes the diagnosis received:

ClassMethod GetEncoding(sentence As %String) As %String [ Language = python ]
{
        import sentence_transformers
        # create the model and form the embeddings
        model = sentence_transformers.SentenceTransformer('/iris-shared/model/')
        embeddings = model.encode(sentence, normalize_embeddings=True).tolist() # Convert search phrase into a vector
        # convert the embeddings to a string
        return str(embeddings)
}

This way, we have our diagnostics vectorized, avoiding having to vectorize them again every time we need to perform a search on them. As you can see, we're using the  sentence_transformer  library to generate the vector with the downloaded model.

With all our received diagnoses vectorized and stored in our database, we will only need to execute a SELECT query to extract those ICD-10 diagnoses closest to the received diagnoses.

Let's look at the code for the method published in our web service that will return the 25 most similar diagnoses:

ClassMethod GetCodeOptions(idRequest As %String) As %Status
{
	set ret = $$$OK
    try {
        set sql = 
            "SELECT TOP 25 * FROM (SELECT C.CodeId, C.Description, VECTOR_DOT_PRODUCT(C.VectorDescription, R.VectorDescription) AS Similarity FROM ENCODER_Object.Codes C, ENCODER_Object.CodeRequests R WHERE R.ID = ?) WHERE Similarity > 0.5 ORDER BY Similarity DESC"
		set statement = ##class(%SQL.Statement).%New()
		$$$ThrowOnError(statement.%Prepare(sql))
        set rs = statement.%Execute(idRequest)

        set array = []
        while rs.%Next() {
            do array.%Push({
                    "CodeId": (rs.%Get("CodeId")),
                    "Description": (rs.%Get("Description")),
                    "Similarity": (rs.%Get("Similarity"))
                })
        }
        set %response.Status = ..#HTTP200OK
        write array.%ToJSON()

    } catch ex {
        set %response.Status = ..#HTTP400BADREQUEST
        return ex.DisplayString()
    }
    quit ret
}

If you look at the query, we're limiting the search to 25 results and only those diagnoses that exceed a similarity level of 0.5. For the similarity calculation, we chose the VECTOR_DOT_PRODUCT  method , although we could have used VECTOR_COSINE . I haven't found any substantial differences between them in this case.

Here we have the search result:

Using LLM to identify diagnosis

So far we've only done a simple search for perfectly identified diagnoses, but... Could we identify diagnoses directly from free text?

Let's try it!

For this feature, we'll use Ollama, which provides us with an API to send our questions to a LLM model of our choice. If you take a look at our docker-compose.yml file, you'll see the Ollama container declaration:

  ## llm locally installed
  ollama:
    build:
      context: .
      dockerfile: ollama/Dockerfile
    container_name: ollama
    volumes:
    - ./ollama/shared:/ollama-shared
    ports:
      - "11434:11434"

For the door, we defined in the container deployment that the LLM llama3.2 should be downloaded.  The reason? Well, it seemed to me to be the one that performed the best in my tests.

This is the content of the entrypoint.sh  file that runs when the container is deployed:

#!/bin/bash
echo "Starting Ollama server..."
ollama serve &
SERVE_PID=$!

echo "Waiting for Ollama server to be active..."
while ! ollama list | grep -q 'NAME'; do
  sleep 1
done

ollama pull llama3.2

wait $SERVE_PID

To take advantage of Ollama's capabilities, I have modified the screen that analyzes free texts to indicate that it should use the LLM to extract diagnoses from the entered text.

We have also modified the business process by adding a method that will construct the prompt needed for llama3.2  to directly extract the diagnostics:

Method AnalyzeText(text As %String, analysisId As %String, language As %String) As %String [ Language = python ]
{
    import sentence_transformers
    import iris
    import requests

    try:
        url = "http://ollama:11434/api/generate"
        data = {
            "model": "llama3.2",
            "prompt": "Extrae únicamente los diagnósticos del siguiente texto separándolos por , y sin añadir interpretaciones: "+text,
            "stream": False
        }
        response = requests.post(url, json=data)
        analyzedText = response.json()
        
        model = sentence_transformers.SentenceTransformer('/iris-shared/model/')
        phrases = analyzedText['response'].split(",")
        sqlsentence = ""
        # iris.cls("Ens.Util.Log").LogInfo("ENCODER.BP.AnalyzeTextProcess", "AnalyzeText", "Starting process")
        for phraseToAnalyze in phrases :
            if phraseToAnalyze != "":
                embedding = model.encode(phraseToAnalyze, normalize_embeddings=True).tolist()
                sqlsentence = "INSERT INTO ENCODER_Object.TextMatches (CodeId, Description, Similarity, AnalysisId, RawText) SELECT TOP 50 * FROM (SELECT CodeId, Description, VECTOR_DOT_PRODUCT(VectorDescription, TO_VECTOR('"+str(embedding)+"', DECIMAL)) AS Similarity, '"+analysisId+"', '"+phraseToAnalyze+"' FROM ENCODER_Object.Codes) ORDER BY Similarity DESC"
                stmt = iris.sql.prepare("INSERT INTO ENCODER_Object.TextMatches (CodeId, Description, Similarity, AnalysisId, RawText) SELECT TOP 50 * FROM (SELECT CodeId, Description, VECTOR_DOT_PRODUCT(VectorDescription, TO_VECTOR(?, DECIMAL)) AS Similarity, ?, ? FROM ENCODER_Object.Codes) WHERE Similarity > 0.65 ORDER BY Similarity DESC")                    
                rs = stmt.execute(str(embedding), analysisId, phraseToAnalyze)        
    except Exception as err:
        iris.cls("Ens.Util.Log").LogInfo("ENCODER.BP.AnalyzeTextProcess", "AnalyzeText", repr(err))
        return repr(err)

    return "Success"
}

The prompt is very simple; it could possibly be improved and fine-tuned as needed; I'll leave it up to you. This method will retrieve the LLM response, separated by commas, and store the vectorized diagnoses found in our database. Here's an example of the result:

In the lower right corner, you can see all the LLM findings regarding the text in the lower left corner.

Well, we'd now have an application that uses LLM models to help us code diagnoses. As you've seen, it's not at all complicated to implement and can be a good foundation for building more complex and comprehensive solutions.

Thank you very much for your time!

Discussion (0)1
Log in or sign up to continue