Data Tagging in IRIS Using Embedded Python and the OpenAI API
Tags: ai, python, analytics, programming
Published: 2024-02-22 14:36:59

<p>The invention and popularization of Large Language Models (such as OpenAI's GPT-4) has launched a wave of innovative solutions that can leverage large volumes of unstructured data that was impractical or even impossible to process manually until recently. Such applications may include data&nbsp;retrieval (see Don Woodlock's ML301 course for a great intro to <a href="https://ai.meta.com/blog/retrieval-augmented-generation-streamlining-the-creation-of-intelligent-natural-language-processing-models/" target="_blank">Retrieval Augmented Generation</a>), sentiment analysis, and even fully-autonomous AI agents, just to name a few!</p>
<p>In this article, I want to demonstrate how the Embedded Python feature of IRIS can be used to directly interface with the Python OpenAI library, by building a simple data tagging application that will automatically assign keywords to the records we insert into an IRIS table. These keywords can then be used to search and categorize the data, as well as for data analytics&nbsp;purposes.&nbsp;I will use customer reviews of products as an example use case.</p>

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eeuwhyxff45bohdx0rua.png)
<h3>Prerequisites</h3>
<ul>
<li>A running instance of IRIS</li>
<li>An OpenAPI API key (which you can create <a href="https://platform.openai.com/account/api-keys" target="_blank">here</a>)</li>
<li>A configured development environment (I will be using <a href="https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cls?KEY=GVSCO" target="_blank">VS Code</a> for this article)</li>
</ul>
<h3>The <code>Review</code> Class</h3>
<p>Let us start by creating an ObjectScript class that will define the data model for our customer reviews. To keep things simple, we will only define 4 <code>%String</code>&nbsp;fields:&nbsp;the customer's&nbsp;name, the product name, the body of the review, and the keywords we will generate. The class should extend&nbsp;<code>%Persistent</code> so that we can save its objects to disk.</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Class</span> DataTagging.Review <span class="hljs-keyword">Extends</span> <span class="hljs-built_in">%Persistent</span>
{
<span class="hljs-keyword">Property</span> Name <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>(MAXLEN = <span class="hljs-number">50</span>) [ Required ]<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> Product <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>(MAXLEN = <span class="hljs-number">50</span>) [ Required ]<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> ReviewBody <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>(MAXLEN = <span class="hljs-number">300</span>) [ Required ]<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> Keywords <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>(MAXLEN = <span class="hljs-number">300</span>) [ SqlComputed, SqlComputeOnChange = ReviewBody ]<span class="hljs-comment">;</span>
}</code></pre>
<p>Since we want the <code>Keywords</code> property to be automatically computed on insert or update to the <code>ReviewBody</code> property, I am marking it as&nbsp;<code>SqlComputed</code>.&nbsp;You can learn more about computed values <a href="https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GSQL_tables#GSQL_tables_class_datavalues_computed" target="_blank">here</a>.</p>
<h3>The <code>KeywordsComputation</code>&nbsp;Method</h3>
<p>We now want to define a method that will be used to compute the keywords based on the review body. We can use&nbsp;Embedded Python to interact directly with the official <code>openai</code> Python package. But first, we need to install it. To do so,&nbsp;run the following shell command:</p>
<pre class="codeblock-container" idlang="12" lang="Shell Session" tabsize="4"><code class="language-shell hljs">&lt;your-IRIS-installation-path&gt;/bin/irispip install --target &lt;your-IRIS-installation-path&gt;/Mgr/python openai</code></pre>
<p>We can now use OpenAI's chat completion API to generate the keywords:</p>
<pre class="codeblock-container" idlang="2" lang="Python" tabsize="4"><code class="language-python hljs">ClassMethod KeywordsComputation(cols As %Library.PropertyHelper) As %String [ Language = python ]
{
    <span class="hljs-string">'''
    This method is used to compute the value of the Keywords property
    by calling the OpenAI API to generate a list of keywords based on the review body.
    '''</span>
    <span class="hljs-keyword">from</span> openai <span class="hljs-keyword">import</span> OpenAI

    client = OpenAI(
        <span class="hljs-comment"># Defaults to os.environ.get("OPENAI_API_KEY")</span>
        api_key=<span class="hljs-string">"&lt;your-api-key&gt;"</span>,
    )

    <span class="hljs-comment"># Set the prompt; use few-shot learning to give examples of the desired output</span>
    user_prompt = <span class="hljs-string">"Generate a list of keywords that summarize the content of a customer review of a product. "</span> \
                + <span class="hljs-string">"Output a JSON array of strings.\n\n"</span> \
                + <span class="hljs-string">"Excellent watch. I got the blue version and love the color. The battery life could've been better though.\n\nKeywords:\n"</span> \
                + <span class="hljs-string">"[\"Color\", \"Battery\"]\n\n"</span> \
                + <span class="hljs-string">"Ordered the shoes. The delivery was quick and the quality of the material is terrific!.\n\nKeywords:\n"</span> \
                + <span class="hljs-string">"[\"Delivery\", \"Quality\", \"Material\"]\n\n"</span> \
                + cols.getfield(<span class="hljs-string">"ReviewBody"</span>) + <span class="hljs-string">"\n\nKeywords:"</span>
    <span class="hljs-comment"># Call the OpenAI API to generate the keywords</span>
    chat_completion = client.chat.completions.create(
        model=<span class="hljs-string">"gpt-4"</span>,  <span class="hljs-comment"># Change this to use a different model</span>
        messages=[
            {
                <span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>,
                <span class="hljs-string">"content"</span>: user_prompt
            }
        ],
        temperature=<span class="hljs-number">0.5</span>,  <span class="hljs-comment"># Controls how "creative" the model is</span>
        max_tokens=<span class="hljs-number">1024</span>,  <span class="hljs-comment"># Controls the maximum number of tokens to generate</span>
    )

    <span class="hljs-comment"># Return the array of keywords as a JSON string</span>
    <span class="hljs-keyword">return</span> chat_completion.choices[<span class="hljs-number">0</span>].message.content
}</code></pre>
<p>Notice how in the prompt, I first specify&nbsp;the general instructions of how I want GPT-4 to "generate a list of keywords that summarize the content of a customer review of a product," and then I give two example inputs along with the desired outputs. I then insert&nbsp;<code>cols.getfield("ReviewBody")</code>&nbsp;and end the prompt with the word "Keywords:", nudging it to complete the sentence by providing the keywords in the same format as the examples I gave it. This is a simple example of the <a href="https://www.promptingguide.ai/techniques/fewshot" target="_blank">Few-Shot Prompting</a> technique.</p>
<p>I chose to store the keywords as a JSON string for the sake of simplicity of presentation; a better way to store them in production&nbsp;could be a <a href="https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&amp;CLASSNAME=%25Library.DynamicArray" target="_blank">DynamicArray</a>, but I will leave this as an exercise to the reader.</p>
<h3>Generating Keywords</h3>
<p>We can now test our data tagging application by inserting a row into our table using the following SQL query through the Management Portal:</p>
<pre class="codeblock-container" idlang="1" lang="SQL" tabsize="4"><code class="language-sql hljs"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> DataTagging.Review (<span class="hljs-keyword">Name</span>, Product, ReviewBody)
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Ivan'</span>, <span class="hljs-string">'BMW 330i'</span>, <span class="hljs-string">'Solid car overall. Had some engine problems but got everything fixed under the warranty.'</span>)</code></pre>
<p>As you can see below, it automatically generated four keywords for us. Well done!</p>

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fs2pfu51x2natctjue31.png)
<h2 id="conclusions">Conclusions</h2>
<p>To summarize, the ability of InterSystems IRIS to embed Python code allows for a large range of possibilities when dealing with unstructured data. Leveraging the power of OpenAI for automated data tagging is just one example of what one can achieve with this powerful feature. This leads to fewer human errors and higher efficiency overall.</p>