<?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>Forem: Anmol Agrawal</title>
    <description>The latest articles on Forem by Anmol Agrawal (@anmolagrwl).</description>
    <link>https://forem.com/anmolagrwl</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%2Fuser%2Fprofile_image%2F1171984%2F2c3116e2-fa2b-4695-bcee-de85c6dc4dc7.png</url>
      <title>Forem: Anmol Agrawal</title>
      <link>https://forem.com/anmolagrwl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/anmolagrwl"/>
    <language>en</language>
    <item>
      <title>Build a Jira comments summarizer app with OpenAI</title>
      <dc:creator>Anmol Agrawal</dc:creator>
      <pubDate>Tue, 07 Nov 2023 09:27:55 +0000</pubDate>
      <link>https://forem.com/atlassian/build-a-jira-comments-summarizer-app-with-openai-45k0</link>
      <guid>https://forem.com/atlassian/build-a-jira-comments-summarizer-app-with-openai-45k0</guid>
      <description>&lt;p&gt;In this tutorial, you will build a Forge app that integrates with OpenAI APIs to summarize comments in Jira issues. This app addresses the following challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a user goes through lots of comments in a Jira issue, it can be overwhelming and time-consuming. It may become difficult to keep track of important details or decisions made during the discussion.&lt;/li&gt;
&lt;li&gt;As more comments are added, it becomes harder to find the relevant information needed to take action on the issue at hand. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Before you begin
&lt;/h2&gt;

&lt;p&gt;Make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Jira Cloud instance where you can install and test your app.&lt;/li&gt;
&lt;li&gt;Basic knowledge of JavaScript, React and the &lt;a href="https://developer.atlassian.com//platform/forge/getting-started/"&gt;Forge platform&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A completed &lt;a href="https://developer.atlassian.com/platform/forge/build-a-hello-world-app-in-jira/"&gt;Build a Jira hello world app&lt;/a&gt;, to ensure that you have set up the Forge development environment.&lt;/li&gt;
&lt;li&gt;An OpenAI API key which you can obtain from the &lt;a href="https://platform.openai.com/docs/api-reference/introduction"&gt;OpenAI website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tutorial uses these components to build the app: &lt;a href="https://developer.atlassian.com/platform/forge/manifest-reference/modules/jira-issue-panel/"&gt;Jira Issue Panel module&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/manifest-reference/permissions/"&gt;Permissions&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/ui-kit-components/fragment/"&gt;Fragment&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/ui-kit-components/text/"&gt;Text&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/runtime-reference/fetch-api/"&gt;fetch API&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/runtime-reference/product-fetch-api/#contextual-methods"&gt;api.asApp()&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/runtime-reference/product-fetch-api/#requestjira"&gt;.requestJira()&lt;/a&gt;, &lt;a href="https://developer.atlassian.com/platform/forge/ui-kit-hooks-reference/#useproductcontext"&gt;useProductContext&lt;/a&gt;, and &lt;a href="https://developer.atlassian.com/platform/forge/ui-kit-hooks-reference/#usestate"&gt;useState()&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the app
&lt;/h2&gt;

&lt;p&gt;To view a summary of an issue's Jira comments, the user clicks the &lt;strong&gt;Summarizer&lt;/strong&gt; button on an issue page.&lt;br&gt;
The app displays an issue panel containing a summary of all the comments for the issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fsoCXsrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://developer.atlassian.com/platform/forge/images/forge-openai-app-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fsoCXsrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://developer.atlassian.com/platform/forge/images/forge-openai-app-demo.gif" alt="Jira summarizer app in action" width="600" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the source code for this demo here - &lt;a href="https://github.com/anmolagrwl/forge-ai-jira-comment-summariser"&gt;anmolagrwl/forge-ai-jira-comment-summariser&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How does the app work?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--niGo6z3y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.atlassian.com/platform/forge/images/forge-openai-app-diagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--niGo6z3y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.atlassian.com/platform/forge/images/forge-openai-app-diagram.png" alt="Jira summarizer high level diagram" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following the numbered points in the diagram:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user first requests the summary. In this case, it will be as simple as a User clicking a button to get the summary as shown in the above video.&lt;/li&gt;
&lt;li&gt;The Summarizer app will get all the comments in the particular Jira issue using the Jira API.&lt;/li&gt;
&lt;li&gt;The Summarizer app will then pass on the comments to OpenAI along with prompt to create summary.&lt;/li&gt;
&lt;li&gt;Once the app gets the summary, it is returned to the user and rendered in the UI.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Step 1: Create the app
&lt;/h2&gt;

&lt;p&gt;Once your development environment is set up, follow these steps to create an initial version of your app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the directory where you want to create the app. &lt;/li&gt;
&lt;li&gt;Create a new project by running the &lt;code&gt;forge create&lt;/code&gt; command in the terminal.&lt;/li&gt;
&lt;li&gt;Enter a name for your app when asked. For example, &lt;code&gt;summarizer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After you have done that, Forge prompts you to select a template to help you start building the app. In this case, select the category &lt;code&gt;UI kit&lt;/code&gt; and then the template &lt;code&gt;jira-issue-panel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Once the app is created, deploy it and see how the app looks. In the app directory inside the terminal, enter the command &lt;code&gt;forge deploy&lt;/code&gt; to deploy your app.&lt;/li&gt;
&lt;li&gt;Enter the command &lt;code&gt;forge install&lt;/code&gt; in terminal. You will be asked to provide the site in which you would like to install the app.&lt;/li&gt;
&lt;li&gt;After the app is installed, view the app in your Jira instance by opening any Jira issue. There you will see a new button and a new issue panel below &lt;strong&gt;Description&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Depending on your Jira site, you may see the name of your app in the menu, as pictured below, or you may see only its icon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fsoCXsrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://developer.atlassian.com/platform/forge/images/forge-openai-app-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fsoCXsrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://developer.atlassian.com/platform/forge/images/forge-openai-app-demo.gif" alt="Jira summarizer app in action" width="600" height="470"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Get all the comments of a Jira Issue via REST API
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Update the manifest to include the required permissions
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;manifest.yml&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;jira:issuePanel:&lt;/span&gt;
    &lt;span class="s"&gt;- key&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;summarizer-hello-world-panel&lt;/span&gt;
      &lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;summarizer&lt;/span&gt;
      &lt;span class="s"&gt;icon&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://developer.atlassian.com/platform/forge/images/icons/issue-panel-icon.svg&lt;/span&gt;
  &lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.run&lt;/span&gt;
&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scopes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;read:jira-work'&lt;/span&gt;
  &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api.openai.com'&lt;/span&gt;
&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your-app-id&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To call certain Jira APIs and external APIs, you need to give your app permission to do so. This is done by adding &lt;a href="https://developer.atlassian.com/platform/forge/manifest-reference/permissions/"&gt;scopes and external permissions&lt;/a&gt; to the app's &lt;a href="https://developer.atlassian.com/platform/forge/manifest-reference/"&gt;manifest.yml&lt;/a&gt; file. The app will call two APIs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/#api-rest-api-3-issue-issueidorkey-comment-get"&gt;Get issue comments API&lt;/a&gt; - As per the API documentation, &lt;code&gt;read:jira-work&lt;/code&gt; permission is required to call this API.&lt;/li&gt;
&lt;li&gt;OpenAI API - &lt;code&gt;external.fetch.backend&lt;/code&gt; is used to define external domains your Forge functions can talk to.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;jira:issuePanel&lt;/code&gt; module entry was added by the &lt;code&gt;jira-issue-panel&lt;/code&gt; template. You can learn more about this module &lt;a href="https://developer.atlassian.com/platform/forge/manifest-reference/modules/jira-issue-panel/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update index.jsx with the main top-level logic for your app
&lt;/h3&gt;

&lt;p&gt;The top level code calls other functions to interact with the Jira and Chat GPT APIs which youâ€™ll add as you work through the tutorial.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;index.jsx&lt;/em&gt;&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;import&lt;/span&gt; &lt;span class="nx"&gt;ForgeUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Fragment&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="nx"&gt;IssuePanel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useProductContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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;@forge/ui&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;api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetch&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;@forge/api&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;App&lt;/span&gt; &lt;span class="o"&gt;=&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="c1"&gt;// Getting the issue key in the context.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useProductContext&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;issueKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platformContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issueKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Getting all the comments of the issue key.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getComments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issueKey&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="nx"&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;Comments - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// ChatGPT prompt to get the summary&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Here is a sample data where all the comments of a jira issue is joined together: 
  "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;". I want to summarize this in a way that anybody can get an idea what's going on in this issue without going through all the comments. Create a summary or TLDR for this.`&lt;/span&gt;

  &lt;span class="c1"&gt;// OpenAI API call to get the summary.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;callOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&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="nx"&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;Summary - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&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;Fragment&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;Text&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;summary&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;/Text&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;/Fragment&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;IssuePanel&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;App&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="sr"&gt;/IssuePanel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the main part of the app, which contains the top level logic to call APIs and render the UI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app first imports the UI components and API methods that will be used in this app.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;run&lt;/code&gt; function is the first function that gets executed. This is handled in &lt;code&gt;manifest.yml&lt;/code&gt; by defining &lt;code&gt;index.run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;App()&lt;/code&gt; is then triggered. This is where all the magic happens:

&lt;ul&gt;
&lt;li&gt;Try to get the current issue key using &lt;a href="https://developer.atlassian.com/platform/forge/ui-kit-hooks-reference/#useproductcontext"&gt;useProductContext&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Then, try to get all the comments in the issue using the &lt;code&gt;getComments()&lt;/code&gt; method, which is defined later in this tutorial.&lt;/li&gt;
&lt;li&gt;After the comments are retrieved, create the prompt to be used by ChatGPT.&lt;/li&gt;
&lt;li&gt;Pass that prompt to OpenAI via an API call using &lt;code&gt;callOpenAI()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Return the results using the &lt;code&gt;Text&lt;/code&gt; component.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;h3&gt;
  
  
  Update index.jsx to call a Jira API to get all comments for this issue
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;index.jsx&lt;/em&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getComments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issueKey&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="c1"&gt;// API call to get all comments of Jira issue with key 'issueKey'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commentsData&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asApp&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;requestJira&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="s2"&gt;`/rest/api/3/issue/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;issueKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/comment`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Accept&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;application/json&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseData&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;commentsData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;jsonData&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;responseData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comments&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;extractedTexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="c1"&gt;// Extracting all texts in the comments into extractedTexts array&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;comment&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="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;comment&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="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contentItem&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;contentItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paragraph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;contentItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;contentItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textItem&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;textItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;textItem&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;extractedTexts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textItem&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="p"&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="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;extractedTexts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function calls the &lt;a href="https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/#api-rest-api-3-issue-issueidorkey-comment-get"&gt;Get issue comments API&lt;/a&gt; using the &lt;a href="https://developer.atlassian.com/platform/forge/runtime-reference/product-fetch-api/#contextual-methods"&gt;api.asApp()&lt;/a&gt; method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the app retrieves all the comments using the Jira API, try to extract only the texts from the comments and exclude other data like &lt;code&gt;created at&lt;/code&gt; and &lt;code&gt;author&lt;/code&gt;, and join all the comments together into a paragraph.&lt;/li&gt;
&lt;li&gt;Join all of the comments together into a paragraph and return it. The app will use this paragraph to construct the &lt;code&gt;prompt&lt;/code&gt; variable it sends to ChatGPT.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Integrate your app with OpenAI API
&lt;/h2&gt;

&lt;p&gt;Now that the app can retrieve all the comments in a Jira Issue via an API, the next step is to pass it to OpenAI API to get the summary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update index.jsx to call the ChatGPT API to summarize the comments
&lt;/h3&gt;

&lt;p&gt;In the previous step, you added the variable &lt;code&gt;prompt&lt;/code&gt;, then constructed a prompt using the comments and a command that tells OpenAI what to do with that data (in this case: summarize it). The code passes the &lt;code&gt;prompt&lt;/code&gt; variable to a function &lt;code&gt;callOpenAI&lt;/code&gt; which would call OpenAI API and return the results.&lt;/p&gt;

&lt;p&gt;Here is the code for the &lt;code&gt;callOpenAI&lt;/code&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;index.jsx&lt;/em&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callOpenAI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&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;choiceCount&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="c1"&gt;// OpenAI API endpoint&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://api.openai.com/v1/chat/completions`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Body for API call&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getOpenAPIModel&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;choiceCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// API call options&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;getOpenAPIKey&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;application/json&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;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;follow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// API call to OpenAI&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;fetch&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="nx"&gt;options&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&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;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;200&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;chatCompletion&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;firstChoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstChoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstChoice&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;content&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Chat completion response did not include any assistance choices.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`AI response did not include any choices.`&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;else&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;text&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;response&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="nx"&gt;result&lt;/span&gt; &lt;span class="o"&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Get OpenAI API key&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getOpenAPIKey&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPEN_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Get OpenAI model&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getOpenAPIModel&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// return 'gpt-4';&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the app makes a basic API call to OpenAI. You can learn more about this through their &lt;a href="https://platform.openai.com/docs/api-reference/introduction"&gt;documentation&lt;/a&gt;. The steps involved include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set the URL of the API to which the call will be made.&lt;/li&gt;
&lt;li&gt;Provide the details of the payload which consists of information about the GPT model to which the request will be made and the prompt containing the comments and command.&lt;/li&gt;
&lt;li&gt;Set the options that contains extra information like call method, authorisation headers and the payload in JSON format.&lt;/li&gt;
&lt;li&gt;Use Forge's &lt;a href="https://developer.atlassian.com/platform/forge/runtime-reference/fetch-api/"&gt;fetch&lt;/a&gt; method to make the API call. Then, parse through the response to get the text of summary that will be displayed in the Jira UI for that issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;getOpenAPIKey()&lt;/code&gt; function returns a Forge environment variable called &lt;code&gt;OPEN_API_KEY&lt;/code&gt;. Before running the app for the first time, set this environment variable to the OpenAI API key that is needed to interact with their APIs. To &lt;a href="https://go.atlassian.com/forge-environments"&gt;create an environment variable in Forge&lt;/a&gt;, enter the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge variables set --encrypt OPEN_API_KEY your-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--encrypt&lt;/code&gt; flag instructs Forge to store the variable in encrypted form.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Deploy your app
&lt;/h2&gt;

&lt;p&gt;Once all the above steps are done, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;forge deploy&lt;/code&gt; in the terminal again as the &lt;code&gt;manifest.yml&lt;/code&gt; file was updated.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;forge install --upgrade&lt;/code&gt; and select the installation to upgrade. If you have followed along with this tutorial, it should list the development environment for your Jira instance.&lt;/li&gt;
&lt;li&gt;Try out the app in your cloud instance. The first time you run it, Atlassian asks you for permission, for that app to access Jira comments and your user information.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Great job on finishing the tutorial on developing a Forge app with OpenAI! Take a moment to celebrate this impressive achievement. If you require any additional help, reach out to our &lt;a href="https://community.developer.atlassian.com/"&gt;developer community&lt;/a&gt;. Keep up the excellent work and continue to explore new opportunities for your apps using Forge and OpenAI technology.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://developer.atlassian.com/platform/forge/build-jira-comments-summarizer-with-openai/"&gt;Build a Jira comments summarizer app with OpenAI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>atlassian</category>
      <category>forge</category>
      <category>jira</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
