新しい投稿

検索

質問
· 2025年5月29日

How can I configure InterSystems ObjectScript Source Control with a client-side workspace in VS Code?

Hello everyone,

I’m using VS Code with the InterSystems ObjectScript extension and I want to keep my local folder (client-side) as the “source of truth” while still using the built-in Server Source Control features (diff, stage, commit, etc.) against my IRIS/Ensemble instance.

So far:

  • I have a local Git repository with my .cls and .mac files.
  • I’ve configured "objectscript.serverSourceControl.respectEditableStatus": true and "objectscript.serverSourceControl.disableOtherActionTriggers": false in my .vscode/settings.json.
  • I’m able to export and import code manually, and IntelliSense works when I export my server code locally.

However, when I edit files in my local folder, I don’t see the “Source Control” icons or context-menu actions injected by the ObjectScript extension—those only appear when I open files under the ISFS server mount.

What I’d like to achieve:

  • Edit files locally in my Git project.
  • On save (or via a keyboard shortcut), push changes to the server (export & compile).
  • Use the ObjectScript Source Control UI (icons, diff, commit…) directly on those local files without manually opening the ISFS folder.

Has anyone successfully configured a fully client-side workflow that still leverages the extension’s Server Source Control features? Are there additional settings, workspace layouts (multi-root?), or keybindings I should use to bridge the gap between my local edits and the server’s Source Control UI?

Thank you in advance for your guidance!

1 Comment
ディスカッション (1)3
続けるにはログインするか新規登録を行ってください
質問
· 2025年5月29日

Prompt Engineering for ollama-ai-iris

My use case is I want AI to extract six pieces of key information from medical visit notes.

It works okay with notes from Epic patient portals. I am struggling with one of my own visit Summaries. So far I have not been able to instruct ollama to give me a JSON response where it gave me what I am asking for.

My original medical_progress_notes_prompt was:

Medical progress note:
---
(document)
---

You are an expert in analyzing medical progress notes. Please carefully read the provided progress note above and extract the following key information:

Extract these six (6) properties from the progress note:
- Title
- Date: The date of the medical encounter
- Provider: The full name of the provider
- Patient: The full name of the patient
- Chief Complaint: The reason for the medical encounter
- Assessment: The plan of the provider

Guidelines:
- The extracted information should be factual and accurate to the document.
- Be concise
- If any property is missing from the note, please leave the field empty rather than guessing.

Answer in JSON format. The JSON should contain 6 keys: "Title", "Date", "Provider", "Patient", "Chief Complaint", and "Assessment".

One of the documents I downloaded from a Patient Portal contained this text: (Patient name was masked)

Name: Merle K Bxxxxxx | DOB: 3/21/1935 | MRN: 50313076-7 | PCP: IVAN LEVIN, MD | Legal Name: Merle K Bxxxxxx
Appointment Details
Pt calls requesting PA for Rifaximin be submitted.
 
Forwarded to PA Team
Electronically signed by Eridana H, RN at 9/9/2024  4:01 PMTelephone Encounter
Eridana H, RN at 9/9/2024  4:00 PM
MyChart® licensed from Epic Systems Corporation © 1999 - 2025 DH9079POC

The first time I processed it using BplSendChat the response from ollama was:

['Here', ' is', ' the', ' extracted', ' information', ' in', ' JSON', ' format', ':\n\n', '``', '`\n', '{\n', ' ', ' "', 'Title', '":', ' "",\n', ' ', ' "', 'Date', '":', ' "', '9', '/', '9', '/', '202', '4', '",\n', ' ', ' "', 'Provider', '":', ' "', 'E', 'rid', 'ana', ' H', ',', ' RN', '",\n', ' ', ' "', 'Patient', '":', ' "', 'Mer', 'le', ' J', ' Bush', 'kin', '",\n', ' ', ' "', 'Chief', ' Complaint', '":', ' "",\n', ' ', ' "', 'Ass', 'essment', '":', ' ""\n', '}\n', '``', '`\n\n', 'Note', ' that', ' some', ' fields', ' were', ' unable', ' to', ' be', ' extracted', ' from', ' the', ' provided', ' progress', ' note', ',', ' and', ' are', ' therefore', ' left', ' blank', '.', '']

This was before I added classMethod DecodeTokenArray(). I processed the same text 30 minutes later and the response from ollama was:

Here is the extracted information in JSON format:\n\n```\n{\n  "Title": "",\n  "Date": "",\n  "Provider": "Ivan Levin, MD",\n  "Patient": "Merle K Bxxxxxx",\n  "Chief Complaint": "",\n  "Assessment": ""\n}\n```\n\nThe following fields were missing from the progress note and were left empty: Title, Date.

I am pleased that the response became much easier to read for human eyes. I noticed that the second response left the date empty. I am not sure why.

I updated my question prompt slightly to this: 

Medical notes:
---
(document)
---

You are an expert in analyzing medical notes downloaded from patient portals. Please carefully read the provided note and extract the following key information:

Extract these six (6) properties from the medical note:
- Title
- Date: The date the medical encounter took place
- Provider: The full name of the provider
- Patient: The full name of the patient
- Chief Complaint: The reason for the medical encounter
- Assessment: The plan of the provider

Guidelines:
- The extracted information should be factual and accurate to the document.
- Be concise
- If any property is missing from the note, please leave the field empty rather than guessing.

Answer in JSON format. The JSON should contain 6 keys: "Title", "Date", "Provider", "Patient", "Chief Complaint", and "Assessment".

The response from ollama with the modified prompt was:

```\n{\n  "Title": "",\n  "Date": "9/9/2024",\n  "Provider": "Eridana H, RN",\n  "Patient": "Merle K Bxxxxxx",\n  "Chief Complaint": "",\n  "Assessment": ""\n}\n```

The original prompt did not yield the expected response from my visitSummary.txt

This is a comprehensive patient chart in electronic format, likely created using the eClinicalWorks system. The chart contains various sections that provide detailed information about the patient's medical history, current health status, diagnoses, medications, test results, and more.\n\nHere are some key points from the chart:\n\n**Demographics**\n\n* Patient name: Oliver Wilms\n* Date of birth: February 28, 1964\n* Accurate identifier (Acc No): 164557\n\n**Medical History**\n\nThe patient has a history of mixed hyperlipidemia (E78.2) and essential hypertension (I10). The patient is also taking medication for these conditions.\n\n**Current Health Status**\n\n* The patient's vital signs include:\n\t+ Temperature: 97.8°F\n\t+ Blood pressure: systolic 142 mmHg, diastolic 84 mmHg\n\t+ Heart rate: 71/min\n\t+ Respiratory rate: 16/min\n* The patient's weight is 189.8 lbs.\n* The patient's BMI is 25.38 kg/m2.\n\n**Medications**\n\nThe patient is taking:\n* Losartan potassium (25 mg) orally once a day for 90 days\n\n**Lab Results and Test Results**\n\nNo laboratory results or test results are listed in the chart.\n\n**Encounters and Procedures**\n\nThe patient has had an encounter with Valora Medical - Frisco on October 18, 2023, for a general adult medical examination without abnormal findings. No procedures were performed during this visit.\n\n**Assessments and Treatment Plans**\n\n* The patient's assessment is categorized as "Encounter for general adult medical examination without abnormal findings (ICD-10 - Z00.00)".\n* The treatment plan includes medication, with Losartan potassium prescribed for 90 days.\n\n**Insurance and Contact Information**\n\nThe patient is insured by United Healthcare, with a subscriber number and group number listed.\n\nOverall, this chart provides a comprehensive overview of the patient's medical history, current health status, diagnoses, medications, and other relevant information

When I ran it with the modified prompt, the ollama response was:

Based on the provided information, here is a summary of Mr. Wilms' medical record:\n\n**Demographics**\n\n* Date of Birth: February 28, 1964\n* Accurate Medical Record Number: 164557\n* Insurance Provider: United Healthcare\n* Address: 2444 Falcon Point Dr, Frisco, TX 75035-0000\n\n**Medical History**\n\n* Mixed hyperlipidemia (E78.2) - Active confirmed\n* Essential hypertension (59621000) - Essential (primary) hypertension (I10) - Active confirmed\n* No other significant medical history noted.\n\n**Vital Signs**\n\n* Temperature: 97.8°F (normal)\n* Blood pressure systolic: 142 mm Hg (elevated)\n* Blood pressure diastolic: 84 mm Hg (elevated)\n* Heart Rate: 71 /min (normal)\n* Respiratory Rate: 16 /min (normal)\n* Height: 72.5 in (within normal range)\n* Weight: 189.8 lbs (obese)\n* BMI: 25.38 kg/m2 (overweight)\n\n**Medications**\n\n* Losartan Potassium 25 MG - Oral, once a day for 90 days\n* Started on August 19, 2022\n\n**Lab Results and Tests**\n\n* No other lab results or test results are provided in this summary.\n\n**Imaging and Procedures**\n\n* None mentioned.\n\n**Physical Examination**\n\n* General appearance: Alert, no distress\n* Head: Normal\n* Eyes: Extraocular movement intact (EOMI), pupils equal, round, reactive to light and accommodation\n* Ears: Normal, tympanic membranes intact, clear, Bilateral\n* Throat: Clear\n* Neck/Thyroid: No lymphadenopathy, no masses, no thyromegaly\n* Heart: RRR, No M/G/R\n* Lungs: CTA (clear)\n* Abdomen: S/NT/ND BS + (no abnormalities noted)\n* Neurologic: Cranial nerves 2-12 grossly intact\n* Skin: Normal\n* Extremities: No clubbing, cyanosis, or edema\n\n**History of Present Illness (HPI)**\n\n* Mr. Wilms is here for a general adult medical examination without abnormal findings.\n* He denies any problems or side effects from his medication and states that he is taking it consistently.\n* He expresses no concerns about his health.\n\n**Care Team and Next Steps**\n\n* Care team includes Bradley Friedman, MD\n* Follow-up appointment scheduled in 6 months\n\nThis summary provides a general overview of Mr. Wilms' medical record, highlighting his current diagnoses, medications, lab results, physical examination findings, and next steps in his care.

I still did not get the answer in JSON format. I waited 315 seconds for the response. I modified the prompt again:

Medical notes:
---
(document)
---

You are an expert in analyzing medical notes downloaded from patient portals. Please carefully read the provided note and extract the following key information:

Extract these six (6) properties from the medical note:
- Title
- Date: The date the medical encounter took place
- Provider: The full name of the provider
- Patient: The full name of the patient
- Chief Complaint: The reason for the medical encounter
- Assessment: The plan of the provider

Guidelines:
- The extracted information should be factual and accurate to the document.
- Please do not summarize the note, but extract only what is asked for.
- If any property is missing from the note, please leave the field empty rather than guessing.

Answer in JSON format. The JSON should contain 6 keys: "Title", "Date", "Provider", "Patient", "Chief Complaint", and "Assessment".

This time I waited 301 seconds and then I got this response:

This is a comprehensive medical record for WILMS, Oliver, a 61-year-old male patient with the following information:\n\n**Demographics**\n\n* Date of birth: 02/28/1964\n* Address: 2444 Falcon Point Dr, Frisco, TX 75035-0000\n* Contact information:\n\t+ Phone: 972-261-6717 (guarantor)\n\t+ Phone: 469-744-0422 (emergency contact)\n* Insurance: United Healthcare\n\n**Medical History**\n\n* Mixed hyperlipidemia (E78.2) - Active confirmed\n* Essential hypertension (59621000) - Essential primary hypertension (I10) - Active confirmed\n* No other significant medical conditions or diagnoses mentioned.\n\n**Vital Signs**\n\n* Temperature: 97.8 degrees Fahrenheit\n* Blood pressure systolic: 142 mm Hg\n* Blood pressure diastolic: 84 mm Hg\n* Heart rate: 71 /min\n* Respiratory rate: 16 /min\n\n**Physical Examination**\n\n* General appearance: Alert, in no distress\n* Head: Normal\n* Eyes: Extraocular movement intact (EOMI), pupils equal, round, reactive to light and accommodation\n* Ears: Normal, tympanic membranes intact, clear, Bilateral\n* Throat: Clear\n* Neck/Thyroid: Neck supple, no lymphadenopathy, no masses, no thyromegaly\n* Heart: RRR (normal heart sounds)\n* Lungs: CTA (clear to auscultation bilaterally)\n* Abdomen: S/NT/ND (normal examination of abdomen)\n* Neurologic: Cranial nerves 2-12 grossly intact\n* Skin: Normal\n* Extremities: No clubbing, cyanosis, or edema\n* Oral cavity: Mucosa moist\n\n**History and Physical Notes**\n\n* The patient is here for a general adult medical examination without abnormal findings.\n* The patient denies any problems or side effects from their medication and has been taking it consistently.\n* The patient feels that the medication is working appropriately.\n\n**Care Team**\n\n* Emergency contact: Rose Wilms\n* Guarantor: Oliver Wilms\n\n**Next Appointment**\n\n* Scheduled for 6 months from the current date, with no specific reason mentioned.\n\nThis medical record provides a comprehensive overview of WILMS' current medical status, including his diagnoses, vital signs, physical examination findings, and medication regimen. It also includes information about his insurance coverage and contact details.

My prompting is not getting the desired result. Let me try again:

Medical notes:
---
(document)
---

You are an expert in analyzing medical notes downloaded from patient portals. 
Please carefully read the provided note, answer six questions, and place the answers inside a JSON object:
- (Title:) What is the title or type of note?
- (Date:) What is the date the medical encounter took place?
- (Provider:) What is the full name of the provider?
- (Patient:) What is the full name of the patient
- (Chief Complaint:) Why did the patient have this encounter?
- (Assessment:) What is the treatment plan of the provider?

Guidelines:
- Please do not summarize the note. You should answer the six questions and put the answer into the corresponding JSON property.
- If any property is missing from the note, please leave the field empty rather than guessing.
- Answer in JSON format. The JSON should contain 6 keys: "Title", "Date", "Provider", "Patient", "Chief Complaint", and "Assessment".

Based on the medical history and physical examination, here are some key findings:\n\n**Medical History:**\n\n* The patient has a history of mixed hyperlipidemia and essential hypertension.\n* He is taking Losartan Potassium 25mg orally once a day for 90 days.\n\n**Physical Examination:**\n\n* General appearance: alert, in no distress\n* Head: normal EOMI (extraocular movement intact), pupils equal, round, reactive to light and accommodation\n* Eyes: extraocular movement intact\n* Ears: normal, tympanic membranes intact, clear, Bilateral\n* Throat: clear\n* Neck/Thyroid: neck supple, no lymphadenopathy, no masses, no thyromegaly\n* Heart: RRR (normal heart sounds), No M/G/R (no murmurs or gallop rhythm)\n* Lungs: CTA (clear chest X-ray)\n* Abdomen: S/NT/ND BS+ (smooth, normal, and non-tender)\n* Neurologic: cranial nerves 2-12 grossly intact\n* Skin: normal\n* Extremities: no clubbing, cyanosis, or edema\n* Oral cavity: mucosa moist\n\n**History of Present Illness (HPI):**\n\n* The patient is here for a general adult medical examination and medication follow-up.\n* He denies any problems or side effects with his medication.\n* He feels that the medication is working appropriately.\n\n**Assessment:**\n\n* The patient is found to be generally healthy, with no abnormal findings on physical examination.\n* His blood pressure is 142/84 mmHg, which is within normal limits for an adult.\n* His lipid profile and thyroid function tests are not provided in this document.\n\n**Plan of Treatment:**\n\n* Continue Losartan Potassium 25mg orally once a day as prescribed.\n* Schedule follow-up appointments every 6 months to monitor blood pressure and lipid profiles.\n\n**Next Appointments:**\n\n* Follow-up appointment: 6 months from today\n* Reason for follow-up: Goals

Medical notes:
---
(document)
---

You are an expert in analyzing medical notes downloaded from patient portals. Please follow these directions. Please do not summarize the note. 
You should answer the six questions below, and put the question and answer into a JSON array.
If the answer cannot be found in the note, please leave it empty rather than guessing.  
The JSON array should look like this:
[ "insights": {"question": "What is the title or type of note?", "answer": "?"},
  {"question": "What is the date the medical encounter took place?", "answer": "?"},
  {"question": "What is the full name of the provider?", "answer": "?"},
  {"question": "What is the full name of the patient?", "answer": "?"},
  {"question": "Why did the patient have this encounter?", "answer": "?"},
  {"question": "What is the treatment plan of the provider?", "answer": "?"}]

1 Comment
ディスカッション (1)1
続けるにはログインするか新規登録を行ってください
記事
· 2025年5月29日 4m read

Use Mako Python template engine to generate dynamic content

Template engines are essential for producing customizable dynamic content, without the need for compilation and opening up great possibilities of extensibility for the template user. Especially if the template engine supports Python. A popular solution for template engine is Mko. It is is a template library written in Python. It provides a familiar, non-XML syntax which compiles into Python modules for maximum performance. Mako's syntax and API borrows from the best ideas of many others, including Django and Jinja2 templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded Python (i.e. Python Server Page) language, which refines the familiar ideas of componentized layout and inheritance to produce one of the most straightforward and flexible models available, while also maintaining close ties to Python calling and scoping semantics. Mako is used by reddit.com where it delivers over one billion page views per month. It is the default template language included with the Pylons and Pyramid web frameworks (source: https://www.makotemplates.org/).

Simple sample with Mako

This code snippet demonstrates the power of Mako in generating dynamic content with full Python support:

<%inherit file="base.html"/>
<%
    rows = [[v for v in range(0,10)] for row in range(0,10)]
%>
<table>
    % for row in rows:
        ${makerow(row)}
    % endfor
</table>
<%def name="makerow(row)">
    <tr>
    % for name in row:
        <td>${name}</td>\
    % endfor
    </tr>
</%def>

Mako statements:

Statement <% ... %> Executes Python code; used for logic, loops, conditionals, etc.
Block (for loops, if) <% if condition: %> / <% for item in items: %> Starts a control block; must be closed properly.
End of Block <% end %> or dedent in Python Marks the end of a control block (depending on syntax).
Include Statement <%include file="filename" /> Includes another template or file.
Call Function <%call expr()%> Calls a block or macro defined in the template.
Macro Definition <%def name(args): %> Defines a macro that can be reused.
Macro Call <%call name(args)%> Calls a macro defined with <%def %>.

 

Using Mako templates with IRIS

I developed an IRIS application that uses Mako, the health-gforms open exchange package (https://openexchange.intersystems.com/package/health-gforms). For this application, the Mako was used to generate a valid FHIR JSON message to create a new patient on server:

{
    "resourceType": "Patient",
    "name": [
        {
            "use": "official",
            "given": [
                "${data['name']}"
            ],
            "family": "${data['family']}"
        }
    ],
    "gender": "${data['gender']}",
    "birthDate": "${data['birthDate']}",
    "telecom": [
        {
            "value": "${data['telecom']}",
            "use": "mobile",
            "system": "phone"
        }
    ]
}

The Mako will receive a data object with patient given and family names, gender, birth date and telecom contact. Mako get the values to apply to final content using ${} instruction.

When the template is rendered the result is:

{
    "resourceType": "Patient",
    "name": [
        {
            "use": "official",
            "given": [
                "Jack"
            ],
            "family": "Chain"
        }
    ],
    "gender": "male",
    "birthDate": "1956-01-01",
    "telecom": [
        {
            "value": "555-555-555",
            "use": "mobile",
            "system": "phone"
        }
    ]
}

The IRIS Embeddded Python code to render the template is:

from mako.template import Template

...

for data in records:
        if getattr(data, "title") == "Given Name":
            makodata["name"] = getattr(data,"userResponse")
        elif getattr(data, "title") == "Family Name":
            makodata["family"] = getattr(data,"userResponse")
        elif getattr(data, "title") == "Gender":
            makodata["gender"] = getattr(data,"userResponse")
        elif getattr(data, "title") == "Birth Date":
            makodata["birthDate"] = getattr(data,"userResponse")
        elif getattr(data, "title") == "Phone":
            makodata["telecom"] = getattr(data,"userResponse")

template = Template(filename=templatepath)

return template.render(data=makodata)

1. A Template instance is created with filename to the template file.

2. The template.render receives makodata on data variable and render the content using it.

2 Comments
ディスカッション (2)2
続けるにはログインするか新規登録を行ってください
お知らせ
· 2025年5月29日

Technology Bonuses Results for the InterSystems FHIR and Digital Health Interoperability Contest 2025

Hi Developers!

We are happy to present the bonuses page for the applications submitted to the FHIR and Digital Health Interoperability Contest 2025!

See the results below.

Project

FHIR

Digital Health Interoperability

Vector Search

LLM AI or LangChain

Embedded Python

Docker

IPM

Online Demo

Community Idea Implementation

Find FHIR bug

Find Interoperability bug

First Article on DC

Second Article on DC

Video on YouTube

First Time Contribution

Total Bonus

Nominal 3 4 3 3 2 2 2 2 4 2 2 2 1 3 3 38
Smart Clinical Copilot - Configuration Management System                               0
hc-export-editor         2 2 2 2       2   3   13
FHIR Bundle to CCDA   4       2               3 3 12
fhir-craft 3 4       2           2 1   3 15
Langchain4jFhir 3     3   2               3 3 14
FHIRInsight 3 4 3 3 2 2 2         2 1 3   25
CCD Data Profiler   4         2   4     2 1 3 3 19
FhirReportGeneration 3     3 2 2                   10
iris-medbot-guide 3     3 2 2 2                 12
ollama-ai-iris       3 2 2   2           3   12
health-gforms 3 4     2 2 2 2 4     2 1 3   25
iris-fhir-bridge 3 4       2 2         2   3   16

IRIS Interop DevTools

3 4       - 2         2   3   14

Please apply with your comments for new implementations and corrections to be made here in the comments or in Discord.

45 Comments
ディスカッション (45)5
続けるにはログインするか新規登録を行ってください
記事
· 2025年5月29日 8m read

Integrate with Google Forms

Google Forms is the most popular solution on the market for collecting data, answering questionnaires and quizzes. So, it is the ideal solution for collecting patient data and responses in a practical way, without the need to expand or develop systems. In this article, I will detail how to create an account on Google Cloud, register the application that will consume the Google Forms API, generate the service user necessary to consume the API and finally perform actions to create new forms and collect data filled in them in an automated way in embedded Python and IRIS.

Create your Google Cloud account

If you don’t have Google Cloud account, follow these steps, otherwise go to the next section.
To create a Google Cloud Platform (GCP) account, you first need a Google account. Then, you can sign in to the Google Cloud console and start using the free tier or create a paid account. Here's a step-by-step guide:

1.    Go to the Google Cloud console: Visit cloud.google.com.
2.    Sign in with your Google account: If you don't have one, you'll need to create one.
3.    Accept the terms and conditions: Review and accept the Google Cloud terms and conditions.
4.    Start Free or Create a Billing Account:
a.    Free Tier: You can start using Google Cloud for free with the free tier.
b.    Paid Account: If you need more resources or advanced features, you'll need to create a billing account.
5.    Create a Billing Account (if needed): If you choose to create a paid account, you'll need to set up a billing account, which requires providing payment verification details and information about your organization.
6.    Get Started: Once your account is set up, you can access the Google Cloud console and start using the services.   

Create a Google Cloud project
 

It is mandatory to create a project to use Google APIs and SDKs into your programs.
Go to this link and follow the steps: https://developers.google.com/workspace/guides/create-project

 

Create a Google Cloud Service Account

It is required create a service account (credentials for applications) to your application consume the Google Forms API.

1.    Go to https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts , select the project that you selected in the previous section.
2.    Click the button + Create service account, fill the required fields and click the button Create and continue.
3.    Select the role Owner and click the Continue button.
4.    Save your Credentials JSON file to use later.
5.    Click the button Done.
6.    Click the button 3 dots and select Manage keys:
 
7.    Click the button Add key > Create new key
8.    Select JSON and click Create:
 
9.    The credentials are saved into your downloads page, SAVE THIS FILE BECAUSE I WILL USE IT LATER.


Enable Google Forms and Google Drive APIs

To your project consume the Google Forms and Google Drive (because Drive store the Google Forms definitions), you must enable the access:
1.    Go to https://console.cloud.google.com/apis/dashboard
2.    Click the button + Enable APIs and services
3.    Search for Google Drive API on the top field Search for APIs & Services, select Google Drive API and enable the API, if not enabled yet.
4.    Repeat the step 3 and Search for Google Forms API on the top field Search for APIs & Services, select Google Forms API and enable the API, if not enabled yet.


Get and run the health-gforms project

I created a sample application (health-gforms at https://openexchange.intersystems.com/package/health-gforms) that create a Google Form and collect data from it.


1.    Clone/git pull the repo into any local directory
$ git clone https://github.com/yurimarx/health-gforms/health-gforms.git
2.    Open the terminal in this directory and run:
$ docker-compose build
$ docker-compose up -d

 

Using the health-gforms API via Postman


1.    Download (https://www.postman.com/downloads/) and install the Postman application, if you don’t have this application yet.
2.    Download the postman collection from https://github.com/yurimarx/health-gforms/raw/refs/heads/master/health-g...
3.    Import this collection into your Postman:
 
4.    Click the 1. Post credentials to upload the google cloud service account credentials into your docker instance:
 
5.    Click the 2. Post form definition, to save the form definition (use a file from our root project folder, formpatient.json) into our docker instance:
 
6.    Click 3. Create form from file definition, to create a new google form on Google cloud and to collect data about a new patient:
 
7.    Copy the value into formId:
 
8.    Open the Google forms using your browser (pay attention for formId value, I used it into the path: https://docs.google.com/forms/d/1DtqV5edXVOjM-FAntPffRHqfVjMjOIJuiq5VXBc...
 
9.    To fill the Google Forms as end user, go to the button participant link   and past in a new browser tab:
 
10.    Fill the form as end user:
 
11.    Post the form answers.
12.    Click the 4. Get form content from template and change the value formId with the formId provided in the step 7:
 
13.    Click the send button and see the fhir json content to send to your FHIR server:

 

Behind the Scenes

Creating a Form into Google Forms:

ClassMethod CreateFormFromFile(formtitle As %String, filepath As %String) [ Language = python ]
{
    
    import httplib2
    import json
    from oauth2client.service_account import ServiceAccountCredentials
    from googleapiclient.discovery import build
    from mako.template import Template

    
    credentials = ServiceAccountCredentials.from_json_keyfile_name(
        "/opt/irisapp/credentials.json",
        scopes=["https://www.googleapis.com/auth/forms.body", 
                "https://www.googleapis.com/auth/forms", 
                "https://www.googleapis.com/auth/drive", 
                "https://www.googleapis.com/auth/drive.file"],
    )

    http = httplib2.Http()
    http = credentials.authorize(http)

    form_service = build("forms", "v1", http=http)

    new_form_template = Template('{"info": {"title": "${title}"}}')
    new_form_str = new_form_template.render(title=formtitle)
    NEW_FORM = json.loads(new_form_str)

    # Create the form
    try:
        result = form_service.forms().create(body=NEW_FORM).execute()
        formid = result["formId"]
        print(f'Form created: {result}')

        with open(filepath) as file:
            itemsjson = json.loads(file.read())
            # Adds form items
            items = (
                form_service.forms()
                .batchUpdate(formId=formid, body=itemsjson)
                .execute()
            )

        permission2 = {
            'type': 'anyone',
            'role': 'writer',
        }

        drive_service = build('drive', 'v3', credentials=credentials)

        drive_service.permissions().create(fileId=formid, body=permission2).execute()

        return formid
    except Exception as e:
        print(f'Error creating form: {e}')
}

1. We create the credentials using the service account data inside a credentials json file for form and drive apis.

2. We use this credentials to build a form_service.

3. The form_service is used to create the Google Form with header only.

4. The form_service reads the formpatient.json to create the forms itens (fields or questions). See this file content:

{
    "requests": [
        {
            "createItem": {
                "item": {
                    "title": "Given Name",
                    "questionItem": {
                        "question": {
                            "required": true,
                            "textQuestion": {}
                        }
                    }
                },
                "location": {"index": 0}
            }
        },
        {
            "createItem": {
                "item": {
                    "title": "Family Name",
                    "questionItem": {
                        "question": {
                            "required": true,
                            "textQuestion": {}
                        }
                    }
                },
                "location": {"index": 1}
            }
        },
        {
            "createItem": {
                "item": {
                    "title": "Gender",
                    "questionItem": {
                        "question": {
                            "required": true,
                            "choiceQuestion": {
                                "type": "RADIO",
                                "options": [
                                    {
                                        "value": "male"
                                    },
                                    {
                                        "value": "female"
                                    }
                                ]
                            }
                        }
                    }
                },
                "location": {"index": 2}
            }
        },
        {
            "createItem": {
                "item": {
                    "title": "Birth Date",
                    "questionItem": {
                        "question": {
                            "required": true,
                            "dateQuestion": {
                                "includeYear": true
                            }
                        }
                    }
                },
                "location": {"index": 3}
            }
        },
        {
            "createItem": {
                "item": {
                    "title": "Phone",
                    "questionItem": {
                        "question": {
                            "required": true,
                            "textQuestion": {}
                        }
                    }
                },
                "location": {"index": 4}
            }
        }
    ]   
}

5. Now we have a new form.

Collect user data responses from a Google Form:

ClassMethod GetResponsesFromFormId(formid As %String) [ Language = python ]
{
    import httplib2
    from oauth2client.service_account import ServiceAccountCredentials
    from googleapiclient.discovery import build

    credentials = ServiceAccountCredentials.from_json_keyfile_name(
        "/opt/irisapp/credentials.json",
        scopes="https://www.googleapis.com/auth/forms.responses.readonly",
    )

    # Create an httplib2.Http object to handle our HTTP requests and authorize
    # it with the Credentials.
    http = httplib2.Http()
    http = credentials.authorize(http)

    form_service = build("forms", "v1", http=http)

    # Prints the responses of your specified form:
    result = form_service.forms().responses().list(formId=formid).execute()
    return result
}

1. A credential object is created using the service account defined into credentials.json with authorization to read google forms.

2. A form_service is created from the credentials.

3. The form_service is used to get all responses from a formId.

2 Comments
ディスカッション (2)1
続けるにはログインするか新規登録を行ってください