<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>REST API on SNow adventures</title>
    <link>https://www.snow-adventures.com/tags/rest-api/</link>
    <description>Recent content in REST API on SNow adventures</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>© Samuel Meylan - 2020</copyright>
    <lastBuildDate>Fri, 11 Jul 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://www.snow-adventures.com/tags/rest-api/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Convert condition builder queries to human-readable text in ServiceNow</title>
      <link>https://www.snow-adventures.com/posts/convert-condition-builder-queries-to-human-readable-text-in-servicenow/</link>
      <pubDate>Fri, 11 Jul 2025 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/convert-condition-builder-queries-to-human-readable-text-in-servicenow/</guid>
      <description>Transform encoded query conditions from the Condition Builder into readable text using a simple script and REST API call.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Let’s say you need to review or document all the conditions <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> used in UI Policies, SLAs, or other records. You open the table, and there it is: the <code>conditions</code> field—stored as an encoded query like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">active=true^priority=1
</span></span></code></pre></div><p>This format is totally fine for developers or tech-savvy admins. But try sharing it with a stakeholder or process owner, and it might raise more questions than it answers.</p>
<p>Unfortunately, there’s no out-of-the-box way in ServiceNow to turn these encoded queries into something readable. Functions like <code>getDisplayValue()</code> or <code>getValue()</code> aremt&rsquo; helpful: they just return the same encoded string.</p>
<h2 id="solution">Solution</h2>
<p>To make this more <em>human-friendly</em> and readable, you can use the script below. It converts encoded queries into nice sentences like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Active is true AND Priority is High
</span></span></code></pre></div><p>It’s handy when you need to make sense of a bunch of conditions—whether for documentation, audits, or just to talk about them clearly.</p>
<p>It calls a (not officially documented) internal ServiceNow REST API that the UI uses to parse condition queries.</p>
<p>Here’s what happens under the hood:</p>
<ul>
<li>The script builds a URL to call the API: <code>/api/now/ui/query_parse/{table}/map?sysparm_query=...</code></li>
<li>It executes the request using <code>sn_ws.RESTMessageV2</code><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></li>
<li>The response comes back as a JSON object with a ‘predicates’ that represent each part of the condition.</li>
<li>The script then recursively parses these predicates into a readable string</li>
</ul>
<h3 id="authentication-setup">Authentication Setup</h3>
<p>You will need to set up a user with enough rights to access the table you’re querying (e.g. <code>ui_policy</code>, <code>contract_sla</code>, etc.), and then create a basic auth record<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. This credential will be used in the REST call to authenticate the request.</p>
<p>Once that’s done, you can pass the <code>sys_id</code> of the credential in the script below.</p>
<h3 id="example-script">Example Script</h3>
<p>Here is the script. It is meant to be a one-time or punctual task, so it is best run in a background script. Of course, if you need it more often, you can adapt it in a Script Include and/or build a Flow Action that does just that.</p>
<p>To use it, copy-paste all of this in the background script and adapt the call:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">authProfileId</span> <span class="o">=</span> <span class="s2">&#34;xxx&#34;</span><span class="p">;</span> <span class="c1">// your credential sys_id
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">uiPolicyGr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;ui_policy&#39;</span><span class="p">);</span> <span class="c1">// Adapt the table...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">uiPolicyGr</span><span class="p">.</span><span class="nx">addEncodedQuery</span><span class="p">(</span><span class="s1">&#39;nameSTARTSWITHsomething&#39;</span><span class="p">);</span> <span class="c1">//... and the query
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">uiPolicyGr</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="nx">uiPolicyGr</span><span class="p">.</span><span class="nx">next</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">conditionText</span> <span class="o">=</span> <span class="nx">getUserFriendlyCondition</span><span class="p">(</span><span class="nx">uiPolicyGr</span><span class="p">.</span><span class="nx">getTableName</span><span class="p">(),</span> <span class="nx">uiPolicyGr</span><span class="p">.</span><span class="nx">conditions</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="nx">uiPolicyGr</span><span class="p">.</span><span class="nx">getDisplayValue</span><span class="p">()</span><span class="si">}</span><span class="sb">,</span><span class="si">${</span><span class="nx">conditionText</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span> <span class="c1">// For example, output a comma-delimited list so you can copy it into Excel or another tool.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Retrieves a user-friendly representation of a condition from a ServiceNow table.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param {string} table - The name of the table to query.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param {string} condition - The encoded query condition string.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param {string} authProfileId - The authentication profile ID for REST API access. Default is provided if not supplied.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @returns {string} A human-readable representation of the condition.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getUserFriendlyCondition</span><span class="p">(</span><span class="nx">table</span><span class="p">,</span> <span class="nx">condition</span><span class="p">,</span> <span class="nx">authProfileId</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">instance</span> <span class="o">=</span> <span class="nx">gs</span><span class="p">.</span><span class="nx">getProperty</span><span class="p">(</span><span class="s2">&#34;instance_name&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">condition</span> <span class="o">=</span> <span class="nb">encodeURIComponent</span><span class="p">(</span><span class="nx">condition</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">r</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">r</span><span class="p">.</span><span class="nx">setHttpMethod</span><span class="p">(</span><span class="s2">&#34;GET&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">r</span><span class="p">.</span><span class="nx">setEndpoint</span><span class="p">(</span><span class="sb">`https://</span><span class="si">${</span><span class="nx">instance</span><span class="si">}</span><span class="sb">.service-now.com/api/now/ui/query_parse/</span><span class="si">${</span><span class="nx">table</span><span class="si">}</span><span class="sb">/map?sysparm_query=</span><span class="si">${</span><span class="nx">condition</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">authProfileId</span> <span class="o">=</span> <span class="nx">authProfileId</span> <span class="o">||</span> <span class="s2">&#34;xxx&#34;</span><span class="p">;</span> <span class="c1">// Replace with your credential. This will be used if no value is passed to the function.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">r</span><span class="p">.</span><span class="nx">setAuthenticationProfile</span><span class="p">(</span><span class="s2">&#34;basic&#34;</span><span class="p">,</span> <span class="nx">authProfileId</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">httpStatus</span> <span class="o">==</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nx">responseObj</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">responseObj</span><span class="o">?</span><span class="p">.</span><span class="nx">result</span><span class="o">?</span><span class="p">.</span><span class="nx">predicates</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">parsePredicates</span><span class="p">(</span><span class="nx">responseObj</span><span class="p">.</span><span class="nx">result</span><span class="p">.</span><span class="nx">predicates</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">parsePredicates</span><span class="p">(</span><span class="nx">predicates</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">processPredicate</span><span class="p">(</span><span class="nx">predicate</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">predicate</span><span class="p">.</span><span class="nx">column_type</span> <span class="o">===</span> <span class="s1">&#39;element&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">predicate</span><span class="p">.</span><span class="nx">term_label</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">predicate</span><span class="p">.</span><span class="nx">compound_type</span> <span class="o">===</span> <span class="s1">&#39;or&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">predicate</span><span class="p">.</span><span class="nx">subpredicates</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">processPredicate</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; OR &#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">predicate</span><span class="p">.</span><span class="nx">compound_type</span> <span class="o">===</span> <span class="s1">&#39;and&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">predicate</span><span class="p">.</span><span class="nx">subpredicates</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">processPredicate</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; AND &#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">predicates</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">processPredicate</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; AND &#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="multi-language-support">Multi-language Support</h2>
<p>If you need to output the condition in a different language, you can simply set the Preferred language of the user used by the REST call to the desired value. The output will then be in this language.</p>
<h2 id="final-notes">Final Notes</h2>
<blockquote>
<p>This script uses an internal ServiceNow REST API (<code>/api/now/ui/query_parse</code>) that isn’t officially documented (or at least not publicly). It&rsquo;s safe for internal tools and scripting, but use it with care and test thoroughly.</p>
<p>Just keep in mind that because the API is not documented, it might change or break in future versions.</p>
</blockquote>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.servicenow.com/docs/bundle/yokohama-platform-user-interface/page/use/common-ui-elements/concept/c_ConditionBuilder.html">Condition builder</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://developer.servicenow.com/dev.do#!/reference/api/yokohama/server/sn_ws-namespace/c_RESTMessageV2API?navFilter=restm">RESTMessageV2 - Scoped, Global | ServiceNow Developers</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://www.servicenow.com/docs/bundle/yokohama-api-reference/page/integrate/outbound-rest/task/t_CreateABasicAuthProfile.html">Create a basic auth profile</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>Search on screenshot attachments</title>
      <link>https://www.snow-adventures.com/posts/search-on-screenshot-attachments/</link>
      <pubDate>Sun, 20 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/search-on-screenshot-attachments/</guid>
      <description>OCR on picture attachments with Google vision API</description>
      <content:encoded><![CDATA[<h2 id="ocr-on-attachment-with-google-vision-api">OCR on attachment with Google vision API</h2>
<p>This article shows how to use the Google Vision API to extract text from attachments and to make this text searchable in Service-Now.</p>
<p>In this quick demo, we can see that attaching printscreens to an incident will trigger a call to the Google Vision API and extract the text in a field <em>Extracted field</em> on the attachment table and consolidate all the attachment texts in a field <em>Attachment text</em> on the incident.</p>
<figure>
    <img loading="lazy" src="/img/Search_on_screenshot/Attachment%20OCR%20demo.gif"/> <figcaption>
            Adding attachment triggers OCR and extract text
        </figcaption>
</figure>

<p>Then we can search string that are present only on the screenshots, like &ldquo;Wikipedia&rdquo; or &ldquo;Croissant&rdquo; in this case.</p>
<figure>
    <img loading="lazy" src="/img/Search_on_screenshot/Attachment%20OCR%20demo%20search.gif"/> <figcaption>
            Search with text from the screenshots
        </figcaption>
</figure>

<p>Now, let&rsquo;s see how to implement this solution.</p>
<h2 id="setup-the-google-api">Setup the google APi</h2>
<p>First of all, you will need a Google Cloud account.</p>
<p>If you don&rsquo;t already have a Google Cloud account, you can setup your account here: <a href="https://cloud.google.com/">https://cloud.google.com/</a></p>
<p>When done, go in the Google Cloud console and follow the instruction in the starting guide[1] and in the Detect text in images guide[2].</p>
<p>Basically you will need to:</p>
<ul>
<li>create a new Project</li>
<li><a href="https://console.cloud.google.com/flows/enableapi?apiid=vision.googleapis.com">activate the Vision API</a> for your project</li>
<li>Create an API key in the credential
<ul>
<li>Go in the menu, the &ldquo;API &amp; Services&rdquo; - &ldquo;Credentials&rdquo;
<figure>
	    <img loading="lazy" src="/img/Search_on_screenshot/63d7441b41fac25810743cf4c7ba4f73.png"/> <figcaption>
	            Create API credentials
	        </figcaption>
	</figure>
</li>
<li>Then click &ldquo;Create Credential&rdquo; - &ldquo;API key&rdquo;
<figure>
	    <img loading="lazy" src="/img/Search_on_screenshot/5c09b2c362592fd867aaf05805e5af55.png"/> <figcaption>
	            Create API credentials
	        </figcaption>
	</figure>
</li>
<li>Then copy and keep the key for later reference.</li>
</ul>
</li>
</ul>
<p>You should now be ready to use the google API.</p>
<blockquote>
<p>Obviously, for real life usage, you may want to use other authentification methods and/or add some more security. To do so please refer to the Google Cloud documentation or consult a Google Cloud specialist.</p>
</blockquote>
<h2 id="adapt-the-attachment-table">Adapt the attachment table</h2>
<p>The idea is to store the extracted text from the image in a text field on the attachment table.</p>
<p>Before doing so, I suggest to work in an Scoped Application: so please create and use a new Application &ldquo;OCR Attachment&rdquo;.</p>
<p>Then, let&rsquo;s create a new field <code>u_extracted_text</code> on the table <code>sys_attachment</code>, of type String and of a sufficient size of 4000.</p>
<p>Then we need give access at our application &ldquo;OCR Attachment&rdquo;  to the Attachment table:</p>
<ul>
<li>go in &ldquo;System Definition&rdquo; - &ldquo;Tables&rdquo;</li>
<li>select the sys_attachment table</li>
<li>on the &ldquo;Application Access&rdquo; tab set &ldquo;Can Update&rdquo; to true. <figure>
    <img loading="lazy" src="/img/Search_on_screenshot/bd99ff397e2a5e1ed9200b8d8c00e40c.png"/> <figcaption>
            Create API credentials
        </figcaption>
</figure>
</li>
<li>To avoid potential issues later, please also reset the cache by doing a <code>cache.do</code> in the Filter Navigator.</li>
</ul>
<h2 id="create-the-rest-message">Create the REST message</h2>
<p>Now we need to create a REST message and the corresponding HTTP method.</p>
<p>Simply create a new REST message &ldquo;Google Vision API&rdquo; and set the endpoint to</p>
<pre tabindex="0"><code class="language-url" data-lang="url">https://vision.googleapis.com/v1/images:annotate
</code></pre><p>Then open the prefefined HTTP method that is automatically created when saving the REST message and</p>
<ul>
<li>renamne it to &ldquo;POST&rdquo;</li>
<li>Set the HTTP method to &ldquo;POST&rdquo;</li>
<li>Set the endpoint to <code>https://vision.googleapis.com/v1/images:annotate?key=${apikey}</code></li>
<li>On the &ldquo;HTTP request&rdquo; tab, set the Content to
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="s2">&#34;requests&#34;</span><span class="o">:</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">	  <span class="p">{</span>
</span></span><span class="line"><span class="cl">		 <span class="s2">&#34;image&#34;</span><span class="o">:</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;content&#34;</span><span class="o">:</span><span class="s2">&#34;${base64Image}&#34;</span>
</span></span><span class="line"><span class="cl">		 <span class="p">},</span>
</span></span><span class="line"><span class="cl">		 <span class="s2">&#34;features&#34;</span><span class="o">:</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">			<span class="p">{</span>
</span></span><span class="line"><span class="cl">			   <span class="s2">&#34;type&#34;</span><span class="o">:</span><span class="s2">&#34;TEXT_DETECTION&#34;</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		 <span class="p">]</span>
</span></span><span class="line"><span class="cl">	  <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<p>The important points are the variable names <code>apikey</code> and <code>base64Image</code>, that we will use in the Business Rule later.</p>
<h3 id="testing-the-rest-message">Testing the rest message</h3>
<p>To test you REST message and HTTP request, you can add 2 entries in the Variable Substitution related list:</p>
<ul>
<li>apikey: containing the API you created before in the Google Cloud console</li>
<li>base64Image: containing a base64 encoded image that have text in it.
<ul>
<li>You can use this <a href="https://www.base64-image.de/">online base64 converter</a> to convert your image.</li>
</ul>
</li>
</ul>
<p>Then you can use the <em>test</em> related link and you should get a code 200 and a json string with the text extracted from your image.</p>
<h2 id="create-a-business-rule-on-the-attachment-table">Create a Business Rule on the attachment table</h2>
<p>Now that both the table and the REST message are ready, we can create a new Business Rule:</p>
<ul>
<li>Name : &ldquo;Extract text from image&rdquo;</li>
<li>Table: sys_attachment</li>
<li>Advanced: true</li>
<li>When to Run
<ul>
<li>When: async</li>
<li>On insert</li>
<li>Condition: Extracted Text is Empty and File name ends with .jpg, .jpeg or .png (adapt the list to your taste)</li>
</ul>
</li>
</ul>
<p>The in the <em>Advanced</em> tab, you can use and adapt the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="nx">executeRule</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span> <span class="cm">/*null when async*/</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// get base64 string from file 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">base64Str</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideSysAttachment</span><span class="p">().</span><span class="nx">getContentBase64</span><span class="p">(</span><span class="nx">current</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// get API key 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">apiKey</span> <span class="o">=</span> <span class="nx">gs</span><span class="p">.</span><span class="nx">getProperty</span><span class="p">(</span><span class="s1">&#39;x_12270_ocr_attach.googleVision_api_key&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="nx">base64Str</span> <span class="o">&amp;&amp;</span> <span class="nx">apiKey</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// build request
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">request</span><span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="s1">&#39;x_12270_ocr_attach.Google Vision API&#39;</span><span class="p">,</span> <span class="s1">&#39;POST&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="nx">request</span><span class="p">.</span><span class="nx">setStringParameterNoEscape</span><span class="p">(</span><span class="s1">&#39;base64Image&#39;</span><span class="p">,</span> <span class="nx">base64Str</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="nx">request</span><span class="p">.</span><span class="nx">setStringParameterNoEscape</span><span class="p">(</span><span class="s1">&#39;apikey&#39;</span><span class="p">,</span> <span class="nx">apiKey</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// execute request
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// extract response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="kd">var</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// if success
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">if</span> <span class="p">(</span><span class="nx">httpStatus</span> <span class="o">==</span> <span class="s1">&#39;200&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">				<span class="nx">responseObj</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">				<span class="k">if</span> <span class="p">(</span><span class="nx">responseObj</span> <span class="o">&amp;&amp;</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">fullTextAnnotation</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">					<span class="kd">var</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">fullTextAnnotation</span><span class="p">.</span><span class="nx">text</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">					<span class="k">if</span> <span class="p">(</span><span class="nx">text</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">						<span class="nx">current</span><span class="p">.</span><span class="nx">u_extracted_text</span> <span class="o">=</span> <span class="nx">text</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">						<span class="nx">current</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">					<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">exception</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error in Business rule &#39;Extract text from image&#39;: &#34;</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">exception</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span><span class="p">);</span>
</span></span></code></pre></div><p>Then the last step is to create a new system property <code>googleVision_api_key</code> and set there the API key you created from the Google Cloud Console.</p>
<h2 id="searching-tasks-using-attachments-text">Searching tasks using attachment&rsquo;s text</h2>
<p>Now the last part is to be able to search records (like incidents, etc.. ) where the related attachment contains the searched text.</p>
<p>The easiest way for this is to create a new field on the <em>Task</em> table that will contains the extracted text of all the attachments. This way the text contained in this field (the text extracted from the attachments) will be included in the Zing search on tasks.</p>
<p>So, let&rsquo;s create a new field <code>attachment_text</code> on the table <code>task</code>, of type String and of a sufficient size of 4000.</p>
<p>Then we need a new Business Rule on the table <code>sys_attachment</code>:</p>
<ul>
<li>Name : &ldquo;Maintain extracted text on related task&rdquo;</li>
<li>Table: sys_attachment</li>
<li>Advanced: true</li>
<li>When to Run
<ul>
<li>When: after</li>
<li>On insert, update, delete</li>
<li>Condition: Extracted Text changes</li>
</ul>
</li>
<li>Conditions:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideTableHierarchy</span><span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">table_name</span><span class="p">).</span><span class="nx">getRoot</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&#34;task&#34;</span> <span class="cm">/*check that the related table is child of task*/</span>
</span></span></code></pre></div><p>The in the <em>Advanced</em> tab, add the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="nx">executeRule</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span> <span class="cm">/*null when async*/</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">try</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// get the related table
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">taskGr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">table_name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">table_sys_id</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// to hold the attachment texts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">attachmentTextObj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// make sure the attachment text field is valid
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">if</span> <span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">isValidField</span><span class="p">(</span><span class="s1">&#39;x_12270_ocr_attach_attachment_text&#39;</span><span class="p">)){</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// if the attachment text field exist and is not empty, parse it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="k">if</span> <span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">x_12270_ocr_attach_attachment_text</span><span class="p">){</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">					<span class="nx">attachmentTextObj</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">x_12270_ocr_attach_attachment_text</span><span class="p">);</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// if we delete the attachment, remove the corresponding text
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="k">if</span> <span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">operation</span><span class="p">()</span> <span class="o">==</span> <span class="s1">&#39;delete&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">					<span class="k">delete</span> <span class="nx">attachmentTextObj</span><span class="p">[</span><span class="nx">current</span><span class="p">.</span><span class="nx">getUniqueValue</span><span class="p">()];</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span> <span class="k">else</span> <span class="cm">/*otherwise, set the text*/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">					<span class="nx">attachmentTextObj</span><span class="p">[</span><span class="nx">current</span><span class="p">.</span><span class="nx">getUniqueValue</span><span class="p">()]</span> <span class="o">=</span> <span class="nx">current</span><span class="p">.</span><span class="nx">u_extracted_text</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// Set back the attachment text to string and update
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="nx">taskGr</span><span class="p">.</span><span class="nx">x_12270_ocr_attach_attachment_text</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">attachmentTextObj</span><span class="p">);</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">				<span class="nx">taskGr</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">exception</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error in Business rule &#39;Maintain extracted text on related task&#39;: &#34;</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">exception</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="testing">Testing</h3>
<p>You can now take a print screen with text in it and attach it to a record like an <em>Incident</em>:</p>
<ul>
<li>The <code>sys_attachment</code> record now have the text extracted in to the <code>Extracted text</code>field.</li>
<li>The <code>incident record</code> record now have also the text in the  <code>attachment_text</code> field.</li>
</ul>
<p>You can now search for a String that is present on the screenshot and you incident should show up in the search result</p>
<h2 id="references">References</h2>
<ol>
<li>Cloud Vision API - Documentation - Quickstart: Setup the Vision API <a href="https://cloud.google.com/vision/docs/setup">https://cloud.google.com/vision/docs/setup</a></li>
<li>Cloud Vision API - Documentation - Detect text in images <a href="https://cloud.google.com/vision/docs/ocr">https://cloud.google.com/vision/docs/ocr</a></li>
</ol>]]></content:encoded>
    </item>
    
  </channel>
</rss>
