User Story EP1 : How Alex Built His First GPT Action from Scratch🎉
Tags: marscode, userstories, gptaction
Published: 2024-05-24 03:48:59

> This article comes from User @ Alex Liu,big shoutout to ALEX for an incredible share! 🌟
> Calling all users to join in and share your stories too! 📚
> We have awesome gifts worth up to $200 waiting for those with amazing tales to tell! 🎁

Recently, with some free time on my hands, I developed a cool GPT Action using MarsCode. It allows querying of information on popular GitHub projects. It's been quite enjoyable, so I thought I'd share my development process and insights.
<img width="100%" style="width:100%" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExY3Q5cTA4dDlrMml2Z29zN3FtMTMxMGlycm43bmxhY2R0b3RkY2NydSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/5ldlNWHkbAogvGfpfQ/giphy.gif" >

(_how it works↑_)


> About GPT Actions: You can think of them as handy little helpers powered by AI, capable of fetching all sorts of information for you. For more details, check out "[Actions in GPTs.](https://platform.openai.com/docs/actions/introduction)"
Developing GPT actions may require an IDE, deployment platform, and API testing tools, among others. That's why I opted for MarsCode – it offers a one-stop solution, allowing me to quickly create a development project and streamline the development of GPT Actions. 

Alright, let's take a look at my entire development process

### Step1: Designing GPT Actions
This is where you get to brainstorm what you want your GPT to do. For mine, I wanted it to scour GitHub Trending for hot projects based on programming language and time frame. Here's what I came up with for inputs and outputs:

- Inputs: the programming language to search for the time frame for the search (e.g., daily, weekly, monthly)
- Outputs: Project list, including project name, author, link, star count, and recent star increments.


### Step2: Setting Up the Project

MarsCode makes this part a breeze. With its variety of ready-to-use development frameworks and templates, I was spoilt for choice. Since I'm more comfortable with Node.js, I opted for the Node.js for AI Plugin template.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9m00krf1mqmt5utbfpzt.png)

(_Clicking on "Create," I swiftly entered the project space↑_)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqbontuy4rrvpza7mrvf.png)
(_The overall layout of MarsCode is quite similar to VS Code, so there wasn't much of a learning curve for me, as someone accustomed to using VS Code. BTW, I have to mention its theme – I really like it! It's a pity it's not open-source.😄↑_)



### Step3 Development
For anyone diving into this template for the first time, it's a smart move to give the README a thorough read. Since it's a template project, sticking to the presets is the way to go.  
In this template, each function file needs to export a function called handler that conforms to the following TypeScript definition:

```
export async function handler({ input, logger }: Args<Input>): Promise<Output> {
  const name = input.name || 'world';

  logger.info(`user name is ${name}`);

  return {
    message: `hello ${name}`
  };
}
```
When an HTTP request comes in, MarsCode executes this function and passes in input and logger. The logic for the action is written within the handler function, which provides several predefined TypeScript types:

- Args: The arguments passed to MarsCode when executing the handler, including input and logger.
- Input: The input of the HTTP request.
- logger: This logs information, including methods like [logger.info](https://logger.info/), logger.error, and logger.debug. These logs appear in the Runtime logs panel of the deployment dashboard and in the API Test's log panel.
- Output: The output of the function.

After grasping all that, I jumped right into coding. I created github/searchTrending.ts under the api directory to fetch GitHub Trending data. Here's how I broke it down into 2 steps:

1. Fetching GitHub Trending Page: I started by making a fetch request to https://github.com/trending to grab the page's HTML. Since MarsCode's Node.js version is v20.12.2, I could directly use fetch for network requests.
2. Parsing HTML with cheerio:  I had the HTML, I used cheerio to parse it and extract repo data like names, descriptions, and star counts.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xoz8bpbixq77dtdgzp31.png)
(_During the coding process, MarsCode AI Assistants were super helpful. They provided features like code auto-completion and generating code based on comments. The fields for the `GitHubRepo` interface were automatically inferred, making the whole process incredibly convenient. 😎↑_)


Once the dependencies are installed, we can dive into writing the core logic of the plugin:

```
async function searchTrending(input: Input): Promise<GitHubRepo[]> {
  let url = 'https://github.com/trending';
  // You can filter by language and time period
  if (input.language) {
    url += `/${input.language}`;
  }
  if (input.since) {
    url += `?since=${input.since}`;
  }

  try {
    // Fetch the HTML from GitHub Trending.
    const response = await fetch(url);
    const body = await response.text();
    // Parse the HTML with cheerio to extract project information.
    const $ = cheerio.load(body);
    // Initialize the list for repository info.
    let repositoriesInfo = [];

    // Iterate over all <article class="Box-row"> elements on the page.
    $('article.Box-row').each(function () {
      const article = $(this);
      // Extract data.
      const name = article.find('h2.h3 a').text().trim();
      const url = 'https://github.com' + article.find('h2.h3 a').attr('href');
      const author = article.find('span.text-normal').text().trim().replace(' /', '');
      const stars = article.find('a[href*="/stargazers"]').last().text().trim().replace(/,/g, ''); // Remove commas from numbers.
      const todayStarsText = article.find('.d-inline-block.float-sm-right').text().trim();
      const todayStarsMatch = todayStarsText.match(/(\d+)/);
      const todayStars = todayStarsMatch ? parseInt(todayStarsMatch[0], 10) : 0;
      const language = article.find('[itemprop="programmingLanguage"]').text().trim();
      const description = article.find('p.color-fg-muted').text().trim();  Extract repo description

      repositoriesInfo.push({
        description,
        language,
        name,
        url,
        author,
        stars,
        todayStars
      });
    });

    return repositoriesInfo;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
  return [];
}

Call the searchTrending function in the handler:
typescript
/**
 * Search the GitHub trending repos
 */
export async function handler({ input, logger }: Args<Input>): Promise<Output> {
  const projects = await searchTrending(input);

  return {
    projects,
  };
}
```
Now that we've wrapped up the main coding part, we can move on to testing this action. 🚀

### Step4: API test
<img width="100%" style="width:100%" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMDNvOXZyOTJheHFpM2Zjdjdqbnd0b29yanVibGlhcm0yMzZpMjdtOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/9jYv7PoaVGCEgDeW9A/giphy.gif" >

(_MarsCode offers a testing tool: API Test. In the API Test panel, you can input the parameters for the interface. Click "Send," and you can check the logs through the Output panel. 🔍↑_)


### Step5: Deployment

<img width="100%" style="width:100%" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExcGJydndwaXltY3pzY3EwaWc3a3Q1dzVrNzNzM2kwMm1ydm55YnNsbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/GvRHDkZf4Zbmt2mbeS/giphy.gif" >

(_Click the "Deploy" button at the top, enter the Changelog, and then click "Start." Your project will begin deploying, and you can monitor the deployment process through the logs. 🚀↑_)


<img width="100%" style="width:100%" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExemZpNXgxZGIyYWk3eHk4d3JnNDVmYmpmam50cThrYnp5azhvYWRjYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/zEs0MmGn3s5CxMtR6a/giphy.gif" >

(_After a successful deployment, you can view the service details through Service Detail. This includes the OpenAPI Schema, Bearer token, domain name, and more.↑_)


### Final Step
For details on how to add the action to your ChatGPT, there's a document from MarsCode team [Add an action to your ChatGPT](https://docs.marscode.com/tutorials/develop-cloud-functions#step-3-add-an-action-to-your-chatgpt).  I won't go into it here, but you can refer to that for a step-by-step guide. 📄🤖

### Some of my ideas
Even though this was my first time developing a GPT Action, I found MarsCode's custom solution pretty impressive overall. The process was smooth with hardly any hiccups. Moving forward, I'm considering developing more AI Bots to cover various other scenarios. If anyone has ideas, feel free to join in and let's create something awesome together! 🚀

FYI : https://github.com/L-mofeng/marscode-github-trending-action