How I built my first AI project for a couple of hours
Tags: ai, development, webdev, openai
Published: 2023-06-20 15:07:20

Artificial Intelligence is here probably for ever. It becomes more and more widespread and usual, like personal computers or smartphones. And we won’t be able to imagine our lives without it very soon. To use it as a developer in your projects becomes incredibly easy too. I developed a simple tool using the OpenAI NPM package, and I’m going to share my approach. Let’s go.

### Idea

The main idea is pretty simple. I saw that many people on Twitter share their achievements, like MRR, subscribers numbers, or progress like lists, with emojis. For example:

🧚‍♂️ be fairy
👑 be gorgeous
🦄 be unique
🐳 be a whale
🦧 be funny

I decided to create a tool that looks for appropriate emoji according to text provided.

### Implementation

Let’s start from the backend. I’m using Node.js so first of all I need to install [OpenAI npm package](https://www.npmjs.com/package/openai). Then to use the package you need to obtain your API-key from [open AI website](https://platform.openai.com/account/api-keys). 
When you finish all the preparation it’s time to get you hands dirty. Init OpenAI package:

```jsx
const { Configuration, OpenAIApi } = require('openai');
// Replace YOUR_API_KEY with your actual OpenAI API key
const API_KEY = process.env.OPENAI_API_KEY;
// Replace MODEL_ID with the ID of the model you want to use
// we are gonna use the chat completion functions so the following model id
// works there properly. Check in the API documentation if a model you wanna try
// works with selected API functions.
const MODEL_ID = 'gpt-3.5-turbo';
const configuration = new Configuration({
	apiKey: API_KEY,
});
const openai = new OpenAIApi(configuration);
```

When we initialised the OpenAI object, we can call the API then:

```jsx
const completion = await openai.createChatCompletion({
	model: MODEL_ID,
	messages: [{ "role": "user", "content": `generate exactly 5 funny and playful emojis for each paragraph of the input following the meaning of them. 
  Return it as JSON with an array of non empty strings containing exactly one emoji arrays.
  It shoudln't contain any additional keys in JSON. Only array of arrays. 
  Length of the array should be equal to ${count}. 
  No additional texts or explanations or extra array entities.
  The input: "${input.trim()}"` }]
});
const output = completion.data.choices[0].message.content;
```

I tried to use [Edits API](https://platform.openai.com/docs/api-reference/edits) first, but the result was not really predictable so I switched to ChatCompletion. It’s not perfect, but responses much more suitable.
Our output should look like a stringified JSON, but sometimes the AI returns not really expected response. So we need to be sure that we have a plan B if it could not be parsed properly.

```jsx
let outputArray = [];
try {
  outputArray = JSON.parse(output
    .replaceAll(' ', '')
    .replaceAll('\n', '')
    .replaceAll('],]', ']]')
    .match(/\[(.|\n)*\]/g)[0] // get only array. There might be other info generated
    .trim()
  );
  outputArray = outputArray.map(arr => {
    if (arr.length) return arr;
    return getNRandomEmojis(5); // there might be an empty array
  });

  while (outputArray.length < input.length) {
    outputArray.push(getNRandomEmojis(5)); // length of any array might be less then we expeced (5)
  }
} catch (e) {
  console.error(e);
  const paragrapthsLength = input.length;
  for (let i = 0; i < paragrapthsLength; i++) { // just generate random emojis as a backup
    outputArray.push(getNRandomEmojis(5));
  }
}
```


Now let’s summarise everything we did and combine it into one file. The full code of the service looks as below.

```jsx
async generateResponse(input) {
  // Replace YOUR_API_KEY with your actual OpenAI API key
  const API_KEY = process.env.OPENAI_API_KEY;
  // Replace MODEL_ID with the ID of the model you want to use
  // we are gonna use the chat completion functions so the following model id
  // works there properly. Check in the API documentation if a model you wanna try
  // works with selected API functions.
  const MODEL_ID = 'gpt-3.5-turbo';

  const configuration = new Configuration({
    apiKey: API_KEY,
  });
  const openai = new OpenAIApi(configuration);
  
  const inputStringified = input.map(inp => inp.val.trim()).join('\n');

  const completion = await openai.createChatCompletion({
    model: MODEL_ID,
    messages: [{ "role": "user", "content": getMessageContent(inputStringified, input.length) }]
  });

  const output = completion.data.choices[0].message.content;

  let outputArray = [];
  try {
    outputArray = JSON.parse(output
      .replaceAll(' ', '')
      .replaceAll('\n', '')
      .replaceAll('],]', ']]')
      .match(/\[(.|\n)*\]/g)[0] // get only array. There might be other info generated
      .trim()
    );
    outputArray = outputArray.map(arr => {
      if (arr.length) return arr;
      return getNRandomEmojis(5);
    });

    while (outputArray.length < input.length) {
      outputArray.push(getNRandomEmojis(5));
    }
  } catch (e) {
    console.error(e);
    const paragrapthsLength = input.length;
    for (let i = 0; i < paragrapthsLength; i++) {
      outputArray.push(getNRandomEmojis(5));
    }
  }

  return outputArray;
}

function getMessageContent(input, count) {
  return `generate exactly 5 funny and playful emojis for each paragraph of the input following the meaning of them. 
  Return it as JSON with an array of non empty strings containing exactly one emoji arrays.
  It shoudln't contain any additional keys in JSON. Only array of arrays. 
  Length of the array should be equal to ${count}. 
  No additional texts or explanations or extra array entities.
  The input: "${input.trim()}"`;
}

function getNRandomEmojis(n) {
  const res = [];
  for (let i = 0; i < n; i++) {
    res.push(getRandomEmoji());
  }
  return res;
}

function getRandomEmoji() {
  const emojis = [
    '😄', '😃', '😀', '😊', '😔', '😉', '😍', '😘', '😚', '😗', '😙', '😜', '😝', '😛', '😳', '😁', '😔', '😌', '😒', '😞', '😣', '😢', '😂', '😭', '😪', '😥', '😰', '😅', '😓', '😩', '😫', '😨', '😱', '😠', '😡', '😤', '😖', '😆', '😋', '😷', '😎', '😴', '😵', '😲', '😟', '😦', '😧', '😈', '👿', '😮', '😬', '😐', '😕', '😯', '😶', '😇', '😏', '😑', '👲', '👳', '👮', '👷', '💂', '👶', '👦', '👧', '👨', '👩', '👴', '👵', '👱', '👼', '👸', '😺', '😸', '😻', '😽', '😼', '🙀', '😿', '😹', '😾', '👹', '👺', '🙈', '🙉', '🙊', '💀', '👽', '💩', '🔥', '✨', '🌟', '💫', '💥', '💢', '💦', '💧', '💤', '💨', '👂', '👀', '👃', '👅', '👄', '👍', '👎', '👌', '👊', '✊', '✌', '👋', '✋', '👐', '👆', '👇', '👉', '👈', '🙌', '🙏', '☝', '👏', '💪', '🚶', '🏃', '💃', '👫', '👪', '👬', '👭', '💏', '💑', '👯', '🙆', '🙅', '💁', '🙋', '💆', '💇', '💅', '👰', '🙎', '🙍', '🙇', '🎩', '👑', '👒', '👟', '👞', '👡', '👠', '👢', '👕', '👔', '👚', '👗', '🎽', '👖', '👘', '👙', '💼', '👜', '👝', '👛', '👓', '🎀', '🌂', '💄', '💛', '💙', '💜', '💚', '❤', '💔', '💗', '💓', '💕', '💖', '💞', '💘', '💌', '💋', '💍', '💎', '👤', '👥', '💬', '👣', '💭', '🐶', '🐺', '🐱', '🐭', '🐹', '🐰', '🐸', '🐯', '🐨', '🐻', '🐷', '🐽', '🐮', '🐗', '🐵', '🐒', '🐴', '🐑', '🐘', '🐼', '🐧', '🐦', '🐤', '🐥', '🐣', '🐔', '🐍', '🐢', '🐛', '🐝', '🐜', '🐞', '🐌', '🐙', '🐚', '🐠', '🐟', '🐬', '🐳', '🐋', '🐄', '🐏', '🐀', '🐃', '🐅', '🐇', '🐉', '🐎', '🐐', '🐓', '🐕', '🐖', '🐁', '🐂', '🐲', '🐡', '🐊', '🐫', '🐪', '🐆', '🐈', '🐩', '🐾', '💐', '🌸', '🌷', '🍀', '🌹', '🌻', '🌺', '🍁', '🍃', '🍂', '🌿', '🌾', '🍄', '🌵', '🌴', '🌲', '🌳', '🌰', '🌱', '🌼', '🌐', '🌞', '🌝', '🌚', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌜', '🌛', '🌙', '🌍', '🌎', '🌏', '🌋', '🌌', '🌠', '⭐', '☀', '⛅', '☁', '⚡', '☔', '❄', '⛄', '🌀', '🌁', '🌈', '🌊', '🎍', '💝', '🎎', '🎒', '🎓', '🎏', '🎆', '🎇', '🎐', '🎑', '🎃', '👻', '🎅', '🎄', '🎁', '🎋', '🎉', '🎊', '🎈', '🎌', '🔮', '🎥', '📷', '📹', '📼', '💿', '📀', '💽', '💾', '💻', '📱', '☎', '📞', '📟', '📠', '📡', '📺', '📻', '🔊', '🔉', '🔈', '🔇', '🔔', '🔕', '📢', '📣', '⏳', '⌛', '⏰', '⌚', '🔓', '🔒', '🔏', '🔐', '🔑', '🔎', '💡', '🔦', '🔆', '🔅', '🔌', '🔋', '🔍', '🛁', '🛀', '🚿', '🚽', '🔧', '🔩', '🔨', '🚪', '🚬', '💣', '🔫', '🔪', '💊', '💉', '💰', '💴', '💵', '💷', '💶', '💳', '💸', '📲', '📧', '📥', '📤', '✉', '📩', '📨', '📯', '📫', '📪', '📬', '📭', '📮', '📦', '📝', '📄', '📃', '📑', '📊', '📈', '📉', '📜', '📋', '📅', '📆', '📇', '📁', '📂', '✂', '📌', '📎', '✒', '✏', '📏', '📐', '📕', '📗', '📘', '📙', '📓', '📔', '📒', '📚', '📖', '🔖', '📛', '🔬', '🔭', '📰', '🎨', '🎬', '🎤', '🎧', '🎼', '🎵', '🎶', '🎹', '🎻', '🎺', '🎷', '🎸', '👾', '🎮', '🃏', '🎴', '🀄', '🎲', '🎯', '🏈', '🏀', '⚽', '⚾', '🎾', '🎱', '🏉', '🎳', '⛳', '🚵', '🚴', '🏁', '🏇', '🏆', '🎿', '🏂', '🏊', '🏄', '🎣', '☕', '🍵', '🍶', '🍼', '🍺', '🍻', '🍸', '🍹', '🍷', '🍴', '🍕', '🍔', '🍟', '🍗', '🍖', '🍝', '🍛', '🍤', '🍱', '🍣', '🍥', '🍙', '🍘', '🍚', '🍜', '🍲', '🍢', '🍡', '🍳', '🍞', '🍩', '🍮', '🍦', '🍨', '🍧', '🎂', '🍰', '🍪', '🍫', '🍬', '🍭', '🍯', '🍎', '🍏', '🍊', '🍋', '🍒', '🍇', '🍉', '🍓', '🍑', '🍈', '🍌', '🍐', '🍍', '🍠', '🍆', '🍅', '🌽', '🏠', '🏡', '🏫', '🏢', '🏣', '🏥', '🏦', '🏪', '🏩', '🏨', '💒', '⛪', '🏬', '🏤', '🌇', '🌆', '🏯', '🏰', '⛺', '🏭', '🗼', '🗾', '🗻', '🌄', '🌅', '🌃', '🗽', '🌉', '🎠', '🎡', '⛲', '🎢', '🚢', '⛵', '🚤', '🚣', '⚓', '🚀', '✈', '💺', '🚁', '🚂', '🚊', '🚉', '🚞', '🚆', '🚄', '🚅', '🚈', '🚇', '🚝', '🚋', '🚃', '🚎', '🚌', '🚍', '🚙', '🚘', '🚗', '🚕', '🚖', '🚛', '🚚', '🚨', '🚓', '🚔', '🚒', '🚑', '🚐', '🚲', '🚡', '🚟', '🚠', '🚜', '💈', '🚏', '🎫', '🚦', '🚥', '⚠', '🚧', '🔰', '⛽', '🏮', '🎰', '♨', '🗿', '🎪', '🎭', '📍', '🚩', '⬆', '⬇', '⬅', '➡', '🔠', '🔡', '🔤', '↗', '↖', '↘', '↙', '↔', '↕', '🔄', '◀', '▶', '🔼', '🔽', '↩', '↪', 'ℹ', '⏪', '⏩', '⏫', '⏬', '⤵', '⤴', '🆗', '🔀', '🔁', '🔂', '🆕', '🆙', '🆒', '🆓', '🆖', '📶', '🎦', '🈁', '🈯', '🈳', '🈵', '🈴', '🈲', '🉐', '🈹', '🈺', '🈶', '🈚', '🚻', '🚹', '🚺', '🚼', '🚾', '🚰', '🚮', '🅿', '♿', '🚭', '🈷', '🈸', '🈂', 'Ⓜ', '🛂', '🛄', '🛅', '🛃', '🉑', '㊙', '㊗', '🆑', '🆘', '🆔', '🚫', '🔞', '📵', '🚯', '🚱', '🚳', '🚷', '🚸', '⛔', '✳', '❇', '❎', '✅', '✴', '💟', '🆚', '📳', '📴', '🅰', '🅱', '🆎', '🅾', '💠', '➿', '♻', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '⛎', '🔯', '🏧', '💹', '💲', '💱', '©', '®', '™', '〽', '〰', '🔝', '🔚', '🔙', '🔛', '🔜', '❌', '⭕', '❗', '❓', '❕', '❔', '🔃', '🕛', '🕧', '🕐', '🕜', '🕑', '🕝', '🕒', '🕞', '🕓', '🕟', '🕔', '🕠', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '✖', '➕', '➖', '➗', '♠', '♥', '♣', '♦', '💮', '💯', '✔', '☑', '🔘', '🔗', '➰', '🔱', '🔲', '🔳', '◼', '◻', '◾', '◽', '▪', '▫', '🔺', '⬜', '⬛', '⚫', '⚪', '🔴', '🔵', '🔻', '🔶', '🔷', '🔸', '🔹'
  ];
  return emojis[Math.floor(Math.random() * emojis.length)];
}
```

Your front-end might look as you prefer. Example of mine is on the GIF

![Emoji generator result of work](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3232om44pspnnqjc346z.gif)

The tool itself - [Emoji Me](https://apps.fleexy.dev/tools/emoji)

### Instead of a conclusion.

It’s was a tiny example of an AI application for some routine automations, but it’s a step into very promising and intriguing AI world. There are so much interesting to discover so do it and enjoy.

---

If you like the article, follow me on social media ❤️

[Twitter](https://twitter.com/alexey_kramin)

[LinkedIn](https://www.linkedin.com/in/alexey-kramin-963243122/)