DEV Community

Cover image for Resumindo vídeos do Youtube com auxílio de LLM's
Fabio Simoes
Fabio Simoes

Posted on

Resumindo vídeos do Youtube com auxílio de LLM's

Algumas vezes encontro vídeos realmente interessantes no Youtube, se não o vídeo todo, mas partes dele. Com frequência costumo salvar esses vídeos em alguma lista de reprodução para assistir mais tarde e anotar em algum lugar seu elementos do seu conteúdo para que eu possa ter como referência no futuro. 

O caso é que quase sempre, não me lembro mais qual vídeo era, e quando tento retomar esses vídeos, mesmo os que eu salvei, é raro que eu encontre o que estava procurando.

Não é de hoje que me interesso bastante por NLP (Processamento de Linguagem Natural) e venho estudando uma série assuntos relacionados ao tema, e aí me toquei que não é difícil usar LLM's para resumir videos do Youtube, gerar um resumo em texto, e dessa forma facilitar a busca do assunto que me interessa, posso inclusive usar LLM's nessa etapa também. 

Mas hoje, vamos falar só da primeira parte desse projeto. Vamos criar uma ferramenta que irá resumir vídeos do Youtube, destacando os principais tópicos abordados, e depois disso iremos salvar isso em um arquivo Markdown, que poderá ser armazenado no GitHub/GitLab se preferir, se você utiliza o Obsidian para gerenciar uma biblioteca de markdowns, fica perfeito. 

Vamos começar criando um diretório para o nosso projeto e as pastas necessárias, eu estou usando Linux, mas a lógica é a mesma para outros sistemas operacionais.

mkdir youtube-summarizer
cd youtube-summarizer
mkdir data
mkdir notebook
Enter fullscreen mode Exit fullscreen mode

Vamos iniciar a configuração do nosso projeto, eu gosto de utilizar o Poetry, mas se você preferir utilizar o Pip com Virtualenv.

echo inicia o projeto
poetry init
echo ativa ambiente virtual
poetry shell
echo instala as bibliotecas
poetry add python-dotenv langchain-community langchain-groq langchain ipykernel youtube-transcript-api pytube
Enter fullscreen mode Exit fullscreen mode

Observação: Se você preferir, poderá usar o Google Colab, que irá funcionar da mesma forma. Só vamos trocar a instalação das bibliotecas, no Colab vamos usar o PIP.

Na primeira célula do notebook no Colab, digite:

!pip install -q -U python-dotenv langchain-community langchain-groq langchain youtube-transcript-api pytube

Enter fullscreen mode Exit fullscreen mode

Se você estiver usando o VSCode como eu, e estiver no diretório do projeto, youtube-summarizer agora basta digitar:

code .
Enter fullscreen mode Exit fullscreen mode

Mãos a obra

Para simplificar vamos utilizar o Jupyter Notebook, eu estou utilizando dentro do VSCode, num segundo momento você pode transferir o código do notebook para uma classe Python. Notebooks são muito bons para prototipação, no entanto não considero recomendável que sejam utilizados como "biblioteca de códigos", se passamos para arquivos .py ou estruturamos uma classe, fica muito mais simples de reutilizar esses códigos em projetos futuros. Mas para um tutorial como esse, eles são ótimos, por isso optei pelo Jupyter. 

Para criar um notebook no VSCode, selecione o diretório notebook, clique no ícone 'new file', e adicione um novo arquivo conforme imagem abaixo.

Criar um Jupyter Notebook no VSCode

Qualquer arquivo que você adicionar a extensão .ipynb será reconhecido pelo VSCode como um Jupyter Notebook desde que você tenha a extensão do Jupyter instalada. Qualquer coisa, basta instalar as extensões mostradas na figura abaixo. As duas primeira são primordiais, as duas seguintes podem ser úteis em outras situações, a Jupyter Cell Tags, por exemplo, é muito importante caso queira usar o Papermill (assunto para outra oportunidade) para orquestrar seus projetos pessoais.

Extensões para o Jupyter

Importação das Bibliotecas

Uma vez que criamos nosso notebook podemos iniciar a prototipação. Na primeira célula do notebook, vamos importar as bibliotecas necessárias, conforme mostrado abaixo.

import os
import textwrap
from dotenv import load_dotenv
from IPython.display import Markdown
from langchain_community.document_loaders import YoutubeLoader
from langchain_groq import ChatGroq
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
Enter fullscreen mode Exit fullscreen mode

Criação da chave de acesso para API do Groq

Nós instalamos a biblioteca langchain_groq, que nos permite acessar modelos armazenados no Groq 🙃. Ok, se você não conhece, o Grop armazena uma série de modelos open source, como o Llama3. Nós podemos utilizar o Ollama para servir modelos como esse, no entanto, precisamos de uma máquina bastante poderosa para poder rodar um modelo 70b, e nos meus testes, o 8b não performou bem, por isso vamos fazer uma conta no Groq, criar uma chave, e utilizar aqui, que vai nos dar um ótimo resultado, e até o momento que escrevo isso, não há custos para desenvolvedores. Então vá até esse endereço, https://console.groq.com/keys, crie uma chave:

Criar Groq API Key

Você deve copiar a chave, ela não será exibida novamente, caso precise de outra, crie uma nova.
Agora na raiz do projeto crie um arquivo chamado .env e adicione a sua chave conforme exemplo abaixo:

Criando arquivo .env

Se for mandar seu código para o GitHub ou GitLab, por exemplo, lembre-se de adicionar esse arquivo ao .gitignore, nunca mande o seu arquivo .env para nenhum repositório, público ou privado. 

Uma vez que o arquivo .env esteja corretamente configurado, voltamos ao notebook e vamos carregar a chave utilizando o comando abaixo.

load_dotenv()
Enter fullscreen mode Exit fullscreen mode

Configuração do Modelo

Esse comando lê o arquivo .env e carrega todas as chaves que encontrar lá, inclusive se você tiver outras chaves, ou preferir utilizar outros modelos como os da Open AI, basta configurar no .env.

Agora vamos carregar nossa LLM.

llm = ChatGroq(
    model_name="llama-3.1-70b-versatile", 
    temperature=0, 
    streaming=False
)
Enter fullscreen mode Exit fullscreen mode

Usando no Colab

Caso você opte pelo Colab, adicione o a sua chave conforme indicado na imagem abaixo, e não esqueça de marcar "Acesso ao notebook"

Adicionando a chave da api no Colab

Ao invés de load_dotenv(), use o código abaixo para carregar informações da sua API key.

from google.colab import userdata
os.environ['GROQ_API_KEY'] = userdata.get('GROQ_API_KEY')
Enter fullscreen mode Exit fullscreen mode

Pronto, agora todo o resto funcionará da mesma forma que no Jupyter.

Configuração do Prompt

Com a LLM carregada, o próximo passo é configurar o prompt, vou usar a classe PromptTemplate do Langchain, conforme exemplo abaixo:

prompt_template = PromptTemplate(
    input_variables=["video_transcript"],
    template="""
        Task: Carefully read the entire transcript. If a chapter list is provided, summarize each chapter concisely.

        Information Extraction: Extract key points and relevant information for each chapter or section of the video. 
        Focus on capturing the essence without including unnecessary details.

        Summary Style: Use clear, engaging language that is accessible to a general audience. 
        Keep summaries concise, but comprehensive enough to convey core insights.

        Special Attention:
        Prioritize including any statistical data, expert opinions, or unique insights if present. Highlight these in the summary.
        If numerical or statistical data is mentioned, provide accurate figures and clarify their relevance.

    Video transcript: {video_transcript} """
)
Enter fullscreen mode Exit fullscreen mode

A variável prompt_template configurada acima, será usada logo mais para receber a transcrição do vídeo, e junto com as instruções pré-configuradas, retornar um resumo do vídeo. O prompt está configurado em inglês, porque tive a impressão em alguns testes, que independente da língua da transcrição extraída, quando o prompt está em inglês o modelo performa melhor.

Para quem não sabe o ChatGPT tem algumas ferramentas, eu usei a "Prompt Engineer", conforme imagem abaixo, para me ajudar a melhorar esse prompt, existem outras disponíveis, mas essa é uma das que mais gostei até agora.

ChatGPT - Ferramentas

Extração da transcrição

O nosso próximo passo é extrair a transcrição de um vídeo do Youtube. Mesmo que não sejam criadas legendas pelo autor o próprio Youtube gera transcrições automáticas, e nós vamos usar a classe YoutubeLoader da biblioteca langchain_community para extrair esses dados.

video_url = 'https://www.youtube.com/watch?v=m_YJgE1Go4c'
video_lang = ["pt", "pt-BR", "en"]
Enter fullscreen mode Exit fullscreen mode
loader = YoutubeLoader.from_youtube_url(video_url, add_video_info=True,language = video_lang)
data = loader.load()

metadata = data[0].metadata
transcript = data[0].page_content
Enter fullscreen mode Exit fullscreen mode

Explicando o que está acontecendo no código acima, temos duas variáveis, uma com o link para o vídeo no Youtube, e outra com as linguagens aceitáveis. Essa variável é importante quando usamos o YoutubeLoader, porque se nada for especificado, o loader por padrão irá procurar por transcrições em inglês, se não houver vai dar erro. Passando uma lista de possíveis linguagens nós evitamos o erro. 

loader.load() irá carregar uma lista com dados sobre o vídeo, que inclui o título, data de publicação, autor etc., que estão na chave metadata. E o mais importante para nós aqui, que é a transcrição está na chave page_content.

Configurando a Chain

Vamos usar o conceito de Chain of Thought. A ideia dessa técnica é que ao invés de o modelo dar a resposta direta, ele deve seguir um fluxo de raciocínio, passando por etapas lógicas antes de dar a resposta final. Imagine que vou ensinar a vocês uma receita culinária. Primeiro vamos falar dos ingredientes (organizar os dados), depois passamos a seguir a receita (aplicar a lógica de negócio, e cálculos), verificar o resultado (dar a resposta). 

No código abaixo prompt_template, é o roteiro da receita, as instruções e perguntas que você quer que o modelo responda, llm, é o 'chef' que vai seguir a receita, o StrOutputParser é o garçom que irá organizar o prato e entregar o resultado (acho que no restaurante o garçom não organiza o prato, mas espero que tenha sido capaz de explicar o conceito).

chain = prompt_template | llm | StrOutputParser()
Enter fullscreen mode Exit fullscreen mode

Agora nós podemos invocar essa cadeia de "raciocínio" através do comando abaixo.

summary = chain.invoke({
    "video_transcript": transcript
})
Enter fullscreen mode Exit fullscreen mode

Quando fizemos a configuração do Prompt Template, nós criamos uma variável lá, video_transcript, e agora nós atribuímos a transcrição extraída a essa variável que será incorporada ao restante do template. Após executar o código acima, podemos visualizar o resultado como no exemplo abaixo.

Resultado do modelo

O modelo faz um ótimo trabalho resumindo os pontos chaves do vídeo. Um ponto específico acho importante comentar, a última linha, na parte de Estatística e Dados, a informação de que a linguagem Python é a mais usada no mundo atualmente não é verdadeira, numa rápida pesquisa constatei que JavaScript é a mais usada. No vídeo é comentando que a linguagem Python é a mais usada no mundo para Inteligência Artificial, especificamente nesse contexto.

Então o resumo em si não de ser usado como fonte de verdade absoluta, aliás nunca use a resposta de um modelo de inteligência artificial como verdade absoluta. Meu objetivo aqui é poder criar uma biblioteca com informações que eu possa pesquisar no futuro com mais facilidade, então encontrando os assuntos que me interessam assistir o vídeo e aí sim tirar minhas próprias conclusões. 

Dito isso, vamos para o próximo passo.

Salvando o resultado

Como quero criar uma biblioteca de dados, quero salvar cada resumo em um arquivo .md diferente, vamos criar uma função para facilitar esse processo.

def get_video_info(metadata, summary):
    infos_video = textwrap.dedent(f"""## Video Summary

    Title: {metadata['title']}
    Author: {metadata['author']}
    Date: {metadata['publish_date'][:10]}
    URL: https://www.youtube.com/watch?v={metadata['source']}

    """) 

    infos_video += textwrap.dedent(f"""## Summary

    """)

    infos_video += textwrap.dedent(f'{summary}')

    final =infos_video 

    return final, metadata['title']
Enter fullscreen mode Exit fullscreen mode

A função acima vai receber o resumo gerado pelo modelo LLM e os metadados extraídos anteriormente, e criar uma Markdown, essa função retorna também o título do vídeo que nós iremos utilizar como nome do arquivo.

Abaixo está a função que irá salvar o arquivo.

def save_summary_to_markdown(summary, filename):
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(summary)
Enter fullscreen mode Exit fullscreen mode

Com as duas funções acima criadas podemos agora finalmente salvar nosso resumo, conforme exemplo abaixo.

final_summary, video_title = get_video_info(metadata, summary)
transcript_path_file_name = '../data/'+video_title+'.md'
save_summary_to_markdown(final_summary,transcript_path_file_name)
Enter fullscreen mode Exit fullscreen mode

No final teremos algo como o apresentado abaixo:

Arquivo Markdown gerado

Conclusão

LLM's são modelos muito dinâmicos, é muito fácil perceber o resultado, e a cada dia temos uma gama maior de alternativas, seja para estudar esses modelos, ou para a utilização deles tanto pessoal como profissional. Temos hoje uma gama muito grande de informações e dados a nossa disposição, nem sempre temos tempo, ou sabemos como catalogar esses dados para que possamos utilizar em momentos futuros, mas uma aplicação simples como a demostrada nesse artigo, consegue de forma muito simples e em poucos minutos gerar documentos que facilitam demais a busca por informações, se você tentar por conta própria criar um resumo de cada vídeo interessante que você encontrar na internet, vai perceber que isso leva bastante tempo. 

Para facilitar a execução, deixo aqui o link para o notebook no Google Colab.

Espero que o exemplo demonstrado aqui possa ser útil, muito obrigado pelo seu tempo, e até a próxima.

Top comments (0)