<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ToolJet</title>
    <description>The latest articles on DEV Community by ToolJet (@tooljet).</description>
    <link>https://dev.to/tooljet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5047%2F8494f13c-ffc6-4700-9c7d-f95b8280d9bd.png</url>
      <title>DEV Community: ToolJet</title>
      <link>https://dev.to/tooljet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tooljet"/>
    <language>en</language>
    <item>
      <title>Build An Audio Transcriber and Analyzer using ToolJet and OpenAI🎙️</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 29 Aug 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/tooljet/build-an-audio-transcriber-and-analyzer-using-tooljet-and-openai-1109</link>
      <guid>https://dev.to/tooljet/build-an-audio-transcriber-and-analyzer-using-tooljet-and-openai-1109</guid>
      <description>&lt;p&gt;In this hands-on tutorial, we’ll learn how to build a powerful audio transcriber and analyzer using ToolJet and Open AI. We'll quickly design an intuitive UI using ToolJet's pre-built &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components/" rel="noopener noreferrer"&gt;components&lt;/a&gt;, and then use the platform's &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;query builder&lt;/a&gt; to interact with Open AI for audio transcription and analysis.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, we'll have a fundamental structure to build more sophisticated transcription and audio analysis applications.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ToolJet&lt;/strong&gt; (&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code platform designed for quickly building and deploying internal tools. Sign up for a free ToolJet cloud account &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open AI Account&lt;/strong&gt; : Register for an Open AI account to utilize AI-powered features in your ToolJet applications. Sign up &lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Here's a quick preview of what we are going to build:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvahkytka6o04f3d76g7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvahkytka6o04f3d76g7.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before you begin, go to the &lt;a href="https://platform.openai.com/api-keys" rel="noopener noreferrer"&gt;Open AI Console&lt;/a&gt;, and copy your secret key. Next, login to your &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;ToolJet account&lt;/a&gt;, locate the &lt;strong&gt;Data Sources&lt;/strong&gt; section on the left sidebar, and configure Open AI as a data source using the secret key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu5xh4zzjm076lsonfdn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu5xh4zzjm076lsonfdn.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the data source is configured, create a new app called "Speech Insight" from the dashboard. And with that, we are ready to start building our application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Building the UI for the Audio Transcriber
&lt;/h2&gt;

&lt;p&gt;Let's use ToolJet's visual app builder to design our UI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the app header, drag and drop an &lt;strong&gt;Icon&lt;/strong&gt; component on the canvas. Navigate to its properties panel on the right, and select the &lt;code&gt;IconBrandDingtalk&lt;/code&gt; icon.&lt;/li&gt;
&lt;li&gt;Drop a &lt;strong&gt;Text&lt;/strong&gt; component next to it, and enter "Speech Insight" under its Data property.&lt;/li&gt;
&lt;li&gt;Change the color of both components to blue (&lt;code&gt;#3E63DD&lt;/code&gt;). This will be the primary color scheme of our app, update the color scheme of the remaining components accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftft7as3w2n2hydid22ll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftft7as3w2n2hydid22ll.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Place a &lt;strong&gt;Container&lt;/strong&gt; component below the header. We will organize the upcoming components inside the Container component.&lt;/li&gt;
&lt;li&gt;Rename it to &lt;code&gt;mainContainer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxfzmcowcuthl26rgz0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxfzmcowcuthl26rgz0w.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the top left of the Container component, place a &lt;strong&gt;Text&lt;/strong&gt; component with the label "Output".&lt;/li&gt;
&lt;li&gt;Below it, add another &lt;strong&gt;Container&lt;/strong&gt; and place two &lt;strong&gt;Text&lt;/strong&gt; components inside it. We will use these components to display the transcribed text and feedback. Name them &lt;code&gt;transcribedText&lt;/code&gt; and &lt;code&gt;feedback&lt;/code&gt; respectively.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;File Picker&lt;/strong&gt; component below it and rename it to &lt;code&gt;uploader&lt;/code&gt;. Change its &lt;code&gt;Accept file types&lt;/code&gt; property to &lt;code&gt;"audio/*"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Place a &lt;strong&gt;Button&lt;/strong&gt; component below it and rename it to &lt;code&gt;analyzeButton&lt;/code&gt; and add an "Analyze Button" label to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hn33z3rpcx6v5omuchx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hn33z3rpcx6v5omuchx.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; We are renaming key components to make them easier to reference in other parts of our application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, place four &lt;strong&gt;Statistics&lt;/strong&gt; components on the right for Fluency, Pronunciation, Intonation, and Vocabulary scores.&lt;/li&gt;
&lt;li&gt;Drop a &lt;strong&gt;Button&lt;/strong&gt; component below it labeled "Copy Output" and rename it to &lt;code&gt;copyButton&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbl7w02dtioa3ibwqga8t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbl7w02dtioa3ibwqga8t.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The UI is now ready! Time to configure the interactions with Open AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Interact With Open AI
&lt;/h2&gt;

&lt;p&gt;In the below steps, we will go through the configuration to interact with Open AI using both REST API and ToolJet's native integration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expand the query panel at the bottom and click on the &lt;strong&gt;Add&lt;/strong&gt; button to create a new REST API query. Rename the query to &lt;code&gt;transcribe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter the Open AI URL under the &lt;code&gt;URL&lt;/code&gt; property: &lt;code&gt;https://api.openai.com/v1/audio/transcriptions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a new row under &lt;strong&gt;Header&lt;/strong&gt;, enter &lt;code&gt;Content-Type&lt;/code&gt; as the key and &lt;code&gt;multipart/form-data&lt;/code&gt; as the value.&lt;/li&gt;
&lt;li&gt;Add another key for &lt;code&gt;Authorization&lt;/code&gt;. Enter &lt;code&gt;Bearer &amp;lt;OPEN_AI_KEY&amp;gt;&lt;/code&gt; in the value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1wpbxyluwy29otqhipr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1wpbxyluwy29otqhipr.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under &lt;strong&gt;Body&lt;/strong&gt;, add &lt;code&gt;file&lt;/code&gt; as the key and value as &lt;code&gt;{{ components.uploader.file[0] }}&lt;/code&gt;. This will ensure the audio file selected in our uploader/File Picker component is sent.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;model&lt;/code&gt; as the key and enter &lt;code&gt;whisper-1&lt;/code&gt; as the value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4pgec9dp0htbqp0jfbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4pgec9dp0htbqp0jfbw.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if we select an audio file in the uploader/File Picker component and click on the &lt;strong&gt;Run&lt;/strong&gt; button, we will see the transcribed audio as the output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwgdw0sq52bsbixc1wfs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwgdw0sq52bsbixc1wfs.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the audio is transcribed, we need to analyze it to provide a score. Let's use the native Open AI integration for this query.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;strong&gt;Add&lt;/strong&gt; button and add a new query. Select &lt;strong&gt;Open AI&lt;/strong&gt; as the data source for this query. This is the same data source that we had set up at the beginning. Rename it to &lt;code&gt;analyze&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Chat&lt;/strong&gt; as the operation and &lt;strong&gt;Message&lt;/strong&gt; as input, and enter the below prompt:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Based&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;transcribed&lt;/span&gt; &lt;span class="nx"&gt;audio&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;provide&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; 
&lt;span class="nx"&gt;JSON&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

   &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nc"&gt;Fluency &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nc"&gt;Pronunciation &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nc"&gt;Vocabulary &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nc"&gt;Intonation &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;paragraph&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;gives&lt;/span&gt; &lt;span class="nx"&gt;general&lt;/span&gt; &lt;span class="nx"&gt;feedback&lt;/span&gt; 
&lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;transcribed&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s quality and overall improvement suggestions.

   Return the object in the following format:

   {fluency: "...", pronunciation: "...", 
vocabulary: "...", intonation: "...", feedback: "..."}

   Transcribed text:
   {{queries.transcribe.data.text}}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2qacepaqbz6z5jozaaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2qacepaqbz6z5jozaaj.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this prompt, we are using Open AI to perform a detailed analysis of the audio transcription. We are referencing the data returned by the &lt;code&gt;transcribe&lt;/code&gt; query in the prompt along with other scoring criteria. &lt;/p&gt;

&lt;p&gt;Running this query will result in the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfkw4y3qw3gmgrvmh6y1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfkw4y3qw3gmgrvmh6y1.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both the queries are ready. As a final step, let's automate the process of triggering the &lt;code&gt;analyze&lt;/code&gt; query every time the &lt;code&gt;transcribe&lt;/code&gt; query is successfully executed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go back to the &lt;code&gt;transcribe&lt;/code&gt; query, navigate to &lt;strong&gt;Events&lt;/strong&gt; and add a new &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-events/" rel="noopener noreferrer"&gt;event&lt;/a&gt; handler.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Query Success&lt;/strong&gt; as the Event, &lt;strong&gt;Run Query&lt;/strong&gt; as the Action, and &lt;code&gt;analyze&lt;/code&gt; as the Query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcbwgj5whjp2u3lzkeso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcbwgj5whjp2u3lzkeso.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using events, we have set up the process of triggering the &lt;code&gt;analyze&lt;/code&gt; query after the &lt;code&gt;transcribe&lt;/code&gt; query is triggered and is ready with the output for analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Binding the Transcripts and Analysis to Components
&lt;/h2&gt;

&lt;p&gt;Onto the final step. We have built our UI and also built queries to interact with Open AI. Now we can connect it all together and see the app in action.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;strong&gt;Analyze Audio&lt;/strong&gt; button, navigate to its properties panel on the right and add a new event.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;On click&lt;/strong&gt; as the Event, &lt;strong&gt;Run Query&lt;/strong&gt; as the Action, and &lt;code&gt;transcribe&lt;/code&gt; as the Query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now every time the Analyze Audio button is clicked, it will trigger the &lt;code&gt;transcribe&lt;/code&gt; query.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;strong&gt;Copy Output&lt;/strong&gt; button and add a new event to it.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;On click&lt;/strong&gt; as the Event, &lt;strong&gt;Copy to clipboard&lt;/strong&gt; as the Action, and &lt;code&gt;{{queries.analyze.data}}&lt;/code&gt; as the Text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration will ensure that the analyzed output gets copied when you click on the Copy Output button.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Text&lt;/strong&gt; component that we had placed to display the transcript. Enter the following value under its Data property:&lt;br&gt;
&lt;strong&gt;Transcript:&lt;/strong&gt; &lt;code&gt;{{queries.transcribe.data.text}}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Text&lt;/strong&gt; component to display the feedback. Enter the following value under its Data property:&lt;br&gt;
&lt;strong&gt;Feedback:&lt;/strong&gt; &lt;code&gt;{{JSON.parse(queries.analyze.data).feedback}}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; We received a JSON string in response to our &lt;code&gt;analyze&lt;/code&gt; query. Therefore, we need to parse it to construct a JavaScript object before displaying it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Statistics&lt;/strong&gt; component for "Fluency" and enter the below value under its &lt;code&gt;Primary value&lt;/code&gt; property:&lt;br&gt;
&lt;code&gt;{{JSON.parse(queries.analyze.data).fluency}}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update the rest of the Statistics components using the same logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our audio transcriber and analyzer is now fully complete. Upload an audio file and click on the Analyze Audio button to see the transcription, feedback, and scores getting populated in the UI. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4qq0bzys8izun9tvfng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4qq0bzys8izun9tvfng.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we learned how to create a complete audio transcription and analysis tool using ToolJet and OpenAI. We walked through designing an intuitive user interface, setting up API queries to interact with OpenAI, and binding the results to display transcriptions, feedback, and speech analysis scores.&lt;/p&gt;

&lt;p&gt;To further customize the application, experiment with different UI components to enhance the user experience or integrate additional APIs to analyze other aspects of the audio, such as emotion detection or language translation.&lt;/p&gt;

&lt;p&gt;To learn more, check out ToolJet's official &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; or connect on &lt;a href="https://tooljet.slack.com" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; for questions or queries.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Build an Advanced Web Scraping Tool Using ToolJet and Scraper API! 🚀 🛠️</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 15 Aug 2024 12:35:05 +0000</pubDate>
      <link>https://dev.to/tooljet/build-an-advanced-web-scraping-tool-using-tooljet-and-scraper-api-fp7</link>
      <guid>https://dev.to/tooljet/build-an-advanced-web-scraping-tool-using-tooljet-and-scraper-api-fp7</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Scraping data can be tedious, especially when dealing with dynamic content. However, it becomes a lot more convenient if you can instantly preview the data scraped in the UI. ToolJet, combined with &lt;a href="https://www.scraperapi.com/" rel="noopener noreferrer"&gt;Scraper API&lt;/a&gt;, enables exactly that. This tutorial shows how to set up a script to scrape data using ToolJet and display the results in real time.&lt;/p&gt;

&lt;p&gt;If you've worked with web scraping using &lt;a href="https://colab.research.google.com/" rel="noopener noreferrer"&gt;Google Colab&lt;/a&gt; or tools like &lt;a href="https://www.selenium.dev/" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt;, you know the challenges. Here, we'll take a different approach using JavaScript web scraping, utilizing ToolJet’s visual app builder to manage the data flow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ToolJet&lt;/strong&gt; (&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code platform designed for quickly building and deploying internal tools. Sign up for a free ToolJet cloud account &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Basic knowledge of &lt;strong&gt;JavaScript&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Begin by creating an application named &lt;strong&gt;TJ Web Scraper&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Designing the UI to Display the Scraped Data
&lt;/h2&gt;

&lt;p&gt;Let's use ToolJet's &lt;a href="https://docs.tooljet.com/docs/#visual-app-builder" rel="noopener noreferrer"&gt;visual app builder&lt;/a&gt; to quickly design the UI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a &lt;strong&gt;Container&lt;/strong&gt; &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;component&lt;/a&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Inside the container, place an &lt;strong&gt;Icon&lt;/strong&gt; component on the left for the logo.&lt;/li&gt;
&lt;li&gt;Place a &lt;strong&gt;Text&lt;/strong&gt; component next to it and enter "TJ Web Scraper" under its Data property.&lt;/li&gt;
&lt;li&gt;Place another &lt;strong&gt;Text&lt;/strong&gt; component on the right to display the total count of scraped products.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0x4w850i94wfxdb2owt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0x4w850i94wfxdb2owt.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We are using blue (hex code: &lt;code&gt;#075ab9&lt;/code&gt;) as the primary color for this application; change the color scheme of all the components accordingly.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;strong&gt;Table&lt;/strong&gt; component below the header and a &lt;strong&gt;Button&lt;/strong&gt; component on the bottom-right of the canvas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp163czpzroo6q8f7iqh3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp163czpzroo6q8f7iqh3.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that, our UI is ready in just a couple of minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Writing the JavaScript Code to Scrape Data
&lt;/h2&gt;

&lt;p&gt;In this step, we will utilize the Scraper API to scrape the data from a sample eCommerce website. Here's a preview of the website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcm9hgeo0ylg94vli8nze.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcm9hgeo0ylg94vli8nze.png" alt=" " width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The website has a few products with their images, titles, and prices. Additionally, it has a load more button to dynamically load more content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To start, expand the &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;Query Panel&lt;/a&gt; at the bottom, and click on the &lt;strong&gt;Add&lt;/strong&gt; button to create a new Run JavaScript code query. Rename the query to &lt;strong&gt;scrapeData&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set up the main scraping function&lt;/strong&gt;: Create the &lt;code&gt;runMainScript()&lt;/code&gt; function that will coordinate all the logic needed for scraping products.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runMainScript&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SCRAPER_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

    &lt;span class="c1"&gt;// Main logic goes here&lt;/span&gt;
    &lt;span class="c1"&gt;// .....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create a request helper&lt;/strong&gt;: Build a helper function &lt;code&gt;makeRequest()&lt;/code&gt; using axios to handle API requests, manage responses, and deal with errors efficiently.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.scraperapi.com/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;404NotFound&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error making request to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extract product details&lt;/strong&gt;: Define the &lt;code&gt;parseProducts()&lt;/code&gt; function to gather relevant information (like title, price, and image) from the HTML content, filtering out incomplete data. This function uses the HTML selectors tailored to the target website.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DOMParser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.product-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.product-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.product-price&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Handle dynamic loading&lt;/strong&gt;: The fetchProducts() function manages the initial page load and any additional AJAX requests, collecting all available products. It saves the total count in a ToolJet &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/variables/#variables-and-page-variables" rel="noopener noreferrer"&gt;variable&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ajaxUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialPageHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;initialPageHtml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parseProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialPageHtml&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ajaxHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ajaxUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?offset=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ajaxHtml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ajaxHtml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newProducts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newProducts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Scraped &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; products so far...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Save the length of the total products fetched in a ToolJet variable&lt;/span&gt;
        &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;totalProductsScraped&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Launch the scraping process&lt;/strong&gt;: Implement the &lt;code&gt;scrapeProducts()&lt;/code&gt; function to trigger the scraping and output the final count of products collected.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;scrapeProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.scrapingcourse.com/button-click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ajaxUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.scrapingcourse.com/ajax/products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ajaxUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\nTotal products scraped: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run the script and handle results&lt;/strong&gt;: Execute the scraping process, save the data, and log a sample of the products for review and handles potential errors by setting an error variable.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;scrapeProducts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Save all the products fetched from the eCommerce website&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scrapedProducts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Scraped products stored in 'scrapedProducts' variable.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Total products: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Sample of scraped products:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Title: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Price: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Image: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`URL: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;---&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scrapingError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An error occurred:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time to see the code in action&lt;/strong&gt; : Invoke the &lt;code&gt;runMainScript()&lt;/code&gt; function to start the entire process.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runMainScript&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Main logic&lt;/span&gt;
    &lt;span class="c1"&gt;// .....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;runMainScript&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The code to scrape the data is ready. The above code for web scraping will have to be adjusted based on each target website.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Run&lt;/strong&gt; button on the Query Panel and check all the logs that will appear in the browser console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxty9ufcbhgtpxadvpc3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxty9ufcbhgtpxadvpc3z.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 3: Displaying the Scraped Data
&lt;/h1&gt;

&lt;p&gt;With the UI and code set up, we can now focus on displaying the data on the Table component and triggering the code based on Button click.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;strong&gt;Button&lt;/strong&gt; component, navigate to its properties and create a new &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-events" rel="noopener noreferrer"&gt;event&lt;/a&gt; handler.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;On click&lt;/strong&gt; as the event, &lt;strong&gt;Run Query&lt;/strong&gt; as the action, and &lt;strong&gt;scrapeData&lt;/strong&gt; as the query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr5m2csnvbphdbmn3wzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr5m2csnvbphdbmn3wzt.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;strong&gt;Table&lt;/strong&gt; component, and under its Data property, enter &lt;code&gt;{{variables.scrapedProducts}}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Text&lt;/strong&gt; component in the header that is created to display the total count of the products that are scraped. Enter the &lt;code&gt;{{"Total Products Scraped: " + variables.totalProductsScraped || 0 }}&lt;/code&gt; code under its Data property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've successfully linked the components with the query. Now, just click the Button component and watch as the data is scraped and displayed in the Table component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf64qvo6tzumizp1qcfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf64qvo6tzumizp1qcfc.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Scraping data effectively requires overcoming challenges like dynamic content and pagination, especially when dealing with AJAX-loaded pages. Using ToolJet combined with Scraper API, you can simplify this process and gain the ability to instantly preview and manage your scraped data through a clean UI.&lt;/p&gt;

&lt;p&gt;Unlike traditional approaches like Selenium web scraping or using Google Colab, this method integrates JavaScript web scraping seamlessly into your workflow with real-time visibility of your data. Building on this foundation, you can scale the tool to handle more complex scraping needs while maintaining an intuitive interface.&lt;/p&gt;

&lt;p&gt;To learn more, check out &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet's official documentation&lt;/a&gt; or connect on &lt;a href="https://tooljet.slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; with any questions.💡&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webscraping</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Build a Grammarly Alternative Using ToolJet and OpenAI in 10 Minutes📝</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Wed, 07 Aug 2024 13:42:21 +0000</pubDate>
      <link>https://dev.to/tooljet/build-a-grammarly-alternative-using-tooljet-and-openai-in-10-minutes-ai9</link>
      <guid>https://dev.to/tooljet/build-a-grammarly-alternative-using-tooljet-and-openai-in-10-minutes-ai9</guid>
      <description>&lt;p&gt;This tutorial will walk you through the process of creating a Grammarly alternative using ToolJet and OpenAI. We will use ToolJet's visual app builder to design an elegant user interface for our application. Then we will use the platform's low-code query builder to connect with OpenAI to perform detailed text analysis. The completed application will allow you to perform four operations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List all grammatical errors in your text&lt;/li&gt;
&lt;li&gt;Fix all grammatical errors and return the revised text&lt;/li&gt;
&lt;li&gt;Provide a score for the text based on specific parameters: clarity, coherence, grammar, and engagement&lt;/li&gt;
&lt;li&gt;Make the content sound more natural (ideal for transforming generic AI-generated content with a more organic tone)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Feel free to adjust the structure and functionality of the application to match your exact content-enhancement needs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check out &lt;a href="https://dev.to/tooljet/creating-a-csv-to-graph-generator-app-using-tooljet-and-python-libraries-18nb"&gt;this tutorial&lt;/a&gt; to learn how to build a QR Code generator using ToolJet and Python.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a final preview of the application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7bujbzi20werwcrfnug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7bujbzi20werwcrfnug.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;ToolJet&lt;/strong&gt; (&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code platform designed for quickly building and deploying internal tools. Sign up for a free ToolJet cloud account &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI Account&lt;/strong&gt; : Register for an OpenAI account to utilize AI-powered features in your applications by accessing APIs such as GPT for advanced natural language processing. Sign up &lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since integration in ToolJet is &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-datasources#adding-a-data-source" rel="noopener noreferrer"&gt;very straightforward&lt;/a&gt;, you can use any other service instead of OpenAI to build the same application.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 1. Set up Your First ToolJet Data Source
&lt;/h2&gt;

&lt;p&gt;In the steps below, we will set up the data source and create a new app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access the &lt;a href="https://platform.openai.com/api-keys" rel="noopener noreferrer"&gt;OpenAI Console&lt;/a&gt; and generate a new secret key. Remember to copy this key for later use.&lt;/li&gt;
&lt;li&gt;Sign up for a free &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;ToolJet cloud account&lt;/a&gt; if you haven't already and log in.&lt;/li&gt;
&lt;li&gt;On the ToolJet dashboard, locate the Data Sources section on the left sidebar. Here, click on the &lt;strong&gt;Add&lt;/strong&gt; button under the OpenAI plugin.&lt;/li&gt;
&lt;li&gt;In the API Key field, paste the API key you copied from OpenAI Console and click on the Save button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcdlsy7ew3wlkey546s3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcdlsy7ew3wlkey546s3.png" alt=" " width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;strong&gt;Test Connection&lt;/strong&gt; button to ensure the OpenAI plugin is correctly connected to your ToolJet account.&lt;/li&gt;
&lt;li&gt;Finally, click on the "Apps" icon in the left sidebar to navigate to the applications section. &lt;/li&gt;
&lt;li&gt;Select "Create new app" and name your application "Wordly" (or anything else based on your use case), and click on "Create app" to finalize the app creation.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Step 2. Building the User Interface
&lt;/h2&gt;

&lt;p&gt;We will start by creating a minimal UI for the application. The UI will take around five minutes to build. First, we will build the header section, then the input section, and finally, the output section, where we will display the results of the text analysis.&lt;/p&gt;
&lt;h3&gt;
  
  
  Header
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For the Header, drop an &lt;strong&gt;Icon&lt;/strong&gt; &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;component&lt;/a&gt; on the empty canvas and place a &lt;strong&gt;Text&lt;/strong&gt; component next to it. Set its Icon property to "IconTextWrap" and change its font size to 28.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi49tirxxj0hv4b8nce3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi49tirxxj0hv4b8nce3s.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We are using light blue ("#d9e2fc") as the primary color in this application. Update the color scheme of all the components accordingly.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Input Section
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a &lt;strong&gt;Container&lt;/strong&gt; component below the header and rename it to &lt;em&gt;mainContainer&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza7li6ydzbo72d1s8426.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza7li6ydzbo72d1s8426.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We will rename important components like containers and input fields to ensure that we can easily refer and access component-related data inside the app builder.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;strong&gt;Text&lt;/strong&gt; component at the top left of the container with the label 'Enter Text'. &lt;/li&gt;
&lt;li&gt;Place a &lt;strong&gt;Dropdown&lt;/strong&gt; component next to it with the label 'Operation'. Rename it to &lt;em&gt;operationDropdown&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;Set the dropdown's Option labels to: &lt;code&gt;{{['List Grammatical Errors', 'Fix Grammatical Errors', 'Humanize Content', 'Provide Content Score']}}&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Set the Option values to: &lt;code&gt;{{['listGrammaticalErrors', 'fixGrammaticalErrors', 'humanizeContent', 'provideAScore']}}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Textarea&lt;/strong&gt; component below and rename it to &lt;em&gt;textInput&lt;/em&gt;.  - Add a &lt;strong&gt;Button&lt;/strong&gt; component labeled 'GENERATE OUTPUT ⚡' and rename it to &lt;em&gt;generateButton&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;Add another &lt;strong&gt;Button&lt;/strong&gt; component next to it labeled 'COPY 🗒️' and rename it to &lt;em&gt;copyButton&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh991ltcpbllhbe5qd6pl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh991ltcpbllhbe5qd6pl.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Output Section
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;strong&gt;Text&lt;/strong&gt; component labeled 'Output'. &lt;/li&gt;
&lt;li&gt;Place another &lt;strong&gt;Text&lt;/strong&gt; component below it to display the output. This component will display the data returned by the OpenAI queries.&lt;/li&gt;
&lt;li&gt;Rename the &lt;strong&gt;Text&lt;/strong&gt; component to &lt;em&gt;output&lt;/em&gt;, and under its Data property, set Markdown as the type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok06gbzjw19btyh44r0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok06gbzjw19btyh44r0i.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 3. Creating Queries to Interact With OpenAI
&lt;/h2&gt;

&lt;p&gt;Next, we’ll create four OpenAI &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;queries&lt;/a&gt; and a JavaScript query that will conditionally trigger one of the OpenAI queries based on the selected operation.&lt;/p&gt;
&lt;h3&gt;
  
  
  List Grammatical Errors:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Expand the Query Panel at the bottom of the screen and click on the &lt;strong&gt;Add&lt;/strong&gt; button to create a new query &lt;/li&gt;
&lt;li&gt;Rename this query to &lt;em&gt;listGrammaticalErrors&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;Select OpenAI as the Data Source and select Chat as the Operation. In the Message input field, enter the following prompt:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Find&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;grammatical&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;given&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Include&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Use&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;bold&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;appropriate&lt;/span&gt; &lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;mention&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Sentence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Provide&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;sentence&lt;/span&gt; &lt;span class="nx"&gt;which&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Provide&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;brief&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;two&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="nx"&gt;breaks&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Use&lt;/span&gt; &lt;span class="nx"&gt;these&lt;/span&gt; &lt;span class="nx"&gt;emojis&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;different&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Verb&lt;/span&gt; &lt;span class="nx"&gt;Agreement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;🧑‍🏫&lt;/span&gt;
&lt;span class="nx"&gt;Verb&lt;/span&gt; &lt;span class="nx"&gt;Tense&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;⏳&lt;/span&gt;
&lt;span class="nx"&gt;Punctuation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;📝&lt;/span&gt;
&lt;span class="nx"&gt;Spelling&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;🔠&lt;/span&gt;
&lt;span class="nx"&gt;Sentence&lt;/span&gt; &lt;span class="nx"&gt;Structure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;🏗️&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="nx"&gt;please&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt; &lt;span class="nx"&gt;more&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;related&lt;/span&gt; &lt;span class="nx"&gt;emojis&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;needed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;Ensure&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="nx"&gt;clearly&lt;/span&gt; &lt;span class="nx"&gt;identifies&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;provides&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc1v1shypccxjwx7krdu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc1v1shypccxjwx7krdu.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Create Three More OpenAI Queries:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create three more OpenAI queries - &lt;em&gt;fixGrammaticalErrors&lt;/em&gt;, &lt;em&gt;humanizeContent&lt;/em&gt;, and &lt;em&gt;provideAScore&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Prompt for &lt;em&gt;fixGrammaticalErrors&lt;/em&gt; query:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Review&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;identify&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;grammatical&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;provide&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;corrected&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 

&lt;span class="nx"&gt;Provide&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Markdown&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Prompt for &lt;em&gt;humanizeContent&lt;/em&gt; query:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Rewrite&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="nx"&gt;sound&lt;/span&gt; &lt;span class="nx"&gt;more&lt;/span&gt; &lt;span class="nx"&gt;natural&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;human&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;written&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 

&lt;span class="nx"&gt;Ensure&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;revised&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;engaging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;maintains&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="nx"&gt;meaning&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 
&lt;span class="nx"&gt;Provide&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Markdown&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Prompt for &lt;em&gt;provideAScore&lt;/em&gt; query:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Analyze&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;provide&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; 
&lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
&lt;span class="nx"&gt;clarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coherence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grammar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;engagement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;overall&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 

&lt;span class="nx"&gt;Present&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Markdown&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;structure&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;Overall&lt;/span&gt; &lt;span class="nx"&gt;Quality&lt;/span&gt;&lt;span class="err"&gt;🌟&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;Show&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="nx"&gt;four&lt;/span&gt; &lt;span class="nx"&gt;paremeters&lt;/span&gt; &lt;span class="nx"&gt;inside&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt;
&lt;span class="nx"&gt;Clarity&lt;/span&gt;&lt;span class="err"&gt;💡&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;Coherence&lt;/span&gt;&lt;span class="err"&gt;🔗&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;Grammar&lt;/span&gt;&lt;span class="err"&gt;✅&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;Engagement&lt;/span&gt;&lt;span class="err"&gt;🔥&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;insert&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;-------------------------------------------------------------------&lt;/span&gt;

&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;Comments&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;comments&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 

&lt;span class="nx"&gt;Ensure&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; 

&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Create a Query to Conditionally Trigger the OpenAI Queries
&lt;/h3&gt;

&lt;p&gt;Create a JavaScript query named &lt;em&gt;triggerQuery&lt;/em&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;operationDropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listGrammaticalErrors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listGrammaticalErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fixGrammaticalErrors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fixGrammaticalErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;humanizeContent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;humanizeContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;provideAScore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provideAScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpp908mipqcljdhytew93.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpp908mipqcljdhytew93.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This JavaScript query will check the selected operation from the operationDropdown component and run the relevant OpenAI query.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4. Configuring Events and Other Functionalities
&lt;/h2&gt;

&lt;p&gt;In the final step, we will configure the events and bind queries with components and see how it all comes together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update the Output on Query Success:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a new Query Success &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;event handler&lt;/a&gt; to the &lt;em&gt;listGrammaticalErrors&lt;/em&gt; query and select Action as Control Component. &lt;/li&gt;
&lt;li&gt;Under Action Options, set the Component as &lt;em&gt;output&lt;/em&gt;, Action as Set text, and Text as &lt;code&gt;{{queries.listGrammaticalErrors.data}}&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Follow the same steps for the remaining three OpenAI queries; this will populate the &lt;code&gt;output&lt;/code&gt; component with the returned data from the query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmcvq6ipxi2t1ymqiytne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmcvq6ipxi2t1ymqiytne.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Button:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Select the Generate Output button, navigate to its properties panel on the right and create a new event under Events. &lt;/li&gt;
&lt;li&gt;For the event configuration, select Action as Control Component. - Under Action Options, set the Component as &lt;em&gt;output&lt;/em&gt;, Action as Clear. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2kt6xgma7o61kiuiqj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2kt6xgma7o61kiuiqj2.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This event will clear the output component every time the button is clicked.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add another event to the Generate Output button to run the JavaScript query when it is clicked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhdl871na53eg5pyq2xa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhdl871na53eg5pyq2xa.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This event will trigger the JavaScript query. The JavaScript query will then trigger one of the OpenAI queries based on the selected operation from the dropdown, and the output component will be populated with the latest data.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy Button
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a new event for the Copy button, select &lt;code&gt;Copy to clipboard&lt;/code&gt; as the event, and enter &lt;code&gt;{{components.output.text}}&lt;/code&gt; under its Text property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6asx7pjeey5qcu7esi9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6asx7pjeey5qcu7esi9z.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With this setting, every time you click on the Copy button, the text inside the output component will be copied to the clipboard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The functionality of our application is now fully configured. Enter some text in the input field, click on the Generate Output button and test the output for the available operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh51801z0k2c5we3e16k4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh51801z0k2c5we3e16k4.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've built a Grammarly alternative in less than 10 minutes. Using ToolJet's Continue adjusting the application's functionality to meet your specific text analysis needs. You can create new OpenAI queries for a variety of content enhancement scenarios such as changing the tone of the content, improving SEO, changing the language of the output content, improving clarity, etc.&lt;/p&gt;

&lt;p&gt;To learn more, check out the &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet documentation&lt;/a&gt; or connect with us on &lt;a href="https://tooljet.slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>openai</category>
    </item>
    <item>
      <title>Creating a CSV to Graph Generator App Using ToolJet and Python Libraries 🚀</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 25 Jul 2024 12:53:21 +0000</pubDate>
      <link>https://dev.to/tooljet/creating-a-csv-to-graph-generator-app-using-tooljet-and-python-libraries-18nb</link>
      <guid>https://dev.to/tooljet/creating-a-csv-to-graph-generator-app-using-tooljet-and-python-libraries-18nb</guid>
      <description>&lt;p&gt;In this tutorial, we'll create a CSV to Graph Generator app using ToolJet and Python code. This app enables users to upload a CSV file and generate various types of graphs, including line, scatter, bar, histogram, and box plots. Since ToolJet supports Python (and JavaScript) code out of the box, we'll incorporate Python code and the &lt;a href="https://matplotlib.org/" rel="noopener noreferrer"&gt;matplotlib&lt;/a&gt; library to handle the graph generation. Additionally, we'll use ToolJet's customizable pre-built components to design an intuitive user interface in minutes.&lt;/p&gt;

&lt;p&gt;Here's a quick preview of the complete application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmwtomyqbpcg31pyg53y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmwtomyqbpcg31pyg53y.png" alt=" " width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check out &lt;a href="https://blog.tooljet.com/create-a-qr-code-generator-using-tooljet-in-5-minutes/" rel="noopener noreferrer"&gt;this&lt;/a&gt; tutorial to learn how to develop a QR code generator using ToolJet.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ToolJet&lt;/strong&gt;(&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic knowledge of &lt;strong&gt;Python&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Begin by creating an application named &lt;strong&gt;CSV To Graph Generator&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Designing the User Interface
&lt;/h2&gt;

&lt;p&gt;Let's use ToolJet's &lt;a href="https://blog.tooljet.com/build-graphs-using-csv-files-with-tooljet-and-python-libraries/" rel="noopener noreferrer"&gt;visual app builder&lt;/a&gt; to quickly design the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designing the Header
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop a &lt;strong&gt;Text&lt;/strong&gt; &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;component&lt;/a&gt; onto the canvas for the header. Rename this component to &lt;code&gt;headerText&lt;/code&gt; and set its text to "CSV TO GRAPH GENERATOR."&lt;/li&gt;
&lt;li&gt;Customize its styling properties to have:

&lt;ul&gt;
&lt;li&gt;Text size: 25&lt;/li&gt;
&lt;li&gt;Font weight: bolder&lt;/li&gt;
&lt;li&gt;Text color: #375fcfff&lt;/li&gt;
&lt;li&gt;Text alignment: right&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This will serve as the header text of your app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add an &lt;strong&gt;Icon&lt;/strong&gt; component, naming it &lt;code&gt;logo&lt;/code&gt;. Set the icon to &lt;code&gt;IconChartAreaFilled&lt;/code&gt; and the icon color to #375fcfff. Position it appropriately on the canvas to complement the header text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sgdf6ag2pd2ioe042m1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sgdf6ag2pd2ioe042m1.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the CSV Upload Section
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Drag a &lt;strong&gt;Container&lt;/strong&gt; component onto the canvas. Style this container with:

&lt;ul&gt;
&lt;li&gt;Border radius: 7&lt;/li&gt;
&lt;li&gt;Background color: #fff&lt;/li&gt;
&lt;li&gt;Box shadow: 2px 2px 1px 1px #aec0f5ff&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This container will hold all the input fields and output preview.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside the container, add a &lt;strong&gt;File Picker&lt;/strong&gt; component and rename it to &lt;code&gt;fileUploader&lt;/code&gt;. Set its &lt;strong&gt;Accept file types&lt;/strong&gt; property to &lt;code&gt;{"csv/*"}&lt;/code&gt; to accept CSV files. Enable the &lt;strong&gt;Parse content&lt;/strong&gt; toggle, and select &lt;strong&gt;File type&lt;/strong&gt; as CSV.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, add a &lt;strong&gt;Dropdown&lt;/strong&gt; component next to the File Picker, rename it to &lt;code&gt;graphSelectionDropdown&lt;/code&gt;. Set the component's &lt;strong&gt;Option values&lt;/strong&gt; to &lt;code&gt;["line", "scatter", "bar", "histogram", "box"]&lt;/code&gt; and &lt;strong&gt;Option labels&lt;/strong&gt; to &lt;code&gt;["Line", "Scatter", "Bar", "Histogram", "Box"]&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Below the dropdown, add a &lt;strong&gt;Button&lt;/strong&gt; component and rename it to &lt;code&gt;generateGraphButton&lt;/code&gt;. Set its text to "Generate Graph".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qbwuxnouuvweuakridt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qbwuxnouuvweuakridt.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/how-to-access-values" rel="noopener noreferrer"&gt;Double curly braces&lt;/a&gt; in ToolJet are used to pass custom code and refer or access values.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Image Preview
&lt;/h3&gt;

&lt;p&gt;To display the generated graph, add an &lt;strong&gt;Image&lt;/strong&gt; component below the File Picker and Button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ad9s1lhax4czbdvyubc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ad9s1lhax4czbdvyubc.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The UI is now ready! &lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Using Python Libraries through Queries
&lt;/h2&gt;

&lt;p&gt;ToolJet's &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;query&lt;/a&gt; builder offers a convenient way to use custom code or connect with external data sources, services, and libraries. We will use it to create a Python query that uses the CSV data and interacts with the matplotlib library to generate graphs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expand the query panel at the bottom, create a new query named &lt;code&gt;generateGraph&lt;/code&gt;, and choose &lt;strong&gt;Python&lt;/strong&gt; as the data source.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the below code in your Python query: &lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_plot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;csv_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileUploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
        &lt;span class="n"&gt;graph_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graphSelectionDropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Debug info:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;csv_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graph_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv_string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CSV must contain at least two columns&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;x_column&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;y_columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Line Plot: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; vs &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graph_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scatter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Scatter Plot: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; vs &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Scatter Plot: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; vs &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graph_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bar&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bar Plot: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xticks&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x_column&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graph_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;histogram&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;bins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Histogram: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Frequency&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graph_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;box&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boxplot&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Box Plot: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid graph type: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;graph_type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Choose &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scatter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bar&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;histogram&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, or &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;box&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;savefig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;png&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;img_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;img_str&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error in create_plot: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="nf"&gt;create_plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspopgg01n6h5tjbznt29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspopgg01n6h5tjbznt29.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once this is configured, you can select a CSV file in the File Picker, select the graph type, and click on the &lt;strong&gt;Run&lt;/strong&gt; button in the query panel. You can see the output generated by the query under preview.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Connecting the UI Components with the Query
&lt;/h2&gt;

&lt;p&gt;Time to bind the query to the components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the Image Preview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Data&lt;/strong&gt; property of the &lt;strong&gt;Image&lt;/strong&gt; component, enter the following code to bind the query's result: &lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data:image;base64,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateGraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For the &lt;strong&gt;Loading state&lt;/strong&gt; property of the Image component, click on the fx button to enter custom code and enter the below code: &lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateGraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;



&lt;h3&gt;
  
  
  Triggering the Query Based on Button Click
&lt;/h3&gt;

&lt;p&gt;Bind the query to the &lt;strong&gt;generateGraphButton&lt;/strong&gt; by adding an &lt;strong&gt;on Click&lt;/strong&gt; &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-events" rel="noopener noreferrer"&gt;event&lt;/a&gt; that triggers the &lt;strong&gt;generateGraph&lt;/strong&gt; query. This setup ensures that the script runs and generates the graph when the button is clicked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihus5ca5efk5gg60tz6s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihus5ca5efk5gg60tz6s.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this setup, every time you upload a CSV file, select a graph type, and click on the &lt;strong&gt;generateGraphButton&lt;/strong&gt;, the graph will be created and a preview will be visible in the Image component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0cemhi6h8kz9i6ag0b2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0cemhi6h8kz9i6ag0b2.png" alt=" " width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following these steps, we've successfully built a dynamic and user-friendly CSV to Graph Generator app with ToolJet. We utilized ToolJet's visual app builder to craft an elegant and intuitive UI, used the query builder to integrate a Python library for graph generation, and demonstrated how to customize ToolJet applications to deliver a smooth user experience.&lt;/p&gt;

&lt;p&gt;To learn and explore more about ToolJet, check out the &lt;a href="https://docs.tooljet.io" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; or connect with us and post your queries on our &lt;a href="https://tooljet.slack.com/" rel="noopener noreferrer"&gt;Slack channel&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build an HTML To Markdown Converter using ToolJet📋</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 04 Jul 2024 13:05:46 +0000</pubDate>
      <link>https://dev.to/tooljet/build-an-html-to-markdown-converter-using-tooljet-4p7h</link>
      <guid>https://dev.to/tooljet/build-an-html-to-markdown-converter-using-tooljet-4p7h</guid>
      <description>&lt;p&gt;In this tutorial, we will walk through the steps to build an HTML to Markdown Converter using ToolJet. This application allows users to input HTML code and get the corresponding Markdown output which can be copied with a button click. Using ToolJet's intuitive pre-built components, we'll design an elegant UI in just 5 minutes. The HTML to markdown conversion will be managed by the &lt;a href="https://github.com/mixmark-io/turndown?utm_source=cdnjs&amp;amp;utm_medium=cdnjs_link&amp;amp;utm_campaign=cdnjs_library" rel="noopener noreferrer"&gt;Turndown JavaScript library&lt;/a&gt;, while the Markdown preview will be rendered using the &lt;a href="https://www.npmjs.com/package/react-markdown" rel="noopener noreferrer"&gt;react-markdown&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ToolJet's Run JavaScript query and Text component can be utilized to convert HTML to Markdown and preview the content without using external libraries. However, in this tutorial, we are looking to demonstrate the process of using 3rd party libraries in ToolJet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a preview of the complete application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnldb333nq4ytyhsfpcyf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnldb333nq4ytyhsfpcyf.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ToolJet&lt;/strong&gt;(&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basics of JavaScript&lt;/strong&gt;: A basic understanding of JavaScript is essential for this tutorial since we will use JavaScript and React libraries to handle the logic for converting HTML to Markdown and previewing the markdown content.&lt;/p&gt;

&lt;p&gt;To begin, create a new application named &lt;strong&gt;HTML To Markdown Converter&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Creating the UI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Header
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a Container &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;component&lt;/a&gt; at the top of the canvas and rename it to &lt;code&gt;headerContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add an Icon and a Text component inside the Container. Rename them to &lt;code&gt;logo&lt;/code&gt; and &lt;code&gt;headerText&lt;/code&gt; respectively.&lt;/li&gt;
&lt;li&gt;Set the text to &lt;strong&gt;"HTML to Markdown Converter"&lt;/strong&gt; and select an appropriate icon for the app in the Icon component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71o2pr63y20cgtv0uyp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71o2pr63y20cgtv0uyp5.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Input Section
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add another Container component on the left and rename it to &lt;code&gt;inputContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside the container, add a Text component labeled &lt;strong&gt;"Enter HTML Code:"&lt;/strong&gt;. Rename it to &lt;code&gt;enterHTMLLabel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Below the label, add a Textarea component for the HTML input and rename it to &lt;code&gt;htmlInput&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Output Section
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a container next to the input section and rename it to &lt;code&gt;outputContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a Text component labeled &lt;strong&gt;"Markdown Preview:"&lt;/strong&gt; below the input section. Rename it to &lt;code&gt;markdownLabel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a Custom Component to display the Markdown output and rename it to &lt;code&gt;markdownOutput&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Buttons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a Button component labeled &lt;strong&gt;"Convert"&lt;/strong&gt; below the Textarea component. Rename the button to &lt;code&gt;convertButton&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add another Button component labeled &lt;strong&gt;"Copy Markdown"&lt;/strong&gt; besides the Convert button and rename it to &lt;code&gt;copyButton&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhmc06dd6h8c0xas7wgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhmc06dd6h8c0xas7wgn.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The UI of the application is done. Time to focus on the functionality.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Adding Queries and Events
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Import Turndown Library
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a Run JavaScript code &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;query&lt;/a&gt; named &lt;code&gt;importTurndownLibrary&lt;/code&gt; to import the Turndown library.&lt;/li&gt;
&lt;li&gt;Use the following code in the query to import the library:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to add script dynamically&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;scriptTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;scriptTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;scriptTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scriptTag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Importing turndown&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;addScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdnjs.cloudflare.com/ajax/libs/turndown/7.0.0/turndown.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Showing a success alert&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showAlert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Turndown JS is imported&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;turndownService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turndown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textarea1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Enable the &lt;strong&gt;Run this query on application load?&lt;/strong&gt; toggle to automatically run this query every time the app loads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl99vh8a3m6uwjx92filx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl99vh8a3m6uwjx92filx.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Convert HTML to Markdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create another Run JavaScript code query named &lt;code&gt;convertToMarkdown&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the following code in the query to convert the text entered in the &lt;code&gt;htmlInput&lt;/code&gt; component to markdown:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;turndownService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TurndownService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;turndownService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turndown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;htmlInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe60btw0gozshpmnsyagj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe60btw0gozshpmnsyagj.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Button Actions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For the &lt;strong&gt;Convert&lt;/strong&gt; button, create a new &lt;strong&gt;On click&lt;/strong&gt; &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-events" rel="noopener noreferrer"&gt;event&lt;/a&gt;, set the Action as &lt;strong&gt;Run Query&lt;/strong&gt;, and select &lt;code&gt;convertToMarkdown&lt;/code&gt; as the Query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yl5ig5foh5nen0z8b2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yl5ig5foh5nen0z8b2r.png" alt=" " width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the &lt;strong&gt;Copy Markdown&lt;/strong&gt; button, create a new &lt;strong&gt;On click&lt;/strong&gt; event, set the Action as &lt;strong&gt;Copy to clipboard&lt;/strong&gt; the &lt;code&gt;{{queries.convertToMarkdown.data}}&lt;/code&gt; as the Text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw3ooa0b9461f6kiri88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw3ooa0b9461f6kiri88.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of the key functionality is now configured. In the next step, we will use a Custom Component to import a React library to preview the markdown content.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Creating Markdown Preview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add Custom Component
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In the Custom Component, add the data that will be returned by the &lt;code&gt;convertToMarkdown&lt;/code&gt; query:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;convertToMarkdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use the following code to render the Markdown preview:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.skypack.dev/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.skypack.dev/react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.skypack.dev/@material-ui/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Markdown&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://esm.sh/react-markdown@9&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyCustomComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Container&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Markdown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Markdown&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Container&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ConnectedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Tooljet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connectComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyCustomComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ConnectedComponent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2a6l46zc7mkbivkij35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2a6l46zc7mkbivkij35.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, the HTML to Markdown converter is ready. Time to see it in action!&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Preview and Testing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Test the application by entering various HTML snippets and checking the Markdown output.&lt;/li&gt;
&lt;li&gt;Ensure that the &lt;strong&gt;Copy Markdown&lt;/strong&gt; button works correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx52gtfv8b8ntysalaeb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx52gtfv8b8ntysalaeb5.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We have successfully built an HTML to Markdown Converter using ToolJet in just minutes! This application is designed to simplify your content formatting process, and you can easily expand its functionality based on your specific requirements. Explore the capabilities of ToolJet to create similar projects and enhance your workflow.&lt;/p&gt;

&lt;p&gt;You can check out &lt;a href="https://docs.tooljet.com" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; for further learning or join the ToolJet Slack community for doubts and queries.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Regex Generator with Gemini AI and ToolJet ⚙️</title>
      <dc:creator>Aman Regu</dc:creator>
      <pubDate>Tue, 02 Jul 2024 13:02:20 +0000</pubDate>
      <link>https://dev.to/tooljet/building-a-regex-generator-with-gemini-ai-and-tooljet-43ng</link>
      <guid>https://dev.to/tooljet/building-a-regex-generator-with-gemini-ai-and-tooljet-43ng</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial will guide you through the process of building an AI-powered Regex Generator using &lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;ToolJet&lt;/a&gt; , a low-code visual app builder, and the Gemini API, a powerful natural language processing API. The resulting application will enable users to input requests in plain English, which will then be translated into Regular Expressions (Regex). We'll use ToolJet's visual app builder to create a user-friendly UI, and ToolJet's low-code query builder to connect it to the Gemini API endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ToolJet&lt;/strong&gt; (&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt; ): An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini API Key&lt;/strong&gt; : Log into &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt; using your existing Google credentials. Within the AI Studio interface, you can locate and copy your API key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a quick preview of our final application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0i4mm3nmx59f29efkj7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0i4mm3nmx59f29efkj7z.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Login to your &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;ToolJet account&lt;/a&gt;. Navigate to the ToolJet dashboard and click on the Create new app button on the top left corner. ToolJet comes with 45+ built-in components. This will let us set up our UI in no time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Assembling our UI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop the &lt;strong&gt;Container&lt;/strong&gt; component onto the canvas from the component library on the right side. Adjust the height and width of the &lt;strong&gt;Container&lt;/strong&gt; component appropriately.&lt;/li&gt;
&lt;li&gt;Similarly, drag-and-drop the &lt;strong&gt;Icon&lt;/strong&gt; and &lt;strong&gt;Text&lt;/strong&gt; component onto the canvas. We'll use them as our header.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Icon&lt;/strong&gt; component, navigate to the properties panel on the right and select the appropriate icon under the &lt;strong&gt;Icon&lt;/strong&gt; property.&lt;/li&gt;
&lt;li&gt;Change the colour of the &lt;strong&gt;Icon&lt;/strong&gt; and &lt;strong&gt;Text&lt;/strong&gt; component according to your preference.&lt;/li&gt;
&lt;li&gt;Drag and drop one &lt;strong&gt;Text&lt;/strong&gt; component and one  &lt;strong&gt;Textarea&lt;/strong&gt; component inside your canvas. We'll use these components for the label and input for our text query. Rename the &lt;strong&gt;Textarea&lt;/strong&gt; component to &lt;em&gt;textQueryInput&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Again, drag-and-drop two &lt;strong&gt;Text&lt;/strong&gt; components and two &lt;strong&gt;Text Input&lt;/strong&gt; components inside your container. We'll use them for displaying the generated regex expressions and testing a string against the generated regex expression respectively.&lt;/li&gt;
&lt;li&gt;Rename the &lt;strong&gt;Text Input&lt;/strong&gt; components as &lt;em&gt;generatedRegex&lt;/em&gt; and &lt;em&gt;testString&lt;/em&gt; respectively.&lt;/li&gt;
&lt;li&gt;Lastly, drag and drop two &lt;strong&gt;Button&lt;/strong&gt; components inside your container. We'll use them for initiating the regex expression generation and adding a &lt;strong&gt;copy to clipboard&lt;/strong&gt; functionality respectively.&lt;/li&gt;
&lt;li&gt;Rename the added &lt;strong&gt;Button&lt;/strong&gt; components to &lt;em&gt;generateRegex&lt;/em&gt; and &lt;em&gt;copyToClipboard&lt;/em&gt; respectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frulz6yc960geeqvosxwq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frulz6yc960geeqvosxwq.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting up Queries
&lt;/h2&gt;

&lt;p&gt;ToolJet allows you to connect to various external data sources, including databases, external APIs, and services using its powerful low code query builder. For this tutorial, We'll be using the REST API query feature to connect with the &lt;strong&gt;Gemini&lt;/strong&gt; API endpoints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using ToolJet's Workspace Constants feature, create a new constant named &lt;strong&gt;GEMINI_API_KEY&lt;/strong&gt; with your Gemini API key.&lt;/li&gt;
&lt;li&gt;In the query panel, click on the &lt;strong&gt;+ Add&lt;/strong&gt; button and choose the &lt;strong&gt;REST API&lt;/strong&gt; option.&lt;/li&gt;
&lt;li&gt;Rename the query to &lt;em&gt;getRegexPattern.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In the Request parameter, choose &lt;strong&gt;POST&lt;/strong&gt; as the Method from the drop-down and paste the following URL.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key={{constants.GEMINI_API_KEY}}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to the Body section of &lt;em&gt;getRegexPattern&lt;/em&gt;. Toggle on &lt;strong&gt;Raw JSON&lt;/strong&gt; and enter the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{
  `{
   "contents": [{
     "parts": [{
       "text": "Text Prompt: Based on pattern, generate a regex without any code highlighting, formatting or backticks, Pattern: ${JSON.stringify(components.textQueryInput.value).replace(/\\?"/g, '\\"')}"
      },],
    },],
  }`
}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Binding Queries to the UI Components
&lt;/h2&gt;

&lt;p&gt;Now that we have successfully added our UI and the query, the next step is to integrate them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;em&gt;generateRegex&lt;/em&gt; &lt;strong&gt;Button&lt;/strong&gt; component and navigate to the properties panel on the right. Click on the &lt;strong&gt;+ New event handler&lt;/strong&gt; button. Change the &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;Run query&lt;/strong&gt; and select the &lt;em&gt;getRegexPattern&lt;/em&gt; query. This will trigger the &lt;em&gt;getRegexPattern&lt;/em&gt; every time we click the &lt;em&gt;generateRegex&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Next, select the &lt;em&gt;generatedRegex&lt;/em&gt; &lt;strong&gt;Text Input&lt;/strong&gt; component and navigate to the properties panel on the right. Paste the following code into the &lt;strong&gt;Default value&lt;/strong&gt; field:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{queries.getRegexPattern.data.candidates[0].content.parts[0].text.trim()}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Select the &lt;em&gt;copyToClipboard&lt;/em&gt; &lt;strong&gt;Button&lt;/strong&gt; component and navigate to the properties panel on the right. Click on the &lt;strong&gt;+ New event handler&lt;/strong&gt; button. Change the &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;Copy to clipboard&lt;/strong&gt;. Paste the following code in the Text field under the Action Options subsection:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{components.generatedRegex.value}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Similarly, select the &lt;em&gt;testString&lt;/em&gt; &lt;strong&gt;Text Input&lt;/strong&gt; component and navigate to the properties panel on the right. Paste the following code in the Regex field under the Validation subsection:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{queries.getRegexPattern.data.candidates[0].content.parts[0].text.trim()}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have successfully integrated everything together. Now let's test the application with the text query below:&lt;br&gt;
&lt;em&gt;Match any string that is at least 8 characters long, contains at least one lowercase letter, one uppercase letter, and one number&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasm1eie2ygtxq2ikektt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasm1eie2ygtxq2ikektt.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations on successfully creating an AI-powered Regex generator with ToolJet and the Gemini API. You can now input natural language prompts to generate Regular Expressions effortlessly.&lt;/p&gt;

&lt;p&gt;To learn and explore more about ToolJet, check out the &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; or connect with us and post your queries on &lt;a href="https://join.slack.com/t/tooljet/shared_invite/zt-2ij7t3rzo-qV7WTUTyDVQkwVxTlpxQqw" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build an AI BPMN Diagram Analyzer using ToolJet 🛠️</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 27 Jun 2024 13:12:06 +0000</pubDate>
      <link>https://dev.to/tooljet/build-an-ai-bpmn-diagram-analyzer-using-tooljet-2b00</link>
      <guid>https://dev.to/tooljet/build-an-ai-bpmn-diagram-analyzer-using-tooljet-2b00</guid>
      <description>&lt;p&gt;In this tutorial, we'll create a BPMN Diagram Analyzer application using ToolJet. This app allows users to generate detailed explanations of BPMN processes by uploading them in image format. We'll use &lt;strong&gt;ToolJet's&lt;/strong&gt; &lt;strong&gt;low-code app-builder&lt;/strong&gt; for the user interface and its &lt;strong&gt;query builder&lt;/strong&gt; to connect to the Gemini API to generate an in depth analysis of uploaded BPMN processes.&lt;/p&gt;

&lt;p&gt;Here's a quick preview of our application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20b0iaftmp1hpm9bbae0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20b0iaftmp1hpm9bbae0.gif" alt=" " width="760" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gemini API Key&lt;/strong&gt; : The Gemini API is an advanced AI service provided by &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;. It enables developers to integrate powerful content generation capabilities into their applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ToolJet&lt;/strong&gt;(&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/p&gt;

&lt;p&gt;To begin, create a new application named &lt;em&gt;BPMN Diagram Analyzer&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Adding UI Elements 🖼️
&lt;/h2&gt;

&lt;p&gt;The first step in the app-building process is to utilize ToolJet's customizable pre-built components to build a UI in minutes. We will start with the header.&lt;/p&gt;

&lt;h3&gt;
  
  
  App Header
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;For the logo, add an &lt;strong&gt;Icon&lt;/strong&gt; component at the top of the canvas and name it &lt;code&gt;logo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Choose an appropriate icon (e.g., &lt;code&gt;IconAnalyzeFilled&lt;/code&gt;) and set its color to &lt;code&gt;#3e63ddff&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Text&lt;/strong&gt; component next to the Icon component.&lt;/li&gt;
&lt;li&gt;Set its Data property to "BPMN Diagram Analyzer".&lt;/li&gt;
&lt;li&gt;Style it with &lt;code&gt;#3e63ddff&lt;/code&gt; as the color, &lt;code&gt;24px&lt;/code&gt; as the font size, and font weight as bold.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r4qz4lxsqiu65o61fae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r4qz4lxsqiu65o61fae.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We are using blue (hex code: #3e63ddff) as the primary color, style the upcoming components accordingly.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Input Section
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add a &lt;strong&gt;Container&lt;/strong&gt; on the left to hold the input elements, and name it &lt;code&gt;inputContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside this container, add a &lt;strong&gt;Text&lt;/strong&gt; component as the header, and name it &lt;code&gt;inputLabel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the Text component's Data property to "Input".&lt;/li&gt;
&lt;li&gt;Below it, place an &lt;strong&gt;Image&lt;/strong&gt; component to display the uploaded BPMN diagram. Name it &lt;code&gt;imagePreview&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;File Picker&lt;/strong&gt; component and name it &lt;code&gt;fileUploader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Button&lt;/strong&gt; component labeled "Generate". Name it &lt;code&gt;generateButton&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add another &lt;strong&gt;Button&lt;/strong&gt; labeled "Copy Output", and name it &lt;code&gt;copyButton&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Position the buttons appropriately next to the File Picker.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjskct4n24vbg07jmv2oz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjskct4n24vbg07jmv2oz.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Output Section
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add another &lt;strong&gt;Container&lt;/strong&gt; for the output section, and name it &lt;code&gt;outputContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Text&lt;/strong&gt; component inside this container as the header, and name it &lt;code&gt;outputLabel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the Text component's Data property to "Output".&lt;/li&gt;
&lt;li&gt;Add another &lt;strong&gt;Text&lt;/strong&gt; component for the generated explanation. Name it &lt;code&gt;generatedOutput&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the data format to HTML since the generated explanation will be formatted in HTML format.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjvytfj5sfdzsp8g7cdx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjvytfj5sfdzsp8g7cdx.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configuring Queries 🔗
&lt;/h2&gt;

&lt;p&gt;With the UI ready, we can now connect to Gemini API and format the image preview using queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Image Preview Query
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new &lt;strong&gt;Run JavaScript code&lt;/strong&gt; query named &lt;code&gt;generateImagePreview&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the code below in the query:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`data:image;base&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="err"&gt;,$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;components.fileUploader.file&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;.base&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="err"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above query will restructure the image data and return it. The returned value will be used as a URL to display the image as a preview in the Image component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analyze Diagram Query
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new &lt;strong&gt;REST API&lt;/strong&gt; query named &lt;code&gt;analyseDiagram&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the method to POST and enter the below URL under the URL property:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;https://generativelanguage.googleapis.com/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;beta/models/gemini&lt;/span&gt;&lt;span class="mf"&gt;-1.5&lt;/span&gt;&lt;span class="err"&gt;-pro:generateContent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Under &lt;strong&gt;Headers&lt;/strong&gt;, add a new header and set the key to &lt;code&gt;Content-Type&lt;/code&gt; and value to &lt;code&gt;application/json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a new workspace constant named &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; and add your Gemini API Key to it.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Parameters&lt;/strong&gt;, add a new row with the key as &lt;code&gt;key&lt;/code&gt; and value as &lt;code&gt;{{constants.GEMINI_API_KEY}}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Configure the Body property of the query using the code below:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Explain in depth the content and overall of the uploaded BPMN (Business Process Model and Notation) diagram in HTML formatting only. Respond with only the explanation, and nothing else. Return the following information, with clear bullet points and headers (under 18 px) for each section: 1. **Title**: The title or main heading of the BPMN diagram. 2. **Description**: A brief description or summary of the BPMN diagram. 3. **Elements**: Explain all the processes identified in the diagram in the correct flow. If there are multiple sequences, explain them individually. 4. **Flows**: Describe the sequence flows, message flows, and associations between elements. 5. **Data Objects**: Identify and describe any data objects present in the diagram. 6. **Swimlanes**: If present, list the swimlanes (e.g., pools, lanes) and their roles or participants. Ensure the returned HTML is well-structured, with appropriate tags for headers, lists, and any other necessary elements for readability and organization."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"inline_data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"mime_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"image/jpeg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{components.fileUploader.file[0].base64Data}}"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This JSON request sends an uploaded BPMN diagram image for analysis, asking for a detailed HTML explanation of its contents, including the title, description, elements, flows, data objects, and swimlanes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Using Events For Dynamic Interaction 🔘
&lt;/h2&gt;

&lt;p&gt;Events in ToolJet allow you to easily create dynamic app interactions based on triggers such as button clicks or query completion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Button Click
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add a new event to the &lt;strong&gt;Generate&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Leave the Event as &lt;strong&gt;On click&lt;/strong&gt;, select &lt;strong&gt;Run Query&lt;/strong&gt; as the Action and Query as &lt;code&gt;analyseDiagram&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjuagcv10qmhon1i8i8ac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjuagcv10qmhon1i8i8ac.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now every time the Generate button is clicked, the &lt;code&gt;analyseDiagram&lt;/code&gt; query will run and the output will be generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy Button Click
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add an &lt;strong&gt;On click&lt;/strong&gt; event on the &lt;strong&gt;Copy Output&lt;/strong&gt; button to copy the generated output to the clipboard.&lt;/li&gt;
&lt;li&gt;Set the action as &lt;strong&gt;Copy to Clipboard&lt;/strong&gt; and under the Text property, enter the code below:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generatedOutput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqovfgxi4tt882feg4oo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqovfgxi4tt882feg4oo.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above setting will copy the output text from the related component every time we click on the Copy Output button.&lt;/p&gt;

&lt;h3&gt;
  
  
  File Picker Load:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add an &lt;strong&gt;On File Loaded&lt;/strong&gt; event on the File Picker component to run the generateImagePreview query.&lt;/li&gt;
&lt;li&gt;This configuration will ensure that the &lt;code&gt;generateImagePreview&lt;/code&gt; query runs each time a file gets uploaded to the File Picker component.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84funu16nihb1wkh9xww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84funu16nihb1wkh9xww.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This configuration will ensure that the generateImagePreview query runs each time a file gets uploaded to the File Picker component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image Preview
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Under the URL property of the &lt;strong&gt;Image&lt;/strong&gt; component, enter the code below:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateImagePreview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the Image component will display the BPMN diagram image once it is uploaded using the File Picker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Testing ✅
&lt;/h2&gt;

&lt;p&gt;Time to test all the functionalities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;strong&gt;File Picker&lt;/strong&gt; to upload an image - a preview should be visible on the Image component.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Generate Button&lt;/strong&gt; - the Text component in output should display the explanation of the BPMN diagram in-depth through HTML formatting.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Copy Output Button&lt;/strong&gt; - the generated explanation should get copied and you should get a notification saying "Copied to clipboard!"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F092pwp4qug1auw560d1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F092pwp4qug1auw560d1q.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following this tutorial, you have successfully created a BPMN Diagram Analyzer using ToolJet. This app allows users to upload BPMN diagrams in image format and receive detailed explanations, enhancing their workflow analysis capabilities. Feel free to expand and customize the app further based on your specific requirements. Happy building!&lt;/p&gt;

&lt;p&gt;To learn and explore more about ToolJet, check out the &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; or connect with us and post your queries on &lt;a href="https://tooljet.slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>Building a Mock Data Generator with Google Sheets, Gemini AI &amp; ToolJet ⚙️</title>
      <dc:creator>Aman Regu</dc:creator>
      <pubDate>Tue, 25 Jun 2024 13:33:12 +0000</pubDate>
      <link>https://dev.to/tooljet/building-a-mock-data-generator-with-google-sheets-gemini-ai-tooljet-24f2</link>
      <guid>https://dev.to/tooljet/building-a-mock-data-generator-with-google-sheets-gemini-ai-tooljet-24f2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial will guide you through the process of building an AI-driven Mock Data Generator using &lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;ToolJet&lt;/a&gt;, a low-code visual app builder, and the Gemini API, a powerful natural language processing API. We'll also use ToolJet's build-in integration with Google Sheets to store our mock data. The resulting application will enable users to generate mock data based on the sample format data present in the spreadsheet. We'll use ToolJet's visual app builder to create a user-friendly UI, and ToolJet's low-code query builder to connect it to the Gemini API endpoints and our Google Sheets data source.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ToolJet&lt;/strong&gt;(&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini API Key&lt;/strong&gt; : The Gemini API is an advanced AI service provided by &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;. It enables developers to integrate powerful content generation capabilities into their applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google account with access to Google Sheets&lt;/strong&gt;: Log into Google Sheets using your Google account and create a new spreadsheet. Add column names to define the structure of your data. Additionally, you can create at least one row of data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a quick preview of our final application:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4m7a4r6dnegk1jv9v4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4m7a4r6dnegk1jv9v4a.png" alt=" " width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Prepare your Google Sheets Document
&lt;/h2&gt;

&lt;p&gt;We will be starting this tutorial by setting up the Google Sheets document with the following data.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7yoxcewyjsuqkm2m7n3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7yoxcewyjsuqkm2m7n3.png" alt=" " width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Connecting Google Sheets to ToolJet
&lt;/h2&gt;

&lt;p&gt;Once the spreadsheet is ready, let’s connect our &lt;strong&gt;Google Sheet&lt;/strong&gt; to &lt;strong&gt;ToolJet&lt;/strong&gt;. Follow the steps mentioned below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the ToolJet dashboard, locate the &lt;strong&gt;Data Sources&lt;/strong&gt; section on the left sidebar. Click on the &lt;strong&gt;+Add&lt;/strong&gt; button under the Google Sheets plugin.&lt;/li&gt;
&lt;li&gt;Choose the &lt;strong&gt;Read and write&lt;/strong&gt; option since we will be adding the mock data to our Google Sheet.&lt;/li&gt;
&lt;li&gt;Once you click on &lt;strong&gt;Connect Data source&lt;/strong&gt;, you will be redirected to grant access to ToolJet to your Google Sheets; grant the access and click &lt;strong&gt;Save data source&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Now that you have successfully connected Google Sheets to your ToolJet account, click the &lt;strong&gt;Apps&lt;/strong&gt; icon on the left sidebar and select &lt;strong&gt;Create an app&lt;/strong&gt;. Let’s name our app &lt;em&gt;Mock Data Generator&lt;/em&gt;.
Now that we’ve set up our App, it’s time to create the UI.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 3: Building the UI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop the &lt;strong&gt;Container&lt;/strong&gt; component onto the canvas from the component library on the right side. Adjust the height and width of the Container component appropriately.&lt;/li&gt;
&lt;li&gt;Similarly, drag and drop the &lt;strong&gt;Icon&lt;/strong&gt; and the &lt;strong&gt;Text&lt;/strong&gt; component onto your canvas. We'll use them as our logo and header.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Icon&lt;/strong&gt; component, navigate to the properties panel on the right and select the appropriate icon under the &lt;strong&gt;Icon&lt;/strong&gt; property.&lt;/li&gt;
&lt;li&gt;Change the color of the Icon and Text component according to your preference.&lt;/li&gt;
&lt;li&gt;Drag and drop the &lt;strong&gt;Dropdown&lt;/strong&gt; component inside your container. We'll use this dropdown to choose between the available sheets. Rename this component to &lt;em&gt;selectSheet&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Similarly, drag and drop two &lt;strong&gt;Button&lt;/strong&gt; components inside the container. We'll use these buttons for generating mock data and saving the data to the Google Sheet.&lt;/li&gt;
&lt;li&gt;Next, add a &lt;strong&gt;Table&lt;/strong&gt; Component to display the generated mock data.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy3ubx5ota81yl4qzrce.png" alt=" " width="800" height="453"&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 4: Setting up Queries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Fetching the Sheets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Expand the &lt;strong&gt;Query Panel&lt;/strong&gt; at the bottom and click the &lt;strong&gt;Add&lt;/strong&gt; button to create a query - rename this query to &lt;em&gt;getSheets&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Choose Data Source as &lt;strong&gt;googlesheets&lt;/strong&gt;, and &lt;strong&gt;Operation&lt;/strong&gt; as &lt;strong&gt;Get spreadsheet info&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Spreadsheet ID&lt;/strong&gt; section, enter the spreadsheet ID of your sheet. To access the spreadsheet ID, check your Google Sheet's URL, the format should be: &lt;code&gt;https://docs.google.com/spreadsheets/d/&amp;lt;SPREADHEET_ID&amp;gt;/edit#gid=0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To ensure that this query runs every time the application loads, toggle &lt;strong&gt;Run this query on application load?&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable the &lt;strong&gt;Transformations&lt;/strong&gt; toggle and enter the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return data.sheets.map(item =&amp;gt; item.properties.title);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return all the sheet names in an Array. We'll use this to populate the values in our dropdown component.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fetching initial sample data
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Similarly, create another query and rename it to &lt;em&gt;getInitialData&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Choose the &lt;strong&gt;Operation&lt;/strong&gt; as &lt;strong&gt;Read data from a spreadsheet&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter the following code in the &lt;strong&gt;Sheet&lt;/strong&gt; field:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{components.selectSheet.value}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Generating Mock Data using Gemini API
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Using ToolJet's &lt;a href="https://docs.tooljet.com/docs/org-management/workspaces/workspace_constants/" rel="noopener noreferrer"&gt;Workspace Constants&lt;/a&gt; feature, create a new constant named &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; with your Gemini API key.&lt;/li&gt;
&lt;li&gt;In the query panel, click on the &lt;strong&gt;+ Add **button and choose the **REST API&lt;/strong&gt; option.
Rename the query to &lt;em&gt;generateMockData&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;In the Request parameter, choose &lt;strong&gt;POST&lt;/strong&gt; as the &lt;strong&gt;Method&lt;/strong&gt; from the drop-down and paste the following URL.
&lt;code&gt;https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key={{constants.GEMINI_API_KEY}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Body&lt;/strong&gt; section of &lt;em&gt;getSqlQuery&lt;/em&gt;. Toggle on Raw JSON and enter the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {{
  `{
   "contents": [{
     "parts": [{
       "text": "Sample Data: ${JSON.stringify(queries.getInitialData.data[0]).replace(/\\?"/g, '\\"')}, Text Prompt: Based on the sample data, only return an Array with 10 objects with same type of mock data without any code highlighting, formatting or backticks"
      },],
    },],
  }`
}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Inserting data into our Google Sheet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create another query and choose Data Source as googlesheets, and &lt;strong&gt;Operation&lt;/strong&gt; as &lt;strong&gt;Append data to a spreadsheet&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter the following code in the Sheet field:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{components.selectSheet.value}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Enter the following code in the Rows field:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{JSON.parse(queries.generateMockData.data.candidates[0].content.parts[0].text)}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5: Binding Queries to the UI Components
&lt;/h2&gt;

&lt;p&gt;Now that we have successfully built our UI and queries, the next step is to integrate them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the Dropdown component, under the Properties section, and enter the following code for both &lt;strong&gt;Option values&lt;/strong&gt; and &lt;strong&gt;labels&lt;/strong&gt; fields:
&lt;code&gt;{{queries.getSheets.data}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select the &lt;em&gt;Generate Data Button&lt;/em&gt; component, under the Properties section, click the &lt;strong&gt;New event handler&lt;/strong&gt; button to create a new event.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;On click&lt;/strong&gt; as the &lt;strong&gt;Event&lt;/strong&gt;, &lt;strong&gt;Run Query&lt;/strong&gt; as the &lt;strong&gt;Action&lt;/strong&gt;, and select &lt;em&gt;getInitialData&lt;/em&gt; as the Query.&lt;/li&gt;
&lt;li&gt;Select the &lt;em&gt;getInitialData&lt;/em&gt; query, and click the &lt;strong&gt;New event handler&lt;/strong&gt; button to create a new event.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Query Success&lt;/strong&gt; as the &lt;strong&gt;Event&lt;/strong&gt;, &lt;strong&gt;Run Query&lt;/strong&gt; as the &lt;strong&gt;Action&lt;/strong&gt;, and select &lt;em&gt;generateMockData&lt;/em&gt; as the Query.&lt;/li&gt;
&lt;li&gt;Next, Select the Table component. In the properties panel on the right, enter the following code in the Data field.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{JSON.parse(queries.generateMockData.data.candidates[0].content.parts[0].text)}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Select the &lt;em&gt;Save to Google Sheets&lt;/em&gt; Button component, under the Properties section, click the &lt;strong&gt;New event handler&lt;/strong&gt; button to create a new event.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;On click&lt;/strong&gt; as the &lt;strong&gt;Event&lt;/strong&gt;, &lt;strong&gt;Run Query&lt;/strong&gt; as the &lt;strong&gt;Action&lt;/strong&gt;, and select &lt;em&gt;insertData&lt;/em&gt; as the &lt;strong&gt;Query&lt;/strong&gt;.
We have successfully integrated our queries into our UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's test the application with the following sample data format:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feek2o7qduujovg6hjwv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feek2o7qduujovg6hjwv0.png" alt=" " width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Table Preview&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1dg2h8s11umapq96ow5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1dg2h8s11umapq96ow5.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the &lt;strong&gt;Save to Google Sheets&lt;/strong&gt; Button.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr3r6t6b6v0b6znxykqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr3r6t6b6v0b6znxykqx.png" alt=" " width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations on successfully building an AI-driven Mock Data Generator using ToolJet and Gemini API.&lt;/p&gt;

&lt;p&gt;To learn and explore more about ToolJet, check out the &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; or connect with us and post your queries on &lt;a href="https://join.slack.com/t/tooljet/shared_invite/zt-2ij7t3rzo-qV7WTUTyDVQkwVxTlpxQqw" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>googlesheets</category>
      <category>ai</category>
      <category>javascript</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Create a QR Code Generator Using ToolJet and Python in 5 Minutes! 🛠️</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 20 Jun 2024 13:04:57 +0000</pubDate>
      <link>https://dev.to/tooljet/create-a-qr-code-generator-using-tooljet-and-python-in-5-minutes-19m6</link>
      <guid>https://dev.to/tooljet/create-a-qr-code-generator-using-tooljet-and-python-in-5-minutes-19m6</guid>
      <description>&lt;p&gt;This quick tutorial will guide you through the steps to create a QR Code Generator application using ToolJet. The app will allow users to select a URL and generate a corresponding QR code. We will utilize ToolJet's visual app-builder to rapidly build a user interface and then connect to a Python module to generate QR codes from URLs.&lt;/p&gt;

&lt;p&gt;Here's the preview of the application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbo8w8oj79llquvfuazh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbo8w8oj79llquvfuazh.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ToolJet&lt;/strong&gt;(&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic knowledge of &lt;strong&gt;Python&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Begin by creating an application named &lt;em&gt;QR Code Generator&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Design the User Interface
&lt;/h2&gt;

&lt;h4&gt;
  
  
  - Add a Container for the Header
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Drag and drop a &lt;code&gt;Container&lt;/code&gt; component onto the canvas.&lt;/li&gt;
&lt;li&gt;Name it &lt;code&gt;headerContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set its background color to &lt;code&gt;#0a60c6ff&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  - Add a Text Component for the App Name
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Inside the &lt;code&gt;headerContainer&lt;/code&gt;, add a &lt;code&gt;Text&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;Set the text to "QR Code Generator."&lt;/li&gt;
&lt;li&gt;Style it with:

&lt;ul&gt;
&lt;li&gt;Text Color: &lt;code&gt;#ffffffff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Text Size: &lt;code&gt;24&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Font Weight: &lt;code&gt;bold&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Border Radius: &lt;code&gt;6&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  - Add an Icon for the App Logo
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Inside the &lt;code&gt;headerContainer&lt;/code&gt;, add an &lt;code&gt;Icon&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;Set the icon to &lt;code&gt;IconQrcode&lt;/code&gt; and color to &lt;code&gt;#ffffffff&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  - Add a Table with URLs and Other Information
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Drag and drop a &lt;code&gt;Table&lt;/code&gt; component onto the canvas.&lt;/li&gt;
&lt;li&gt;Name it &lt;code&gt;linksTable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Below is the database table structure that we are using for this application:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;: Auto-generated&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt;: String&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;: String&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: String&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Populate the &lt;code&gt;Table&lt;/code&gt; component with data, based on the provided structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  - Add a Text Component for the Table Header
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Above the table, add a &lt;code&gt;Text&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;Set the text to "URL Information."&lt;/li&gt;
&lt;li&gt;Style it with:

&lt;ul&gt;
&lt;li&gt;Text Color: &lt;code&gt;#0a60c6ff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Text Size: &lt;code&gt;24&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Font Weight: &lt;code&gt;bold&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  - Add a Modal for QR Code Generation
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Drag and drop a &lt;code&gt;Modal&lt;/code&gt; component onto the canvas.&lt;/li&gt;
&lt;li&gt;Name it &lt;code&gt;generateButton&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the Trigger button label to "Generate QR" and the Background color to &lt;code&gt;#0a60c6ff&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  - Add an Image Component to Display the QR Code
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Inside the modal, add an &lt;code&gt;Image&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;Name it &lt;code&gt;qrOutput&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the below code for the Image component's URL property:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;,{{&lt;/span&gt;&lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QRGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Similarly, use the below code for the Loading state property of the Image component:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QRGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;The above configuration will display the generated QR code in the Image component after we craft and run the related query(named &lt;code&gt;QRGenerator&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Implement Functionality
&lt;/h2&gt;

&lt;h4&gt;
  
  
  - Add a Python Script for QR Code Generation
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Add a query named &lt;code&gt;QRGenerator&lt;/code&gt; using the Run Python code data source.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the following Python code to generate the QR code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;micropip&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;micropip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qrcode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;qrcode&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;QR_Generator&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;qr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QRCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;error_correction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ERROR_CORRECT_L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;box_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;qr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linksTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;qr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fill_color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;back_color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;buffered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PNG&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Specify the format as a string
&lt;/span&gt;    &lt;span class="n"&gt;img_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;img_str&lt;/span&gt;
&lt;span class="nc"&gt;QR_Generator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffde7kmb9xs2i4ocx8ido.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffde7kmb9xs2i4ocx8ido.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This code uses the &lt;code&gt;qrcode&lt;/code&gt; library to generate a QR code from a selected URL in a ToolJet table component. The generated QR code is converted to a base64-encoded PNG image and returned as a string.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  - Link the QR Generator to the Generate Button
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Select the &lt;code&gt;generateButton&lt;/code&gt; modal and add a new event handler to it.&lt;/li&gt;
&lt;li&gt;Set up an &lt;code&gt;On open&lt;/code&gt; event to run the &lt;code&gt;QRGenerator&lt;/code&gt; query.&lt;/li&gt;
&lt;li&gt;After the above configuration, the output of the &lt;code&gt;QRGenerator&lt;/code&gt; query will be displayed in the &lt;code&gt;qrOutput&lt;/code&gt; Image component based on the earlier configuration.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 3: Test the Application
&lt;/h2&gt;

&lt;p&gt;Select a row on the &lt;code&gt;Table&lt;/code&gt; component and click on the &lt;code&gt;generateButton&lt;/code&gt; modal to generate and view the QR code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzwezsz8969iqes9gvv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzwezsz8969iqes9gvv6.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can save the QR code by right-clicking on the image and selecting &lt;code&gt;Save image as&lt;/code&gt;. Alternatively, you can set up a Button component to download the image directly.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Congratulations
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've successfully built a production-ready QR code generator. This application demonstrates ToolJet's capability to rapidly design clean user interfaces and extend functionality with custom code. While we used Python code in this tutorial, ToolJet also supports JavaScript code and Custom Components for users who want to extend the platform's functionality for very specific use-cases.&lt;/p&gt;

&lt;p&gt;For any questions or support, join the &lt;a href="https://tooljet.slack.com/" rel="noopener noreferrer"&gt;ToolJet Slack community&lt;/a&gt;. You can also check out the &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; to learn more!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a SQL Report Generator using Gemini AI + ToolJet 📊</title>
      <dc:creator>Aman Regu</dc:creator>
      <pubDate>Tue, 18 Jun 2024 13:00:56 +0000</pubDate>
      <link>https://dev.to/tooljet/building-a-sql-report-generator-using-gemini-ai-tooljet-424p</link>
      <guid>https://dev.to/tooljet/building-a-sql-report-generator-using-gemini-ai-tooljet-424p</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial will guide you through the process of building an AI-driven SQL custom report generator using &lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;ToolJet&lt;/a&gt;, a low-code visual app builder, and the Gemini API, a powerful natural language processing API. The resulting application will enable users to input requests in plain English, which will then be translated into custom reports. We'll use ToolJet's visual app builder to create a user-friendly UI, and ToolJet's low-code query builder to connect it to the Gemini API endpoints and our data sources. The final product will enable users to preview generated reports and download them in PDF, Excel, or CSV formats.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ToolJet&lt;/strong&gt; (&lt;a href="https://github.com/ToolJet/ToolJet):" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet):&lt;/a&gt; An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini API Key&lt;/strong&gt; : Log into &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt; using your existing Google credentials. Within the AI Studio interface, you can locate and copy your API key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a quick preview of our final application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxb7brsesfnu9t6ny61h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxb7brsesfnu9t6ny61h1.png" alt="SQL Report Builder Preview" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Login to your &lt;a href="https://app.tooljet.com/" rel="noopener noreferrer"&gt;ToolJet account&lt;/a&gt;. Navigate to the ToolJet dashboard and click on the Create new app button on the top left corner. ToolJet comes with 45+ built-in components. This will let us set up our UI in no time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building our UI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop the &lt;strong&gt;Container&lt;/strong&gt; component onto the canvas from the component library on the right side. Adjust the height and width of the &lt;strong&gt;Container&lt;/strong&gt; component appropriately.&lt;/li&gt;
&lt;li&gt;Similarly, drag-and-drop the &lt;strong&gt;Icon&lt;/strong&gt; and three &lt;strong&gt;Text&lt;/strong&gt; components inside your Container. We'll use these &lt;strong&gt;Text&lt;/strong&gt; components for our header and label texts.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Icon&lt;/strong&gt; component, navigate to the properties panel on the right and select the appropriate icon under the &lt;strong&gt;Icon&lt;/strong&gt; property.&lt;/li&gt;
&lt;li&gt;Change the colour of the &lt;strong&gt;Icon&lt;/strong&gt; and &lt;strong&gt;Text&lt;/strong&gt; component according to your preference.&lt;/li&gt;
&lt;li&gt;Change the font size and content of the &lt;strong&gt;Text&lt;/strong&gt; component appropriately.&lt;/li&gt;
&lt;li&gt;Drag and drop the &lt;strong&gt;Textarea&lt;/strong&gt; component inside your Container. We'll use this component as an input for our text query.&lt;/li&gt;
&lt;li&gt;Rename the &lt;strong&gt;Textarea&lt;/strong&gt; component to &lt;em&gt;textPrompt&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Next, drag and drop the &lt;strong&gt;Table&lt;/strong&gt; component onto the Container. We'll use this component to display a preview of our report. The &lt;strong&gt;Table&lt;/strong&gt; component comes built-in with the functionality to download the displayed data. This will allow us to download our generated report in PDF, Excel, or CSV formats.&lt;/li&gt;
&lt;li&gt;Now let's add a &lt;strong&gt;Button&lt;/strong&gt; component that initiates the report generation process. Change the colour, size and content appropriately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b1r1pifxlt1kj74xe0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b1r1pifxlt1kj74xe0e.png" alt="SQL Report Builder UI" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting up Queries
&lt;/h2&gt;

&lt;p&gt;Apart from its built-in database and data sources, ToolJet allows you to connect to various external data sources, including databases, external APIs, and services. For this tutorial, we'll be using ToolJet's built-in PostgreSQL sample data source. The queries we'll set up will be applicable to an external PostgreSQL data source as well.&lt;/p&gt;

&lt;p&gt;We'll also be using the REST API query feature to connect with the &lt;strong&gt;Gemini&lt;/strong&gt; API endpoints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the query panel, click the + Add button and choose the Sample data source option.&lt;/li&gt;
&lt;li&gt;Rename the query to getDatabaseSchema.&lt;/li&gt;
&lt;li&gt;In the dropdown, choose the SQL mode and enter the code below. This will fetch all the table names in our database along with their column names.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT table_name, string_agg(column_name, ', ') AS columns
FROM information_schema.columns
WHERE table_schema = 'public'
GROUP BY table_name

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To ensure that the query runs every time the application loads, enable the &lt;strong&gt;Run this query on application load?&lt;/strong&gt; toggle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's create another query that will connect to the Gemini AI API and generate our custom SQL report query.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using ToolJet's &lt;a href="https://docs.tooljet.com/docs/org-management/workspaces/workspace_constants/" rel="noopener noreferrer"&gt;Workspace Constants&lt;/a&gt; feature, create a new constant named &lt;strong&gt;GEMINI_API_KEY&lt;/strong&gt; with your Gemini API key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the query panel, click on the &lt;strong&gt;+ Add&lt;/strong&gt; button and choose the &lt;strong&gt;REST API&lt;/strong&gt; option.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename the query to &lt;em&gt;getSqlQuery&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Request parameter, choose POST as the Method from the drop-down and paste the following URL.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key={{constants.GEMINI_API_KEY}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Navigate to the Body section of &lt;em&gt;getSqlQuery&lt;/em&gt;. Toggle on Raw JSON and enter the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{
  `{
   "contents": [{
     "parts": [{
       "text": "Data Schema: ${JSON.stringify(queries.getTablesWithColumns.data.map(item =&amp;gt; ({ ...item, table_name: "public." + item.table_name }))).replace(/"([^"]+)":/g, '$1:').replace(/"/g, '\\"')}, Text Prompt: Write a standard SQL query for a custom SQL report that will ${components.textPrompt.value.replaceAll("\n"," ")}. Return without formatting and without any code highlighting and any backticks"
      },],
    },],
  }`
}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add our final query which will retrieve the data from the sample data source that we need for our custom report.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Similarly, create another &lt;strong&gt;Sample data source&lt;/strong&gt; query, rename it to &lt;em&gt;getReportData&lt;/em&gt; and enter the code below:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{queries.getSqlQuery.data.candidates[0].content.parts[0].text}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Binding Queries to the UI Components
&lt;/h2&gt;

&lt;p&gt;Now that we have successfully built our UI and queries, the next step is to integrate them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Button&lt;/strong&gt; component and navigate to the properties panel on the right. Click on the &lt;strong&gt;+ New event handler&lt;/strong&gt; button. Change the &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;Run query&lt;/strong&gt; and select the &lt;em&gt;getSqlQuery&lt;/em&gt; query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, navigate to the &lt;em&gt;getSqlQuery&lt;/em&gt; query and click on the &lt;strong&gt;+ New event handler&lt;/strong&gt; button. Change the &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;Run query&lt;/strong&gt; and select the &lt;em&gt;getReportData&lt;/em&gt; query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, Select the &lt;strong&gt;Table&lt;/strong&gt; component. In the properties panel on the right, enter the following code in the Data field.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{queries.getReportData.data}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have successfully integrated our queries into our UI. Now let's test the application with the prompt below:&lt;br&gt;
&lt;em&gt;list the names of customers along with the products they have ordered, including the order date and the total quantity ordered for each product.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbdvss1cd8b7mjucowym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbdvss1cd8b7mjucowym.png" alt="SQL Report Example" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click on the &lt;strong&gt;+&lt;/strong&gt; button on the &lt;strong&gt;Table&lt;/strong&gt; footer to download this report in PDF, Excel, or CSV formats.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations on successfully building an AI-powered SQL report generator using ToolJet and the Gemini API. You can now input prompts in plain English and generate reports across multiple tables in your PostgreSQL instance.&lt;br&gt;
To learn and explore more about ToolJet, check out the &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; or connect with us and post your queries on &lt;a href="https://join.slack.com/t/tooljet/shared_invite/zt-2ij7t3rzo-qV7WTUTyDVQkwVxTlpxQqw" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>lowcode</category>
      <category>gemini</category>
      <category>javascript</category>
      <category>ai</category>
    </item>
    <item>
      <title>Build an AI Business Proposal Writer Using Gemini API and ToolJet in 10 minutes 🚀</title>
      <dc:creator>Karan Rathod</dc:creator>
      <pubDate>Thu, 13 Jun 2024 13:03:15 +0000</pubDate>
      <link>https://dev.to/tooljet/build-an-ai-business-proposal-writer-using-gemini-api-and-tooljet-in-10-minutes-4j3j</link>
      <guid>https://dev.to/tooljet/build-an-ai-business-proposal-writer-using-gemini-api-and-tooljet-in-10-minutes-4j3j</guid>
      <description>&lt;p&gt;In this tutorial, we'll guide you through the process of creating an AI Business Proposal Writer using ToolJet and Gemini API. We will utilize ToolJet's pre-built components and simple integration process to quickly create an application that can interact with the Gemini API. This application will allow users to input business details and generate professional business proposals.&lt;/p&gt;

&lt;p&gt;Here's a preview of the final application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frghughfkz183bzjtqpou.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frghughfkz183bzjtqpou.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewcpalt0obyfkvdh68xr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewcpalt0obyfkvdh68xr.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gemini API Key&lt;/strong&gt; : The Gemini API is an advanced AI service provided by &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;. It enables developers to integrate powerful content generation capabilities into their applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ToolJet&lt;/strong&gt;(&lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;https://github.com/ToolJet/ToolJet&lt;/a&gt;) : An open-source, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/p&gt;

&lt;p&gt;Begin by creating an application named &lt;em&gt;Business Proposal Writer&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Create a New Application
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open ToolJet and click on &lt;strong&gt;Create new application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name your application "Business Proposal Writer."&lt;/li&gt;
&lt;li&gt;Once you create a new application, you will see an empty canvas with a component library on the right and a query panel at the bottom.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuox8timx0s6gmmhjbty9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuox8timx0s6gmmhjbty9.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Design the UI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Drag and drop the following components onto your canvas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Containers&lt;/strong&gt;: To organize the header, input fields, and output section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text and Text Inputs&lt;/strong&gt;: For company name, service description, budget, deadline, and company expertise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Button&lt;/strong&gt;: For generating the proposal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt;: To display the generated proposal in HTML format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons&lt;/strong&gt;: For logos and making the UI more appealing.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Rename the input fields for clarity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;companyNameInput&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;serviceDescriptionInput&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;budgetInput&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deadlineInput&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;companyExpertiseInput&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Name the button &lt;code&gt;createButton&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Name the text component that will display the generated proposal as &lt;code&gt;output&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd268ymnakkc0xzrhm09o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd268ymnakkc0xzrhm09o.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ToolJet's pre-built &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;components&lt;/a&gt; offer complete flexibility in functionality and styling customization.&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Integrating with Gemini API through Queries
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/workspace-constants/" rel="noopener noreferrer"&gt;workspace constant&lt;/a&gt; to save your Gemini API key. Name it &lt;code&gt;GEMINI_API_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Expand the query panel, create a new query, and name it &lt;code&gt;generateProposal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Change the Request Method to &lt;code&gt;POST&lt;/code&gt; and paste the following URL under the URL input:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;https://generativelanguage.googleapis.com/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;beta/models/gemini&lt;/span&gt;&lt;span class="mf"&gt;-1.5&lt;/span&gt;&lt;span class="err"&gt;-pro:generateContent?key=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="err"&gt;constants.GEMINI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Body&lt;/strong&gt; section of the &lt;code&gt;generateProposal&lt;/code&gt; query. Toggle on &lt;strong&gt;Raw JSON&lt;/strong&gt; and enter the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"
1. **Client/Company Name:** {{components.companyNameInput.value}}
2. **Project/Service Description:** {{components.serviceDescriptionInput.value}}
3. **Budget Range (if applicable):** {{components.budgetInput.value}}
4. **Deadline:** {{components.deadlineInput.value}}
5. **Company Expertise:** {{components.companyExpertiseInput.value}}

Based on these inputs, generate a well-structured and comprehensive business proposal document in HTML format. The generated proposal should include the following sections, each with ample padding and spacing:

1. **Executive Summary**
2. **Company Overview and Qualifications**
3. **Project Understanding and Approach**
4. **Proposed Solution and Methodology**
5. **Timeline and Deliverables**
6. **Team Structure and Bios**
7. **Cost Breakdown and Budget** (Include charts as needed)
8. **Terms and Conditions**
9. **Conclusion and Call to Action**

Ensure that the HTML output is properly formatted and visually appealing."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx6u1z4w3go5whk6ednk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx6u1z4w3go5whk6ednk.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries" rel="noopener noreferrer"&gt;Queries&lt;/a&gt; in ToolJet offer a simple and easy way to connect with &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-datasources" rel="noopener noreferrer"&gt;databases, APIs, and cloud storage services&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Connecting the UI Components with Queries
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;code&gt;createButton&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;Add an event handler to trigger the &lt;code&gt;generateProposal&lt;/code&gt; query when the button is clicked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi66iykhynllvavuvuvub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi66iykhynllvavuvuvub.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-events" rel="noopener noreferrer"&gt;Events&lt;/a&gt; are used to run queries, show alerts, and other functionalities based on triggers such as button clicks or query completion.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the &lt;code&gt;output&lt;/code&gt; component that was added to display the generated business proposal.&lt;/li&gt;
&lt;li&gt;Under its &lt;strong&gt;Data&lt;/strong&gt; property, enter the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="err"&gt;queries.generateProposal.data.candidates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;.content.parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;.text&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, enter the required details in the input fields and click on the button. You should see the generated business proposal in the output component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2hkc9s5duzoqm7s4uud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2hkc9s5duzoqm7s4uud.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxed4o0pkc92cywh7vj1e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxed4o0pkc92cywh7vj1e.png" alt=" " width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have successfully built a business proposal writer using the Gemini API and ToolJet in just 10 minutes. This tool will streamline the creation of professional business proposals, saving you time and effort. &lt;/p&gt;

&lt;p&gt;For any questions or support, join the &lt;a href="https://join.slack.com/t/tooljet/shared_invite/zt-2l2i9tuls-NNCZPBlPAi2flYIhrjBqHA" rel="noopener noreferrer"&gt;ToolJet Slack community&lt;/a&gt;. You can also check out the &lt;a href="https://docs.tooljet.com" rel="noopener noreferrer"&gt;ToolJet documentation&lt;/a&gt; to learn more!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building an Ed-Tech Sales CRM using ToolJet 📈</title>
      <dc:creator>Pritesh Kiri</dc:creator>
      <pubDate>Tue, 11 Jun 2024 12:33:52 +0000</pubDate>
      <link>https://dev.to/tooljet/building-an-ed-tech-sales-crm-using-tooljet-3e2i</link>
      <guid>https://dev.to/tooljet/building-an-ed-tech-sales-crm-using-tooljet-3e2i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;An effective Customer Relationship Management (CRM) system can help Ed-tech companies streamline their sales processes, maintain customer information, and enhance customer interactions.  &lt;/p&gt;

&lt;p&gt;In this tutorial, we will guide you through the process of building an Ed-tech sales CRM using &lt;a href="https://www.tooljet.com" rel="noopener noreferrer"&gt;ToolJet&lt;/a&gt; and &lt;a href="https://docs.tooljet.com/docs/tooljet-db/tooljet-database" rel="noopener noreferrer"&gt;ToolJet Database&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Here is a quick preview of the CRM that we’ll be building in ToolJet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr253djk8qvb5proe7wwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr253djk8qvb5proe7wwi.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ToolJet &lt;a href="https://github.com/ToolJet/ToolJet" rel="noopener noreferrer"&gt;(https://github.com/ToolJet/ToolJet)&lt;/a&gt;: An &lt;strong&gt;open-source&lt;/strong&gt;, low-code business application builder. &lt;a href="https://www.tooljet.com/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; for a free ToolJet cloud account or &lt;a href="https://docs.tooljet.com/docs/setup/try-tooljet/" rel="noopener noreferrer"&gt;run ToolJet on your local machine&lt;/a&gt; using Docker.&lt;/li&gt;
&lt;li&gt;  Basics of JavaScript: Basic knowledge of JavaScript can be handy for implementing dynamic functionality in your ToolJet applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up the ToolJet Database
&lt;/h2&gt;

&lt;p&gt;This section will teach you how to set up the database for our CRM app. We will be using &lt;strong&gt;ToolJet Database&lt;/strong&gt; for this application.  &lt;/p&gt;

&lt;p&gt;Log in to your ToolJet account and click on the ToolJet Database icon in the left sidebar. We will be creating two tables, one will be for the &lt;em&gt;&lt;strong&gt;sales_revenue&lt;/strong&gt;&lt;/em&gt; and other for &lt;em&gt;&lt;strong&gt;sales_executives&lt;/strong&gt;&lt;/em&gt;. Let's start by creating the database tables.  &lt;/p&gt;

&lt;p&gt;Create a new table with the following columns and rename it to &lt;em&gt;&lt;strong&gt;sales_revenue&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;id (primary key/auto-generated)&lt;/li&gt;
&lt;li&gt;course(varchar)&lt;/li&gt;
&lt;li&gt;number_of_courses_sold (int)&lt;/li&gt;
&lt;li&gt;discount (varchar)&lt;/li&gt;
&lt;li&gt;customer_name (int)&lt;/li&gt;
&lt;li&gt;customer_email (varchar)&lt;/li&gt;
&lt;li&gt;customer_country (varchar)&lt;/li&gt;
&lt;li&gt;customer_age_group (int)&lt;/li&gt;
&lt;li&gt;revenue  (int)&lt;/li&gt;
&lt;li&gt;se_name (varchar)&lt;/li&gt;
&lt;li&gt;profession (varchar)&lt;/li&gt;
&lt;li&gt;sale_date (varchar)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a new table with the following columns and rename it to &lt;strong&gt;&lt;em&gt;sales_executives&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;id (primary key/auto-generated)&lt;/li&gt;
&lt;li&gt;name(varchar)&lt;/li&gt;
&lt;li&gt;email (varchar)&lt;/li&gt;
&lt;li&gt;phone (varchar)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We recommend adding some dummy data to the table so that we have something to work with when we begin the app development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI Development
&lt;/h2&gt;

&lt;p&gt;Once you are done setting up the database, click on the &lt;strong&gt;Apps&lt;/strong&gt; in the sidebar and create a new app with the name &lt;strong&gt;Ed-Tech Sales CRM&lt;/strong&gt;. After the successful creation of the App, you will land on the App-Bulider page.&lt;/p&gt;

&lt;p&gt;Now we can drag and drop ToolJet's pre-built components to build the app's UI quickly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0a51v03j5zu67jda3t4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0a51v03j5zu67jda3t4.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the structure of the app that we will be building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header&lt;/li&gt;
&lt;li&gt;Tabs

&lt;ul&gt;
&lt;li&gt;Overview&lt;/li&gt;
&lt;li&gt;Sales Executives&lt;/li&gt;
&lt;li&gt;Revenue&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Let us start will building the &lt;strong&gt;Header&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Drag and drop a &lt;a href="https://docs.tooljet.com/docs/widgets/container/" rel="noopener noreferrer"&gt;Container&lt;/a&gt; component on the canvas from the &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-components" rel="noopener noreferrer"&gt;components library&lt;/a&gt; on the right and rename it to &lt;em&gt;header&lt;/em&gt;. Containers are used to group related components in the App-Builder.&lt;/li&gt;
&lt;li&gt; Resize it and change its color to #2E425A and border radius to 8.&lt;/li&gt;
&lt;li&gt;  Inside the Container component, add two &lt;a href="https://docs.tooljet.com/docs/widgets/text" rel="noopener noreferrer"&gt;Text&lt;/a&gt; component for and rename it to &lt;em&gt;brandName&lt;/em&gt; and &lt;em&gt;CRMTitle&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt; In the &lt;em&gt;brandName&lt;/em&gt; component change the Data to &lt;strong&gt;TOOLJET&lt;/strong&gt; and change the color to white, font size to 20, font weight to bolder and letter spacing to 6.&lt;/li&gt;
&lt;li&gt; In &lt;em&gt;CRMTitle&lt;/em&gt; component, change the Data to &lt;strong&gt;Ed-Tech Sales CRM&lt;/strong&gt; and change the color to white, font size to 18. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlt6zglchrt0v0mgx95x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlt6zglchrt0v0mgx95x.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Renaming components can be useful as the application grows, allowing easy reference to component-related values throughout various parts of the application.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Drag and Drop the &lt;a href="https://docs.tooljet.com/docs/widgets/tabs/" rel="noopener noreferrer"&gt;Tabs&lt;/a&gt; component and change the tab names to &lt;strong&gt;Overview&lt;/strong&gt;, &lt;strong&gt;Sales Executives&lt;/strong&gt; and &lt;strong&gt;Revenue&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Revenue&lt;/strong&gt; tab, add a &lt;a href="https://docs.tooljet.com/docs/widgets/table/table-properties" rel="noopener noreferrer"&gt;Table&lt;/a&gt; component which will contain the data from the &lt;em&gt;&lt;strong&gt;sales_revenue&lt;/strong&gt;&lt;/em&gt; table in the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now add a &lt;a href="https://docs.tooljet.com/docs/widgets/modal/" rel="noopener noreferrer"&gt;Modal&lt;/a&gt; component, place it above the table, and rename it to &lt;em&gt;saleDetails&lt;/em&gt;. In properties change the title to &lt;strong&gt;Sale Details&lt;/strong&gt;, Trigger button label to &lt;strong&gt;Add sale&lt;/strong&gt; and change the color of button to primary color ( &lt;code&gt;#2E425A&lt;/code&gt; ).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvre20m2z5q6b70ufoy2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvre20m2z5q6b70ufoy2.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now we need to add input fields in this modal. Here we will be dividing the modal into two parts, first is &lt;strong&gt;Customer Details&lt;/strong&gt; and &lt;strong&gt;Revenue Details&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Customer Details&lt;/strong&gt;, add &lt;a href="https://docs.tooljet.com/docs/widgets/text-input/" rel="noopener noreferrer"&gt;Text Input&lt;/a&gt; component for &lt;strong&gt;Name&lt;/strong&gt; and &lt;strong&gt;Email&lt;/strong&gt;, Dropdown component for &lt;strong&gt;Country&lt;/strong&gt;, &lt;strong&gt;Course&lt;/strong&gt; and &lt;strong&gt;Sales Executive name&lt;/strong&gt;, Radio button component for the &lt;strong&gt;Age group&lt;/strong&gt; and &lt;strong&gt;profession&lt;/strong&gt; and a Date component for the &lt;strong&gt;Sale date&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the &lt;strong&gt;Country&lt;/strong&gt; dropdown you can add the following data in Option values and labels:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ ["Argentina", "Australia", "Brazil", "Canada", "China", "Egypt", "France", "Germany", "Greece", "India", "Indonesia", "Italy", "Japan", "Mexico", "Netherlands", "New Zealand", "Russia", "Saudi Arabia", "South Africa", "South Korea", "Spain", "Switzerland", "Thailand", "United Kingdom", "United States"]
}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; For the Courses dropdown you can add the following data in Option values and labels:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ ["Marketing Management", "Data Science Fundamentals", "Financial Accounting", "Introduction to Psychology", "Business Ethics", "Digital Marketing Strategy", "Creative Writing Workshop", "Computer Programming Basics", "Public Speaking Mastery", "Introduction to Economics", "Full Stack Web Development"]
}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For the &lt;strong&gt;Sales Executive&lt;/strong&gt; dropdown, we will be fetching data from the &lt;em&gt;&lt;strong&gt;sales_executives&lt;/strong&gt;&lt;/em&gt; table in the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here is the quick preview of &lt;em&gt;salesDetails&lt;/em&gt; modal UI, you can change the design at your convenience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytip4je8zxdrk9exv7ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytip4je8zxdrk9exv7ta.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In &lt;em&gt;salesDetails&lt;/em&gt; modal, as you can see we have the &lt;strong&gt;dynamic UI&lt;/strong&gt; elements that will show the values of &lt;strong&gt;Revenue without discount&lt;/strong&gt; and &lt;strong&gt;Total revenue generated&lt;/strong&gt; based on what they choose in &lt;strong&gt;Courses&lt;/strong&gt; &lt;em&gt;sold&lt;/em&gt; and &lt;strong&gt;Discounts&lt;/strong&gt; offered. The HEX color codes for both of these Text components are &lt;code&gt;#4A90E2&lt;/code&gt; and &lt;code&gt;#9013FE&lt;/code&gt; respectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To build these dynamic text elements we need to add &lt;strong&gt;on change&lt;/strong&gt; event handlers on &lt;strong&gt;Courses sold&lt;/strong&gt; and &lt;strong&gt;Discounts offered&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will run a script that will calculate both of these revenues and then will populate those details in the Text components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the Query Manager and add a Javascript query. Name it &lt;strong&gt;updateRevenue&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the following code to this query. This will return the values that we can use in the &lt;strong&gt;Revenue without discount&lt;/strong&gt; and &lt;strong&gt;Total revenue generated&lt;/strong&gt; in UI respectively. Make sure you rename the number input component to &lt;em&gt;courses&lt;/em&gt; and the radio button component to &lt;em&gt;discount&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const revenue = components.courses.value * 2000 * (100 - components.discount.value) * 0.01
const revenueWithoutDiscount = components.courses.value * 2000

return {revenue, revenueWithoutDiscount}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-events" rel="noopener noreferrer"&gt;Events&lt;/a&gt; in ToolJet are used to run queries, show alerts, and other functionalities based on triggers such as button clicks or query completion&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Update the Data property of the &lt;strong&gt;Revenue without discount&lt;/strong&gt; text component: &lt;code&gt;{{queries.updateRevenue.data.revenueWithoutDiscount ? queries.updateRevenue.data.revenueWithoutDiscount : 0}}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update the Data property of the Total revenue generated text component: &lt;code&gt;{{queries.updateRevenue.data.revenue ? queries.updateRevenue.data.revenue : 0}}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsy5hjuyxp8h1xfzu9lqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsy5hjuyxp8h1xfzu9lqe.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once you do these updates, just add &lt;strong&gt;on change&lt;/strong&gt; and &lt;strong&gt;on select&lt;/strong&gt; event handlers in &lt;strong&gt;Course sold&lt;/strong&gt; number input and &lt;strong&gt;Discount offered&lt;/strong&gt; radio button input respectively and add &lt;strong&gt;updateRevenue&lt;/strong&gt; query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Sales executive&lt;/strong&gt; tab also, we will be adding a modal and a table, so drag and drop both of these components in the tab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change the modal size to small and height to 300px. Also change the color of trigger button to &lt;code&gt;#2E425A&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now add three text components for &lt;strong&gt;Name&lt;/strong&gt;, &lt;strong&gt;Email&lt;/strong&gt; and &lt;strong&gt;Phone&lt;/strong&gt; and a submit button in the modal. Change the color of submit button to &lt;code&gt;#2E425A&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk942srsx87ut0xdnr0mh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk942srsx87ut0xdnr0mh.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the &lt;strong&gt;Overview&lt;/strong&gt; tab, add three &lt;a href="https://docs.tooljet.com/docs/widgets/statistics/" rel="noopener noreferrer"&gt;Statistics&lt;/a&gt; components. Hide the secondary value and change the primary color to &lt;code&gt;#F28585&lt;/code&gt; for all three components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the primary value labels to &lt;strong&gt;Total revenue&lt;/strong&gt;, &lt;strong&gt;Total courses&lt;/strong&gt;, and &lt;strong&gt;Total customers&lt;/strong&gt;. Keep the primary values as default for now. We will be update it later once we add the data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now add seven &lt;a href="https://docs.tooljet.com/docs/widgets/chart/" rel="noopener noreferrer"&gt;Chart&lt;/a&gt; components from the component library. Set the chart type to pie for five of them and to bar for the remaining two.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change the background color of all the charts to &lt;code&gt;#F1F4FC&lt;/code&gt;. For the two bar charts, set the marker color to &lt;code&gt;#2A77B4&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0bmxvi5idneixhj7yn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0bmxvi5idneixhj7yn5.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbel39oic5t6nqfk78ah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbel39oic5t6nqfk78ah.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have completed building UI, now let's quickly create queries and add functionality to our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Fetching
&lt;/h2&gt;

&lt;p&gt;With ToolJet, we can easily connect the UI elements to the data sources and fetch data by &lt;a href="https://docs.tooljet.com/docs/tooljet-concepts/what-are-queries/" rel="noopener noreferrer"&gt;creating queries&lt;/a&gt; in the Query Manager.&lt;/p&gt;

&lt;p&gt;We will be adding queries for &lt;strong&gt;Revenue&lt;/strong&gt;, &lt;strong&gt;Sales Executive&lt;/strong&gt; and &lt;strong&gt;Overview&lt;/strong&gt; tabs. We will start with &lt;strong&gt;Sales Executive&lt;/strong&gt; tab, as we will need that data in the modal for adding sales in the revenue tab.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Sales Executive Tab
&lt;/h3&gt;

&lt;p&gt;Here, we will need two queries, one will be to add the data to the database and one will be to show the data in the table.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open the &lt;strong&gt;Query Manager&lt;/strong&gt; at the bottom, click on &lt;strong&gt;Add&lt;/strong&gt;, and then click on the &lt;strong&gt;ToolJet database&lt;/strong&gt;. Rename the query to &lt;strong&gt;getSalesExecutives&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the table name as &lt;strong&gt;&lt;em&gt;sales_executives&lt;/em&gt;&lt;/strong&gt; and operation as &lt;strong&gt;List rows&lt;/strong&gt;. In settings, turn on &lt;strong&gt;Run this query on application load?&lt;/strong&gt; toggle to run this query every time the app reloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you are done with this, you can click on &lt;strong&gt;Preview&lt;/strong&gt; to check the data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let's link this query to the table. Click on table and add &lt;code&gt;{{queries.getSalesExecutives.data}}&lt;/code&gt; in the data. You will see your data from the database in the UI.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we need to add another query to add the data in sales_executives from the modal component.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;strong&gt;Add&lt;/strong&gt; in the Query Manger and then click on the &lt;strong&gt;ToolJet database&lt;/strong&gt;. Rename the query to &lt;strong&gt;addSalesExecutive&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the table name as &lt;strong&gt;&lt;em&gt;sales_executives&lt;/em&gt;&lt;/strong&gt; and operation as &lt;strong&gt;Create row&lt;/strong&gt;. Then select &lt;strong&gt;name&lt;/strong&gt;, &lt;strong&gt;email&lt;/strong&gt; and &lt;strong&gt;phone&lt;/strong&gt; in the column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now we need to add the data from UI to these columns in the keys input. Add &lt;code&gt;{{components.seName.value}}&lt;/code&gt;, &lt;code&gt;{{components.seEmail.value}}&lt;/code&gt;, &lt;code&gt;{{components.sePhone.value}}&lt;/code&gt; in the respective columns in the keys input.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here &lt;em&gt;seName&lt;/em&gt;, &lt;em&gt;seEmail&lt;/em&gt; and &lt;em&gt;sePhone&lt;/em&gt; are the component names. Make sure you rename them before adding them to the query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the modal and select the submit button. In properties, click on &lt;strong&gt;New event handler&lt;/strong&gt; and add &lt;strong&gt;on click&lt;/strong&gt; event, select action as &lt;strong&gt;Run query&lt;/strong&gt; and select the &lt;strong&gt;addSalesExecutive&lt;/strong&gt; query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The last thing we need to add is the event handlers in the query. You can add these three events - close modal, success prompt and run &lt;strong&gt;getSalesExecutives&lt;/strong&gt; query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try adding the data in the inputs components and submit it. You will see the that data populating in the table.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Revenue Tab
&lt;/h3&gt;

&lt;p&gt;In this tab also, we will be needing two queries, one will be to add the data to the database and one will be to show the data in the table.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open the &lt;strong&gt;Query Manager&lt;/strong&gt; at the bottom, click on &lt;strong&gt;Add&lt;/strong&gt;, and then click on &lt;strong&gt;Run Javascript code&lt;/strong&gt;. Rename the query to &lt;strong&gt;getRevenueDetails&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the table name as &lt;strong&gt;&lt;em&gt;sale_revenue&lt;/em&gt;&lt;/strong&gt; and operation as &lt;strong&gt;List rows&lt;/strong&gt;. In settings, turn on &lt;em&gt;&lt;strong&gt;R&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;un this query on application load?&lt;/strong&gt; toggle to run this query every time the app reloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you are done with this, you can click on &lt;strong&gt;Preview&lt;/strong&gt; to check the data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let's link this query to the table. Click on table and add &lt;code&gt;{{queries.getRevenueDetails.data}}&lt;/code&gt; in the data. You will see your data from the database in the UI.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we need to add another query to add the data in sale_revenue from the Modal component.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;strong&gt;Add&lt;/strong&gt; in the Query Manger and then click on the &lt;strong&gt;ToolJet database&lt;/strong&gt;. Rename the query to &lt;strong&gt;addRevenueDetails&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the table name as &lt;strong&gt;&lt;em&gt;sale_revenue&lt;/em&gt;&lt;/strong&gt; and operation as &lt;strong&gt;Create row&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add and the columns and then add the data from UI to these columns in the keys input. Add &lt;code&gt;{{components.name.value}}&lt;/code&gt;, &lt;code&gt;{{components.email.value}}&lt;/code&gt; and all other items from the modal based on names you have added for all the input components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the modal and select the submit button. In properties, click on &lt;strong&gt;New event handler&lt;/strong&gt; and add &lt;strong&gt;on click&lt;/strong&gt; event, select action as &lt;strong&gt;Run query&lt;/strong&gt; and select the &lt;strong&gt;addRevenueDetails&lt;/strong&gt; query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can add these three events - close modal, success prompt, and run &lt;strong&gt;getRevenueDetails&lt;/strong&gt; to your query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try adding the data in the inputs and submit it. You will see that data populating in the table.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Overview Tab
&lt;/h3&gt;

&lt;p&gt;In this tab, we will be calculating all the data to be added in all the Chart and Statistics components using Javascript.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open on the &lt;strong&gt;Query Manger&lt;/strong&gt; at the bottom, click on &lt;strong&gt;Add&lt;/strong&gt; and then click on &lt;strong&gt;Run Javascript code&lt;/strong&gt;. Rename it to &lt;strong&gt;analytics&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can paste the following code which calculates all the data that you can put inside of all the charts and statistics components.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await queries.getRevenueDetails.run(); 

let data = queries.getRevenueDetails.getData(); 

const totalRevenue = data.reduce((acc, obj) =&amp;gt; acc + obj.revenue, 0);
const totalCourseSold = data.reduce((acc, obj) =&amp;gt; acc + obj.number_of_courses_sold, 0);
const totalCustomers = Array.from(new Set(data.map(obj =&amp;gt; obj.customer_email))).length


const countryCounts = data.reduce((counts, obj) =&amp;gt; {
  counts[obj.customer_country] = (counts[obj.customer_country] || 0) + 1;
  return counts;
}, {});

const customerCountryData = Object.keys(countryCounts).map(state =&amp;gt; ({ x: state, y: countryCounts[state] }));

const ageRangeCounts = data.reduce((counts, obj) =&amp;gt; {
  counts[obj.customer_age_group] = (counts[obj.customer_age_group] || 0) + 1;
  return counts;
}, {});

const ageRangeData = Object.keys(ageRangeCounts).map(state =&amp;gt; ({ x: state, y: ageRangeCounts[state] }));

const discountCounts = data.reduce((counts, obj) =&amp;gt; {
  counts[obj.discount] = (counts[obj.discount] || 0) + 1;
  return counts;
}, {});

const discountData = Object.keys(discountCounts).map(state =&amp;gt; ({ x: state, y: discountCounts[state] }));

const professionCounts = data.reduce((counts, obj) =&amp;gt; {
  counts[obj.profession] = (counts[obj.profession] || 0) + 1;
  return counts;
}, {});

const professionData = Object.keys(professionCounts).map(state =&amp;gt; ({ x: state, y: professionCounts[state] }));


const courseCounts = data.reduce((counts, obj) =&amp;gt; {
  if (obj.course) {
    counts[obj.course] = (counts[obj.course] || 0) + 1;
  }
  return counts;
}, {});


const courseData = Object.keys(courseCounts).map(course =&amp;gt; ({ x: course, y: courseCounts[course] }));

const revenueByExecutive = data.reduce((acc, obj) =&amp;gt; {
  if (obj.se_name) {
    acc[obj.se_name] = (acc[obj.se_name] || 0) + (obj.revenue || 0);
  }
  return acc;
}, {});


const teamData = Object.keys(revenueByExecutive).map(executive =&amp;gt; ({ x: executive, y: revenueByExecutive[executive] }));

// Aggregate revenue by year
const revenueByYear = data.reduce((acc, entry) =&amp;gt; {
    const year = parseInt(entry.sale_date.split('/')[2]);
    if (!acc[year]) {
        acc[year] = 0;
    }
    acc[year] += entry.revenue;
    return acc;
}, {});

// Format the data
const yearRevenueData = Object.entries(revenueByYear).map(([year, revenue]) =&amp;gt; {
    return {
        y: revenue.toString(),
        x: parseInt(year)
    };
});

// Sort the data by year (y) in increasing order
yearRevenueData.sort((a, b) =&amp;gt; a.y - b.y);



return {totalRevenue, totalCourseSold, totalCustomers, courseData, teamData, customerCountryData, ageRangeData, discountData, professionData, yearRevenueData};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can preview and check the data. Now we will be connecting the query to all the components in this tab.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Total Revenue&lt;/strong&gt; component and add &lt;code&gt;{{queries.analytics.data.totalRevenue}}&lt;/code&gt; in the Primary value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Total Course&lt;/strong&gt; component and add &lt;code&gt;{{queries.analytics.data.totalCourseSold}}&lt;/code&gt; in the Primary value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Total Customers&lt;/strong&gt; component and add &lt;code&gt;{{queries.analytics.data.totalCustomers}}&lt;/code&gt; in the Primary value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Customer location&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.customerCountryData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Courses&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.courseData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Age range&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.ageRangeData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Team revenue&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.teamData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Profession&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.professionData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Discounts&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.discountData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Year Vs Revenue&lt;/strong&gt; chart component and add &lt;code&gt;{{queries.analytics.data.yearRevenueData}}&lt;/code&gt; in the chart data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you are done connecting all queries to your components, turn on &lt;strong&gt;Run this query on application load?&lt;/strong&gt; toggle in the settings, to run this query every time the app reloads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijwk1uvmym4wk9mqbl21.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijwk1uvmym4wk9mqbl21.gif" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations, your Ed-tech sales CRM application is now fully functional! By leveraging Tooljet and the ToolJet Database, you've created a powerful and efficient CRM tailored to the unique needs of the Ed-tech industry. Your application can now effectively manage leads, track sales activities, and analyze performance metrics, all within a user-friendly interface.&lt;/p&gt;

&lt;p&gt;We hope this guide has been helpful and inspires you to explore further capabilities and integrations with ToolJet. To continue exploring, check out the official &lt;a href="https://docs.tooljet.com/docs/" rel="noopener noreferrer"&gt;ToolJet docs&lt;/a&gt; or connect on &lt;a href="https://tooljet.com/slack" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; for queries and doubt-solving.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tooljet</category>
      <category>lowcode</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
