Storyteller bot, or how to generate stories using ChatGPT and Telegram

Storyteller bot, or how to generate stories using ChatGPT and Telegram

Imagine that you need to write a fiction novel. You have the key ideas, the main turns of events are thought out, but there is no way to connect everything into one story.

It seems that writing an exciting story is simple. An idea appeared – write it down, a new thought came – write it down too. Then add details and emotions – and you’re done. But it is sometimes the last point that takes the most time.

The same problem can be encountered, for example, if you need to write a post or prepare a description of a work project. If you’re familiar with this, just automate the process. You can write a special bot that will generate a complete story from theses using ChatGPT, and then record it in Notion. It is not difficult to implement such a project and deploy it to the server – let’s see how to do it.



We create a Node.js program


First, let’s prepare the working environment and create a Node.js project:

npm init -y
npm i -D nodemon // для разработки 
npm i @notionhq/client config openai telegraf 

Then change the type field in package.json so that the project can work with import & export:

"type": "module",
"scripts": { 
    "dev": "nodemon ./src/main.js", 
    "start": "node ./src/main.js" 
},

Next, let’s create ./src/main.js:

import { Telegraf } from 'telegraf'
import { message } from 'telegraf/filters'
import config from 'config'

const bot = new Telegraf(config.get('TELEGRAM_TOKEN'), {
  handlerTimeout: Infinity,
})

bot.command('start', (ctx) =>
  ctx.reply(
    'Добро пожаловать. Отправьте текстовое сообщение с тезисами про историю.'
  )
)

bot.on(message('text'), ctx => {
 // тут будет логика приложения-интегратора
})

bot.launch()

We receive a token for the Telegram bot

The next step is to create a Telegram bot. This will require an API token, which can be obtained from

@BotFather

using the command / Newbot.

Next, we create a configuration in which we will place the token itself:

mkdir config 
touch default.json
{ 
"TELEGRAM_TOKEN": "ВАШ ТОКЕН ДЛЯ БОТА TELEGRAM", 
}

We write the ChatGPT logic

To start

we get a token

to work with OpenAI services, and then enter it into the configuration:

{ 
"TELEGRAM_TOKEN": "ВАШ ТОКЕН ДЛЯ БОТА TELEGRAM",
"OPENAI_KEY": "КЛЮЧ ДЛЯ РАБОТЫ С ChatGPT"
}

Now create the file ./src/chatgpt.js and write the script:

import OpenAI from 'openai'
import config from 'config'

const CHATGPT_MODEL = 'gpt-3.5-turbo'

const ROLES = {
  ASSISTANT: 'assistant',
  SYSTEM: 'system',
  USER: 'user',
}

const openai = new OpenAI({
  apiKey: config.get('OPENAI_KEY'),
})

const getMessage = (m) => `
  Напиши на основе этих тезисов последовательную эмоциональную историю: ${m}

  Эти тезисы с описание ключевых моментов дня. 
  Необходимо в итоге получить такую историю, чтобы я запомнил этот день и смог рассказать ее друзьям. Текст не должен быть больше 100 слов. Главное — чтобы были эмоции, правильная последовательность и учитывался контекст.
`

export async function chatGPT(message="") {
  const messages = [
    {
      role: ROLES.SYSTEM,
      content:
        'Ты опытный копирайтер, который пишет краткие эмоциональные статьи для соц сетей.',
    },
    { role: ROLES.USER, content: getMessage(message) },
  ]
  try {
    const completion = await openai.chat.completions.create({
      messages,
      model: CHATGPT_MODEL,
    })

    return completion.choices[0].message
  } catch (e) {
    console.error('Error while chat completion', e.message)
  }
}

Please note: we assign ChatGPT the role of copywriter for higher quality texts. And also set the initial message with instructions for the bot.

We integrate Notion

It’s time to integrate Notion – it’s necessary for this

get the key to the base

. As a result, we get two keys and a ready database. Add to the configuration:

{
  "TELEGRAM_TOKEN": "ВАШ ТОКЕН ДЛЯ БОТА TELEGRAM",
  "OPENAI_KEY": "КЛЮЧ ДЛЯ CHATGPT",
  "NOTION_KEY": "КЛЮЧ ДЛЯ ИНТЕГРАЦИИ",
  "NOTION_DB_ID": "ID БАЗЫ ДАННЫХ"
}

In the Notion database (inline database component), we specify the basic fields – name and date. In the application, create a separate file ./src/notion.js and add a script to it:

import { Client } from '@notionhq/client'
import config from 'config'

const notion = new Client({
  auth: config.get('NOTION_KEY'),
})

export async function create(short, text) {
  const dbResponse = await notion.pages.create({
    parent: { database_id: config.get('NOTION_DB_ID') },
    properties: {
      Name: {
        title: [
          {
            text: {
              content: short,
            },
          },
        ],
      },
      Date: {
        date: {
          start: new Date().toISOString(),
        },
      },
    },
  })

  return dbResponse
}

In order to write the text received from ChatGPT as page content, we add another script:

const pageResponse = await notion.blocks.children.append({
    block_id: dbResponse.id,
    children: [
      {
        object: 'block',
        type: 'paragraph',
        paragraph: {
          rich_text: [
            {
              type: 'text',
              text: {
                content: text,
              },
            },
          ],
        },
      },
    ],
  })

We create a Loader

Since the execution of the script takes time, we will show the user the process of loading the Loader. In the file ./src/loader.js we describe the logic of this object:

export class Loader {
  icons = [
    '🕐','🕑','🕒',
    '🕓','🕔','🕕',
    '🕖','🕗','🕘',
    '🕙','🕚','🕛',
  ]
  interval = null
  message = null

  constructor(ctx) {
    this.ctx = ctx
  }

  async show() {
    let index = 0
    this.message = await this.ctx.reply(this.icons[index])
    this.interval = setInterval(() => {
      index = index < this.icons.length - 1 ? index + 1 : 0
      this.ctx.telegram.editMessageText(
        this.ctx.chat.id,
        this.message.message_id,
        null,
        this.icons[index]
      )
    }, 500)
  }

  hide() {
    this.ctx.telegram.deleteMessage(this.ctx.chat.id, this.message.message_id)
    clearInterval(this.interval)
  }
}

Now we have a class that shows an animated clock. What’s next?

Putting it together: integration with Telegram

All preparatory work is done, it remains to assemble the “puzzle” into one script./src/main.js:

import { chatGPT } from './chatgpt.js'
import { create } from './notion.js'
import { Loader } from './loader.js'

// ============

bot.on(message('text'), proccessGPTResponse)

async function proccessGPTResponse(ctx) {
  try {
    const text = ctx.message.text
    if (!text.trim()) ctx.reply('Текст не может быть пустым')
    const loader = new Loader(ctx)
    loader.show()
    const response = await chatGPT(text)

    if (!response) return ctx.reply(`Ошибка с API. ${response}`)

    const notionResp = await create(text, response.content)
    loader.hide()
    ctx.reply(`Ваша страница: ${notionResp.url}`)
  } catch (e) {
    console.log(`Error while proccessing gpt response`, e.message)
  }
}

Done – the script is fully functional.

The user submits abstracts for the day, ChatGPT processes the request and the Loader is launched.

The bot generated and sent a story page.

Result.


Deploy the project to the server


To begin with, create an empty keep file in the config folder so that it remains in the Git space. And also create .gitignore:

.gitignore
node_modules 
.vscode 
config/default.json

Next, we create a repository on GitHub, go to the terminal, initialize the project, make a commit and download it:

git init
git add .
git commit -m "initial commit"
git remote add origin REPO_URL
git push -u origin master

Setting up the server and launching the project

The robot is now running on the computer. This is inconvenient if you want to record stories 24/7. After all, then you need to maintain uninterrupted operation of the computer and a constant connection to the Internet. Better move the bot to the cloud.

1. Let’s go to the section Cloud platform inside the control panel:

2. We create a server. Our program does not need a lot of power, so one vCPU core with a share of 20% and 512 MB of RAM will be enough:

3. Log in to the server through the console:

4. Update the system and install Git:

apt update
apt install git

5. Install Node.js – full instructions are available at

Selectel Academy

:

curl -o- <https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh> | bash
source ~/.bashrc 
nvm install 20 
nvm use 20 
npm -v 
node -v

6. Clone the GitHub repository and deploy the project:

git clone REPO_URL
cd PROJECT_FOLDER_NAME
npm i
touch config/default.json
nano config/default.json

7. Launch the project:

npm install pm2 -g
pm2 start ./src/main.js

Done – the bot is running on the server and generating stories.

Conclusion


In this instruction, we did not just make an interesting project, but studied the main stages of developing Telegram bots — from a simple script to deployment on the server. The acquired knowledge can be used when working with larger projects. Regardless of their complexity, Selectel has the appropriate configuration.

Other useful materials


Related posts