Open AI integration with IRIS - His master voice’s – Are you angry?
Tags: ai, api, framework, programming
Published: 2024-05-23 19:03:26


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/66p8qnlnsnytld4h62i4.jpg)
<p><span>Continuing with the series of articles on voice file management, we are going to see how we can convert text into audio and receive the file with the chosen voice.<br>We will also explore how a service from OpenAI can help us analyze a text and determine the mood expressed in it.<br>Let's analyze how you can create your own voice file and how it can “read” your feelings.</span></p>
<p><!--break--></p>
<h2>The voice</h2>
<p>OpenAI offers a service that can create a voice file with your text. It is a lifesaver if you want to integrate a voice response service for visually impaired people.</p>
<p>I know that there are a lot of applications that can read a text and convert it to a voice, for instance, Loquendo, AWS, Text-to-speech by Google, etc...</p>
<p>However, the problem with most of them is that the voice is not as natural as you might expect. It happens because they typically translate the phoneme as it sounds in verbal language, but they do not place emphasis or emotion in the text.<br>On the other hand, when you use AI, it understands the context of the text and tries to add the correct intonation according to it, e.g. exclamation, question, sadness, joy, etc...</p>
<p>This service retrieves the file directly as a binary stream in the response object. It also lets you use different types of audio files: MP3, OVG, etc...</p>
<p>I did not want to return the content directly, but I planned to return a Base64 string that the user could convert to a file, play it directly, etc., and that can be used through a file API.</p>
<p>The first problem that I faced was converting the <a href="https://docs.intersystems.com/irisforhealthlatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&amp;CLASSNAME=%25Stream.GlobalBinary" target="_blank">%Stream.GlobalBinary</a> file into a Base64.</p>
<p>My first attempt was to read the binary and convert it as a string decoding a Base64</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">do</span> tHttpResponse.Data.Rewind()
<span class="hljs-keyword">set</span> response = <span class="hljs-string">""</span>
<span class="hljs-keyword">while</span> tHttpResponse.Data.AtEnd {
    <span class="hljs-keyword">set</span> temp=stream.<span class="hljs-keyword">Read</span>(<span class="hljs-number">4000</span>)
    <span class="hljs-keyword">set</span> temp=<span class="hljs-built_in">$system</span>.Encryption.Base64Encode(temp)
    <span class="hljs-keyword">set</span> response = response_temp
}
</code></pre>
<p>However, the content was not correctly converted to Base64.</p>
<p>Yet, as always, the community saves my life (again). The idea was to convert the <a href="https://docs.intersystems.com/irisforhealthlatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&amp;CLASSNAME=%25Stream.GlobalBinary" target="_blank">%Stream.GlobalBinary</a> to a <a href="https://docs.intersystems.com/irisforhealth20241/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&amp;PRIVATE=1&amp;CLASSNAME=%25Stream.GlobalCharacter" target="_blank">%Stream.GlobalCharacter</a> and then read the content in Base64. Thanks you, <a href="https://community.intersystems.com/user/marc-mundt" target="_blank">Marc Mundt</a><span>&nbsp;</span>for your <a href="https://community.intersystems.com/post/encoding-base64-stream-chunk-sizes#comment-200751" target="_blank">amazing response</a>.</p>
<p>After that, I created the following class to convert my GlobalBinary to GlobalCharacter stream.</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Class</span> St.OpenAi.B64.Util <span class="hljs-keyword">Extends</span> <span class="hljs-built_in">%RegisteredObject</span>
{

<span class="hljs-comment">/// Be cautious if changing CHUNKSIZE. Incorrect values could cause the resulting encoded data to be invalid.</span>
<span class="hljs-comment">/// It should always be a multiple of 57 and needs to be less than ~2.4MB when MAXSTRING is 3641144</span>
<span class="hljs-keyword">Parameter</span> CHUNKSIZE = <span class="hljs-number">2097144</span><span class="hljs-comment">;</span>
<span class="hljs-keyword">ClassMethod</span> B64EncodeStream(pStream <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Stream.Object</span>, pAddCRLF <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Boolean</span> = <span class="hljs-number">0</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Stream.Object</span>
{
    <span class="hljs-keyword">set</span> tEncodedStream=<span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%Stream.GlobalCharacter</span>).<span class="hljs-built_in">%New</span>()
    
    <span class="hljs-keyword">do</span> pStream.Rewind()
    
    <span class="hljs-keyword">while</span> ('pStream.AtEnd) {
        <span class="hljs-keyword">set</span> tReadLen=..#CHUNKSIZE
        <span class="hljs-keyword">set</span> tChunk=pStream.<span class="hljs-keyword">Read</span>(.tReadLen)
        
        <span class="hljs-keyword">do</span> tEncodedStream.<span class="hljs-keyword">Write</span>(<span class="hljs-built_in">$System</span>.Encryption.Base64Encode(tChunk,'pAddCRLF))
        <span class="hljs-keyword">if</span> (pAddCRLF &amp;&amp; 'pStream.AtEnd) {
            <span class="hljs-keyword">do</span> tEncodedStream.<span class="hljs-keyword">Write</span>(<span class="hljs-built_in">$c</span>(<span class="hljs-number">13</span>,<span class="hljs-number">10</span>))
        }
    }
    
    <span class="hljs-keyword">do</span> tEncodedStream.Rewind()
    
    <span class="hljs-keyword">quit</span> tEncodedStream
}

}</code></pre>
<p>My next step was to call it from the St.OpenAi.BO.Api.Connect class, and get the Base64 correctly.</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">set</span> pResponse = <span class="hljs-keyword">##class</span>(St.OpenAi.Msg.Audio.SpeachResponse).<span class="hljs-built_in">%New</span>()
<span class="hljs-keyword">do</span> pResponseStream.Content.Rewind()
<span class="hljs-keyword">set</span> contentfile = <span class="hljs-keyword">##class</span>(St.OpenAi.B64.Util).B64EncodeStream(pResponseStream.Content)
<span class="hljs-keyword">set</span> content = <span class="hljs-string">""</span>
<span class="hljs-keyword">while</span> ('contentfile.AtEnd)
{
   <span class="hljs-keyword">set</span> content = content_contentfile.<span class="hljs-keyword">Read</span>()
}
<span class="hljs-keyword">set</span> pResponse.Content=content</code></pre>
<p>I am very lucky to have such a great community by my side!</p>
<h2>What do you mean in your text?</h2>
<p>What do you think the intention is here if you have the following text?</p>
<div style="background: rgb(238, 238, 238); border: 1px solid rgb(204, 204, 204); padding: 5px 10px; text-align: center;">“My life has no meaning. I want to leave everything forever.”</div>
<p>You may feel that the speaker intends to do something bad to himself. Indeed, since you are human, you understand what the context is, and you know how to "read between the lines"</p>
<p>To a computer, a word is a collection of 0s and 1s, which should be transformed into characters for us to understand. We even put the characters in a different order; we also have words in other languages: "Hello", "Hola", and "Ciao".</p>
<p>We can create a relation between the word “Hello” and its counterpart in Spanish (“Hola”) or Italian (“Ciao”).</p>
<p>However, there is no easy way to relate the phrase "My life has no meaning" to something negative, or “I want to leave everything forever“ to your desire to harm yourself.</p>
<p>If you try to do the same as before, we can consider that the phrase “I want to leave everything forever” means that you want to harm yourself. It might make sense, but the same line in the following phrase “I don't like this city. I want to leave everything forever” is neutral.</p>
<p>Indeed, the context is crucial to determine if a text is neutral or contains violence, hate, or self-harm.</p>
<h3>How can you train your AI in moderation?</h3>
<p>Training an AI to moderate texts involves several steps and essential considerations:</p>
<p><strong>Data Collection with Labels:</strong> It is critical to gather a sufficiently large and diverse dataset containing examples of texts you need to moderate, labeled as appropriate or inappropriate according to your moderation criteria.</p>
<p><strong>Definition of Moderation Criteria:</strong> You need to clearly define what types of content you consider inappropriate and what actions should be taken regarding them (e.g., removing, hiding, or marking them as potentially offensive).</p>
<p><strong>Selection of Algorithms and Models:</strong> You can use supervised machine learning techniques, where models are trained with labeled examples, or semi-supervised machine learning techniques, where both labeled and unlabeled examples are leveraged. Models like BERT, GPT, or specific text classification models can come in handy in this case.</p>
<p><strong>Data Preprocessing:</strong> Before training the model, you should perform such tasks as tokenization, text normalization (e.g., converting all parts of the text to lowercase), removal of special characters, etc.</p>
<p><strong>Model Training:</strong> Utilize your labeled data to train the selected model. During training, the model will learn to distinguish between appropriate and inappropriate texts based on the defined criteria.</p>
<p><strong>Model Performance Evaluation:</strong> After training, evaluate the model's performance with the help of a separate test dataset. It will help you determine how well the model is generalizing and whether it needs additional adjustments.</p>
<p><strong>Fine-Tuning and Continuous Improvement:</strong> You are likely to need to fine-tune and improve your model as you gather more data and observe its performance in the real world. It may involve retraining the model with updated data and parameter optimization.</p>
<p><strong>Production Deployment:</strong> Once you are satisfied with the model's performance, you can deploy it in your online moderation system to help automate the text moderation process.</p>
<p>It is vital to note that no automated moderation system is perfect, so it is always advisable to combine AI with human supervision to address difficult cases or new types of inappropriate content.</p>
<p>The main purpose of OpenAI's "moderation" service is to provide artificial intelligence tools and models to help online platforms moderate and manage user-generated content. It includes detecting and mitigating such inappropriate content as spam, hate speech, harassment, violence, sexually explicit content, etc. The goal is to help develop a safer and healthier online environment for users by reducing the presence of harmful content. We can do it by identifying content that might be harmful and taking action.</p>
<p>When using OpenAI’s moderation, the previous text would throw us the following result:</p>
<pre class="codeblock-container" idlang="3" lang="JSON" tabsize="4"><code class="language-json hljs">{
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"modr-9FRqaywTVudh3Jk9FEYnxuRbrDmUH"</span>,
    <span class="hljs-attr">"model"</span>: <span class="hljs-string">"text-moderation-007"</span>,
    <span class="hljs-attr">"results"</span>: [
        {
            <span class="hljs-attr">"flagged"</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">"categories"</span>: {
                <span class="hljs-attr">"sexual"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"hate"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"harassment"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"self-harm"</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">"sexual/minors"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"hate/threatening"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"violence/graphic"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"self-harm/intent"</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">"self-harm/instructions"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"harassment/threatening"</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">"violence"</span>: <span class="hljs-literal">false</span>
            },
            <span class="hljs-attr">"category_scores"</span>: {
                <span class="hljs-attr">"sexual"</span>: <span class="hljs-number">6.480985575763043e-6</span>,
                <span class="hljs-attr">"hate"</span>: <span class="hljs-number">0.00005180266089155339</span>,
                <span class="hljs-attr">"harassment"</span>: <span class="hljs-number">0.000108763859316241</span>,
                <span class="hljs-attr">"self-harm"</span>: <span class="hljs-number">0.861529529094696</span>,
                <span class="hljs-attr">"sexual/minors"</span>: <span class="hljs-number">6.210859737620922e-7</span>,
                <span class="hljs-attr">"hate/threatening"</span>: <span class="hljs-number">9.927841659873593e-8</span>,
                <span class="hljs-attr">"violence/graphic"</span>: <span class="hljs-number">0.000012115803656342905</span>,
                <span class="hljs-attr">"self-harm/intent"</span>: <span class="hljs-number">0.9326919317245483</span>,
                <span class="hljs-attr">"self-harm/instructions"</span>: <span class="hljs-number">0.00005927650636294857</span>,
                <span class="hljs-attr">"harassment/threatening"</span>: <span class="hljs-number">7.471672233805293e-6</span>,
                <span class="hljs-attr">"violence"</span>: <span class="hljs-number">0.0008052702760323882</span>
            }
        }
    ]
}
</code></pre>
<p>It has detected that there is an intent of self-harm, the percentage is:</p>
<pre>Self-harm: 86.15%
Self-harm intent: 93.26%</pre>
<p>You can develop some filters using these percentages and detected categories and activate alerts or resend other types of responses more intelligently.</p>
<p>The model classifies the following categories:</p>
<table align="center" border="1" cellpadding="1" cellspacing="1" style="width:500px;">
<thead>
<tr>
<th scope="col">CATEGORY</th>
<th scope="col">DESCRIPTION</th>
</tr>
</thead>
<tbody>
<tr>
<td>hate</td>
<td>Content that expresses, incites, or promotes hate based on race, gender, ethnicity, religion, nationality, sexual orientation, disability status, or caste. Hateful content aimed at non-protected groups (e.g., chess players) is harassment.</td>
</tr>
<tr>
<td>hate/threatening</td>
<td>Hateful content that includes violence or serious harm towards the targeted group based on race, gender, ethnicity, religion, nationality, sexual orientation, disability status, or caste.</td>
</tr>
<tr>
<td>harassment</td>
<td>Content that expresses, incites, or promotes harassing language towards any target.</td>
</tr>
<tr>
<td>harassment/threatening</td>
<td>Harassment content that additionally includes violence or serious harm towards any target.</td>
</tr>
<tr>
<td>self-harm</td>
<td>Content that promotes, encourages, or depicts such acts of self-harm as suicide, self-cutting/injury, and eating disorders.</td>
</tr>
<tr>
<td>self-harm/intent</td>
<td>Content where the speaker expresses that they are engaging or intend to engage in such acts of self-harm as suicide, self-cutting/injury, and eating disorders.</td>
</tr>
<tr>
<td>self-harm/instructions</td>
<td>Content that encourages performing such acts of self-harm as suicide, self-cutting/injury, and eating disorders, or that gives instructions or advice on how to commit such acts.</td>
</tr>
<tr>
<td>sexual</td>
<td>Content meant to arouse sexual excitement, e.g. the description of sexual activity, or that promotes sexual services (excluding sex education and wellness).</td>
</tr>
<tr>
<td>sexual/minors</td>
<td>Sexual content that includes an individual who is under 18 years old.</td>
</tr>
<tr>
<td>violence</td>
<td>Content that depicts death, violence, or physical injury.</td>
</tr>
<tr>
<td>violence/graphic</td>
<td>Content that depicts death, violence, or physical injury in graphic detail.</td>
</tr>
</tbody></table>
<p>The score value is between 0 and 1, where higher values denote higher confidence. The scores should not be interpreted as probabilities.</p>
<h2>Speech</h2>
<h3>Endpoint: POST https://api.openai.com/v1/audio/speech</h3>
<p>The Audio API provides a speech endpoint based on the TTS (text-to-speech) model. It comes with 6 built-in voices and can be used to do the following:</p>
<ul>
<li>Narrate a written blog post.</li>
<li>Produce spoken audio in multiple languages.</li>
<li>Give real time audio output using streaming.</li>
</ul>
<p>The input parameters would be as mentioned below:</p>
<ul>
<li><strong>model</strong>: Required.</li>
<li style="list-style-type: none">It is related to the available TTS models: tts-1 or tts-1-hd.</li>
<li><strong>input</strong>: Required.</li>
<li style="list-style-type: none">It is connected to the text used to generate audio. The maximum length is 4096 characters.</li>
<li><strong>voice</strong>: Required.</li>
<li style="list-style-type: none">It is linked to the voice to employ when generating the audio. Supported voices are “alloy”, “echo”, “fable”, “onyx”, “nova”, and “shimmer”. Previews of the voices are available in <a href="https://platform.openai.com/docs/guides/text-to-speech/voice-options">Text to speech guide.</a></li>
<li><strong>response_format</strong>: Optional.</li>
<li style="list-style-type: none">It is associated with the format of the audio. Supported formats are “mp3”, “opus”, “aac”, “flac”, “wav”, and “pcm”. if not indicated, the default value is “mp3”.</li>
<li><strong>speed</strong>: Optional.</li>
<li style="list-style-type: none">It is bonded with the speed of the generated audio. Select a value from “0.25” to “4.0”. If not indicated, the default value is “1.0”.</li>
</ul>
<h2>Moderations</h2>
<h3>Endpoint: POST https://api.openai.com/v1/moderations</h3>
<p>The input parameters would be as mentioned below:</p>
<ul>
<li><strong>model</strong>: Optional.</li>
<li style="list-style-type: none">It is related to the available moderation models: text-moderation-stable or text-moderation-latest. if not indicated, the default value is “text-moderation-latest”.</li>
<li><strong>input</strong>: Required.</li>
<li style="list-style-type: none">It is connected to the text to classify.</li>
</ul>
<h2>What's next?</h2>
<p>Since OpenAI is evolving continuously, nobody knows what next feature they will release.</p>
<p>Do not forget to mark the article with a “like” if you enjoyed it.</p>