coding

Como automatizar a criação de Instagram Reels usando GPT da OpenAI

Escrito em 20 de dezembro de 2023 - 🕒 6 min. de leitura

Após criar um script Node.js para postar automaticamente Reels no Instagram e outro para gerar automaticamente miniaturas para Reels no Instagram, o que vem a seguir? Gerar automaticamente o conteúdo do vídeo, claro!

Neste post, vou mostrar como usar o GPT-3.5 da OpenAI para gerar o conteúdo de um vídeo tutorial de programação. Vou usar o mesmo script Node.js que usei nos posts anteriores, além de um create-react-app que será usado para digitar o código do tutorial gerado.

AI trabalhando
AI trabalhando

Engenharia de prompts

A primeira pergunta que tive que me fazer foi: como posso pedir ao GPT-3.5 para gerar um tutorial de programação? Quero dizer, não posso simplesmente pedir para ele gerar um tutorial de programação, certo? Preciso dar um contexto, alguma informação, algo com que ele possa trabalhar.

O futuro está aqui
O futuro está aqui

Nesta nova era de trabalhar com modelos de linguagem, é estranho que, se você quer que o modelo faça algo, você só precisa pedir. Então, comecei criando uma lista de coisas que eu queria que estivessem no vídeo, como:

  • Um título
  • Uma descrição
  • O próprio código
  • Uma lista de ideias que já usei antes
  • Uma lista de coisas a evitar

E então comecei a pensar em como eu poderia usar essa informação para pedir ao GPT-3.5 para gerar um tutorial de programação. Cheguei ao seguinte prompt:

Respire fundo, relaxe e pense analiticamente sobre o problema que está tentando resolver. Tenho um arquivo JSON para um script de um tutorial de programação em vídeo para Reels no Instagram, que se parece com isto: <EXEMPLO_JSON_AQUI> Por favor, use este modelo para gerar um novo script para um tutorial de programação em vídeo para Reels no Instagram. Evite usar as seguintes ideias: <IDEIAS_UTILIZADAS> E evite os seguintes tópicos: <TÓPICOS_A_EVITAR> Certifique-se de responder apenas com um arquivo JSON com a mesma estrutura do que eu te dei e nada mais.

Após elaborar este prompt, testei-o algumas vezes no ChatGPT, e parecia bom, mas como esperado, às vezes a saída não era um formato JSON válido, e foi então que aprendi sobre chamadas de função.

Function calling

Chamadas de função são uma nova funcionalidade da API da OpenAI que permite chamar uma função a partir do prompt, e isso ajuda a garantir que a saída do GPT seja o que você espera.

No meu caso, criei uma função chamada generateTutorialViaOpenAi que recebe o arquivo JSON com o script para o vídeo e retorna um novo arquivo JSON com o script para o vídeo.

const OpenAI = require('openai');

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const generateTutorialViaOpenAi = async (prompt) => {
  const schema = {
    type: 'object',
    required: ['commands', 'files', 'description'],
    properties: {
      description: {
        type: 'string',
        description: 'A nice and catchy description for the tutorial.',
      },
      commands: {
        type: 'string',
        description: 'A string with the code and commands to use for the tutorial. It must not be empty.',
      },
      files: {
        type: 'array',
        description: 'The list of files that are going to be used in the tutorial. One of them MUST be index.html',
        items: {
          type: 'object',
          description: 'A file that is going to be used in the tutorial',
          required: ['name', 'content'],
          properties: {
            name: {
              type: 'string',
              description: 'The name of the file',
            },
            content: {
              type: 'string',
              description: 'The content of the file. Should be empty for the file that is going to be typed from the script.',
            },
          },
        },
      },
    },
  };

  const reelsCommands = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo',
    messages: [
      { role: 'system', content: 'You are a helpful programming professor.' },
      { role: 'user', content: prompt },
    ],
    functions: [{ name: 'generate_tutorial', parameters: schema }],
    function_call: { name: 'generate_tutorial' },
  });

  return reelsCommands;
};

Como você pode ver, o objeto schema é a chave aqui, garantindo que a saída do GPT seja o que eu espero.

Gerando o vídeo

Agora que tenho um arquivo JSON gerado sob demanda pela OpenAI, preciso de alguma forma convertê-lo em um vídeo, e é aqui que o script Puppeteer.js entra em cena.

Não vou entrar em muitos detalhes aqui porque esta é, na verdade, a parte mais complexa, e merece seu próprio post um dia, mas em resumo, estou usando Puppeteer.js para abrir um navegador Chrome sem cabeçalho, carregar um aplicativo React, e usando react-ace para o destaque de código, então com Puppeteer.js estou digitando o código e tirando uma captura de tela da página e salvando-a como um arquivo PNG usando o ‘Page.screencastFrame’.

const allFrames = [];
const browser = await puppeteer.launch();
const [page] = await browser.pages();
const client = await page.target().createCDPSession();
client.on('Page.screencastFrame', async ({ data, sessionId }) => {
  await client.send('Page.screencastFrameAck', { sessionId });
  allFrames.push(data);
});

Depois disso, estou usando ffmpeg para converter os arquivos PNG em um vídeo.

const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('ffmpeg-static');
const ffprobe = require('ffprobe-static');

ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg.setFfprobePath(ffprobe.path);

const createVideoFromFrames = async (
  fps,
  frames,
  outputPath
) => {
  const tempOutput = `${outputPath}.temp`;
  await new Promise((resolve, reject) => {
    ffmpeg()
      .input(frames)
      .inputFPS(fps)
      .toFormat('mp4')
      .videoCodec('libx264')
      .videoBitrate('5000k')
      .addOption('-crf', '23')
      .addOption('-g', '30')
      .addOption('-profile:v', 'high')
      .addOption('-level', '4.0')
      .on('end', resolve)
      .on('error', reject)
      .save(tempOutput);
  });

  await new Promise((resolve, reject) => {
    ffmpeg(tempOutput)
      .fps(FPS)
      .on('end', resolve)
      .on('error', reject)
      .output(outputPath)
      .run();
  });
};

Juntando tudo

Agora que tenho todas as peças, só preciso uni-las. Criei um novo script Node.js que irá:

  • Gerar um novo arquivo JSON com o script para o vídeo
  • Gerar um novo vídeo com o script para o vídeo
  • Gerar uma nova miniatura para o vídeo
  • Postar o vídeo no Instagram Reels
const generateTutorialViaOpenAi = require('./generate-tutorial-via-openai');
const generateImageForPost = require('./generate-image-for-post');
const generateVideoForPost = require('./generate-video-for-post');
const postVideoToInstagramReels = require('./post-video-to-instagram-reels');
const prompt = require('./prompt');

const generateTutorial = async () => {
  const reelsCommands = await generateTutorialViaOpenAi(prompt);
  const { description, commands, files } = reelsCommands.data.choices[0].value;

  const outputPath = `./output/${Date.now()}`;
  const thumbnailPath = `${outputPath}/thumbnail.png`;
  const videoPath = `${outputPath}/video.mp4`;

  await generateImageForPost(
    './assets/background.png',
    './assets/foreground.png',
    description,
    thumbnailPath
  );

  await generateVideoForPost(commands, files, videoPath);

  await postVideoToInstagramReels(description, videoPath, thumbnailPath);
};

generateTutorial();

O código real que estou usando é um pouco mais complexo, mas essa é a ideia geral.

Prova de conceito

Claro que depois de fazer todo esse trabalho, eu tinha que testá-lo, então criei uma nova conta no Instagram que postará um novo tutorial todos os dias, e sempre evitará ideias e tópicos existentes, bem, pelo menos em teoria…

… mas a realidade acabou sendo que os tutoriais gerados não são tão bons, e não tenho certeza se é devido ao prompt que estou usando, ou devido ao próprio modelo, mas tenho certeza que é uma combinação de ambos. Por alguma razão, ele continua gerando os mesmos tutoriais, sempre relacionados a colorir coisas usando CSS.

Estive executando esta conta por 3 meses agora, e ela obteve apenas 38 seguidores até hoje e alcançou 466 contas nos últimos 30 dias, então não tenho certeza se vale a pena continuar com ela, mesmo que seja totalmente automatizada e o custo total até agora foi de apenas U$1.00.

Acho que a melhor abordagem aqui é uma híbrida, onde gero meus próprios scripts e uso meu código Node.js para gerar o vídeo e postá-lo no Instagram Reels, o que já automatiza muito do trabalho.

Conclusão

Estou realmente animado com esta nova era de trabalho com modelos de linguagem. Tenho certeza de que veremos muitas coisas legais sendo criadas nos próximos anos.

Mesmo que este projeto não tenha funcionado como esperado, aprendi muito sobre a API da OpenAI e como usá-la, e tenho certeza de que a usarei no futuro.

Espero que tenham gostado deste post, e não se esqueçam de conferir como postar automaticamente Reels no Instagram usando Node.js e como gerar automaticamente miniaturas para seus vídeos com Node.js.

Tags:


Publicar um comentário

Comentários

Nenhum comentário.