15/04/2025

Ness post detalho um prompt específico para utilizar o ChatGPT (rebatizado temporariamente como Mastermind GPT) em uma dinâmica de debate entre personalidades diferentes sobre um tema escolhido.

O objetivo é proporcionar uma interação detalhada e crítica, simulando diferentes pontos de vista e até conflitos diretos entre os participantes.

📌 O Prompt Original Completo

Quer formar seu mastermind agora? Execute esse prompt.

**Contexto:**  
O objetivo é ter acesso a diferentes perspectivas sobre um tema de interesse para analisar em profundidade, contando com pontos de vista potencialmente conflitantes. Para isso, o ChatGPT deve utilizar toda a informação disponível para emular de maneira precisa e efetiva cada personalidade, reproduzindo o posicionamento, vícios de escrita e maneirismos.

---

**Intenção:**  
O objetivo é estabelecer um debate com diversas personalidades sobre um tema específico, respeitando o seguinte método:

1. O ChatGPT deve iniciar a interação solicitando o tema e as personalidades desejadas.  
2. O usuário responde.  
3. O ChatGPT faz uma breve introdução atualizada do tema e apresenta a opinião de cada personalidade em sentenças diretas.  
4. O ChatGPT apresenta uma lista com os principais conflitos entre as opiniões.  
5. O ChatGPT apresenta uma lista de provocações, onde cada personalidade pode fazer uma pergunta direta a outra sobre um conflito identificado.  
6. O ChatGPT solicita a mediação do usuário.  

**7. Possíveis desvios:**  
- Se o usuário solicitar a opinião de uma nova personalidade, o ChatGPT deve apresentar a opinião dessa personalidade, os conflitos com as demais e uma provocação direta da nova personalidade para outra, voltando ao passo 5.  
- Se o usuário selecionar uma provocação, o ChatGPT deve fazer uma atualização criteriosa do tema considerando a provocação, apresentar a réplica da personalidade provocada e a tréplica da personalidade provocadora, e então apresentar uma nova lista de provocações, voltando ao passo 5.  
- Se o usuário fizer outra solicitação, o ChatGPT deve atendê-la da melhor forma possível e retornar ao passo 3.

---

**Condição para informação insuficiente:**  
Caso o ChatGPT não tenha informações suficientes sobre uma das personalidades sugeridas, deve indicar isso claramente e não incluir essa personalidade na discussão.

---

**Formato:**  
- As opiniões devem ser apresentadas em uma lista numerada, escritas como se fossem pelas próprias personalidades, no formato `"Nome da personalidade: Opinião"`, com o nome entre colchetes.  
- Os conflitos devem ser apresentados em uma lista numerada.  
- As provocações devem estar no formato `"[Provocador] para [Provocado]: Provocação"`, sendo a provocação uma questão relacionada a uma discordância anterior.  
- O nome do ChatGPT a partir daquele momento seria **"Mastermind GPT"**, devendo ser sucinto e não fazer advertências ou explicações contextuais sobre seu funcionamento.  
- Ao entender o prompt, o ChatGPT deve se apresentar como **"Mastermind GPT"** e executar imediatamente o passo 1 do método.

🧩 Analisando as partes do Prompt

Agora, vamos destrinchar e explicar as partes fundamentais desse prompt, mostrando o que cada trecho realiza tecnicamente na interação.

1️⃣ Contexto inicial

**Contexto:**  
O objetivo é ter acesso a diferentes perspectivas sobre um tema de interesse para analisar em profundidade, contando com pontos de vista potencialmente conflitantes. Para isso, o ChatGPT deve utilizar toda a informação disponível para emular de maneira precisa e efetiva cada personalidade, reproduzindo o posicionamento, vícios de escrita e maneirismos.

Explicação:
Aqui, o prompt estabelece claramente o propósito da interação: fornecer múltiplas perspectivas. O destaque é a fidelidade na simulação das personalidades, incluindo posicionamentos específicos e maneirismos de expressão, o que torna a interação realista e autêntica.

2️⃣ Método de funcionamento

O coração do prompt é esta seção:

**Intenção:**  
O objetivo é estabelecer um debate com diversas personalidades sobre um tema específico, respeitando o seguinte método:

1. O ChatGPT deve iniciar a interação solicitando o tema e as personalidades desejadas.  
2. O usuário responde.  
3. O ChatGPT faz uma breve introdução atualizada do tema e apresenta a opinião de cada personalidade em sentenças diretas.  
4. O ChatGPT apresenta uma lista com os principais conflitos entre as opiniões.  
5. O ChatGPT apresenta uma lista de provocações, onde cada personalidade pode fazer uma pergunta direta a outra sobre um conflito identificado.  
6. O ChatGPT solicita a mediação do usuário.  

Explicação:
O método descrito é passo a passo, orientando claramente o fluxo do debate. O prompt orienta o GPT a ser breve e direto, evitando excessos e priorizando conflitos reais entre perspectivas diferentes, além de estimular a interação constante do usuário.

3️⃣ Tratamento de Desvios ou interações dinâmicas adicionais

**7. Possíveis desvios:**  
- Se o usuário solicitar a opinião de uma nova personalidade, o ChatGPT deve apresentar a opinião dessa personalidade, os conflitos com as demais e uma provocação direta da nova personalidade para outra, voltando ao passo 5.  
- Se o usuário selecionar uma provocação, o ChatGPT deve fazer uma atualização criteriosa do tema considerando a provocação, apresentar a réplica da personalidade provocada e a tréplica da personalidade provocadora, e então apresentar uma nova lista de provocações, voltando ao passo 5.  
- Se o usuário fizer outra solicitação, o ChatGPT deve atendê-la da melhor forma possível e retornar ao passo 3.

Explicação:
Essa parte do prompt dá flexibilidade à interação, permitindo que novas personalidades sejam introduzidas dinamicamente e que provocações específicas sejam aprofundadas. Isso garante que o debate seja flexível, dinâmico e adaptável às necessidades e curiosidades do usuário.

4️⃣ Condição especial: falta de informação

**Condição para informação insuficiente:**  
Caso o ChatGPT não tenha informações suficientes sobre uma das personalidades sugeridas, deve indicar isso claramente e não incluir essa personalidade na discussão.

Explicação:
Esta cláusula assegura clareza e honestidade na interação. Caso não existam dados suficientes para simular corretamente uma personalidade, o GPT deve comunicar isso claramente ao usuário.

5️⃣ Formatação e identidade visual da interação

**Formato:**  
- As opiniões devem ser apresentadas em uma lista numerada, escritas como se fossem pelas próprias personalidades, no formato `"Nome da personalidade: Opinião"`, com o nome entre colchetes.  
- Os conflitos devem ser apresentados em uma lista numerada.  
- As provocações devem estar no formato `"[Provocador] para [Provocado]: Provocação"`, sendo a provocação uma questão relacionada a uma discordância anterior.  
- O nome do ChatGPT a partir daquele momento seria **"Mastermind GPT"**, devendo ser sucinto e não fazer advertências ou explicações contextuais sobre seu funcionamento.  
- Ao entender o prompt, o ChatGPT deve se apresentar como **"Mastermind GPT"** e executar imediatamente o passo 1 do método.

Explicação:
Essa parte detalha exatamente como a interação deve ser apresentada, criando uma consistência visual e facilitando a leitura. Além disso, estabelece que o GPT assume explicitamente uma nova identidade: Mastermind GPT, criando um ambiente imersivo.

✅ Conclusão sobre a Engenharia do Prompt

Este prompt é um exemplo claro de engenharia avançada de prompts, combinando instruções precisas, formatação clara e mecanismos de controle de fluxo dinâmicos. Sua força está em guiar o modelo para fornecer respostas contextualizadas e convincentes, criando interações ricas e detalhadas, adaptadas exatamente às necessidades do usuário.

06/07/2024

Tenho algumas centenas de horas de aulas gravadas ensinando algoritmos e estruturas de dados, padrões de projeto, Domain-driven Design e Reputação e Marketing Pessoal. Também tenho algumas centenas de horas de sessões de mentoria em arquitetura de software.

Nas minhas masterclasses, sempre vou muito além do material preparado.

Todos esses vídeos possuem ideias incríveis, mas que não são fáceis de acessar, sem que, obviamente, alguém assista todos os vídeos novamente, estruturando conteúdo de maneira interessante.

Recentemente, a Google lançou uma ferramenta incrível chamada NotebookLM. Ela permite “conversar com documentos”. Mas, até então, estes documentos precisam ser textos.

Então, o caminho tem sido gerar versões em texto dos meus vídeos. Mas, como? A resposta é utilizar tecnologias de IA como a Whisper da OpenAI.

Preparação do Ambiente

Para gerenciar as dependências de forma eficaz, recomendo criar um ambiente virtual usando conda. Primeiro, instale a última versão do Python e configure o ambiente:

Python
conda create -n transcricao_env python=3.10
conda activate transcricao_env

Instalação dos Pacotes

Com o ambiente configurado, instale os pacotes necessários:

Python
!pip install git+https://github.com/openai/whisper.git
!pip install ffmpeg-python

Passo-a-passo (Jupyter Notebook)

Importação e Carregamento do Modelo

Em um notebook (ou script Python), começo importando os pacotes necessários e carregando o modelo do Whisper. A primeira execução consome um pouco mais de tempo:

Python
import whisper
import ffmpeg
import os

model = whisper.load_model("base")

Extração do Áudio do Vídeo

Em seguida, extraímos o áudio do vídeo. Isso é feito para facilitar a transcrição, uma vez que o Whisper trabalha diretamente com arquivos de áudio:

Python
video_path = r"/Users/elemarjr/Downloads/mentoria_arquitetura_1.mp4"
audio_path = r"/Users/elemarjr/Downloads/mentoria_arquitetura_1.m4a"
ffmpeg.input(video_path).output(audio_path).run(overwrite_output=True)

Geração da Transcrição

Finalmente, obtemos a transcrição e a salvamos em um arquivo de texto:

Python
# Obter a transcrição
output_path = r"/Users/elemarjr/Downloads/mentoria_arquitetura_1.txt"
result = model.transcribe(audio_path, language='pt')

# Salvar a transcrição em um arquivo de texto
with open(output_path, "w", encoding='utf-8') as f:
    f.write(result['text'])

Pronto para o NotebookLM

Pronto. Tenho um arquivo texto com todo o conteúdo da aula que, agora, pode ser usado como source no NotebookLM.

Juntando tudo em um Utilitário de Linha de Comando

Para facilitar o uso do processo descrito acima, criei um utilitário de linha de comando em Python. Este script permite passar o caminho de um vídeo como argumento e obtém a transcrição do vídeo. Aqui está o código:

Python
import whisper
import ffmpeg
import os
import sys

def transcribe_video(video_path):
    # Define o caminho do arquivo de áudio e da transcrição
    audio_path = os.path.splitext(video_path)[0] + '.m4a'
    output_path = os.path.splitext(video_path)[0] + '.txt'

    # Extrai o áudio do vídeo
    ffmpeg.input(video_path).output(audio_path).run(overwrite_output=True)

    # Carrega o modelo Whisper
    model = whisper.load_model("base")

    # Gera a transcrição
    result = model.transcribe(audio_path, language='pt')

    # Salva a transcrição em um arquivo de texto
    with open(output_path, "w", encoding='utf-8') as f:
        f.write(result['text'])

    print(f"Transcrição salva em {output_path}")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Uso: python transcribe.py <caminho_para_o_video>")
        sys.exit(1)

    video_path = sys.argv[1]
    transcribe_video(video_path)

Para usar este utilitário, salve o código acima em um arquivo chamado transcribe.py e execute-o na linha de comando passando o caminho para o vídeo:

python transcribe.py /caminho/para/o/video.mp4

Pronto! Agora você tem um utilitário de linha de comando que transcreve vídeos automaticamente.

Possíveis Erros e Soluções

Durante o processo, alguns erros podem ocorrer. Aqui estão alguns comuns e como resolvê-los:

  • Erro de instalação de pacotes: Certifique-se de que você tem permissão para instalar pacotes e que sua conexão com a internet está estável.
  • Erro ao carregar o modelo: Verifique se você tem espaço suficiente em disco e memória disponível.
  • Erro ao extrair o áudio: Assegure-se de que o caminho do arquivo de vídeo está correto e que o ffmpeg está instalado corretamente.

Contextualização e Aplicações Práticas

A transcrição de áudio e vídeo é extremamente útil para diversas aplicações, como:

  • Análise de conteúdo: Facilita a análise de grandes volumes de informações contidas em vídeos.
  • Acessibilidade: Ajuda na criação de legendas, tornando o conteúdo acessível para pessoas com deficiência auditiva.
  • SEO e Indexação: Melhora o SEO, permitindo que os motores de busca indexem o conteúdo textual.
  • Recuperar conteúdo relevante e contextualizado: Permite encontrar rapidamente trechos importantes e contextualmente ricos dos vídeos gravados.

Com essa abordagem, posso oferecer material de qualidade para quem estuda comigo, transformando horas de vídeo em documentos de texto utilizáveis, prontos para serem analisados e manipulados em ferramentas como o NotebookLM.

Se você deseja estudar comigo e acessar material de alta qualidade e contextualizado, entre em contato. Estou sempre pronto para compartilhar conhecimento e ajudar no seu desenvolvimento profissional.

01/05/2024

WordPress é uma das plataformas mais populares do mundo para construção de Websites e blogs. A Ontologia da EximiaCo foi construída com WordPress.

Os consultores da EximiaCo colaboram com a produção de conteúdo que está devidamente organizado em classes.

Buscando dados do WordPress

O WordPress disponibiliza uma API RESTish que permite obtenção fácil de informações a respeito de um site.

Python
import pandas as pd
import requests
from cachetools import cached, TTLCache
from datetime import datetime


class WordPress:
    def __init__(self, url):
        self.url = url

    @cached(cache=TTLCache(maxsize=100, ttl=300))
    def get_post_types(self):
        endpoint = '/wp-json/wp/v2/types'
        api_url = f'{self.url}{endpoint}'

        response = requests.get(api_url)
        post_types = response.json()

        if response.status_code == 200:
            data = [{'key': key, 'name': value['name']} for key, value in post_types.items()]
            return pd.DataFrame(data)
        else:
            return pd.DataFrame()

    @cached(cache=TTLCache(maxsize=100, ttl=300))
    def get_users(self):
        api_url = f'{self.url}/wp-json/wp/v2/users'

        response = requests.get(api_url)

        if response.status_code == 200:
            users_data = response.json()
            df = pd.DataFrame(users_data)
            return df
        else:
            return pd.DataFrame()

    @cached(cache=TTLCache(maxsize=100, ttl=300))
    def get_posts(self, post_type_slug, start_date, end_date):

        start_iso = (datetime.strptime(start_date, '%Y-%m-%d')
                     .replace(hour=0, minute=0, second=0)
                     .strftime('%Y-%m-%dT%H:%M:%S'))
        end_iso = (datetime.strptime(end_date, '%Y-%m-%d')
                   .replace(hour=23, minute=59, second=59)
                   .strftime('%Y-%m-%dT%H:%M:%S'))

        endpoint = f'/wp-json/wp/v2/{post_type_slug}'
        api_url = f'{self.url}{endpoint}'

        params = {
            'after': start_iso,
            'before': end_iso,
            'date_gmt': ''
        }

        response = requests.get(api_url, params=params)
        posts = response.json()

        if response.status_code == 200 and isinstance(posts, list):
            data = [
                {'ID': post['id'],
                 'Title': post['title']['rendered'],
                 'Modified': post['modified'],
                 'Created': post['date_gmt'],
                 'AuthorId': post.get('author', 1)
                 } for post in posts]
            df = pd.DataFrame(data)
            return df
        else:
            return pd.DataFrame()

Tenho optado por retornar Dataframes do Pandas quase sempre. Isso torna a interação com os dados algo fácil.

Outra coisa que resolvi fazer nessa implementação foi utilizar um cache em memória mesmo. A ideia é reduzir a quantidade de “ataques” no servidor para informações que considero estáveis.

Facilitando as pesquisas envolvendo períodos semanais

Boa parte das consultas que irei fazer contra meu WordPress serão relacionadas a períodos semanais – ou seja, começando em um domingo e encerrando no próximo sábado. Para tornar a especificação desses intervalos mais fácil, criei uma classe helper.

Python
from datetime import timedelta, datetime


class Weeks:
    @staticmethod
    def get_week_dates(reference_date):
        start_of_week = reference_date - timedelta(days=reference_date.weekday() + 1)
        end_of_week = start_of_week + timedelta(days=6)
        return start_of_week.strftime('%Y-%m-%d'), end_of_week.strftime('%Y-%m-%d')

    @staticmethod
    def get_current():
        today = datetime.now()
        return Weeks.get_week_dates(today)

    @staticmethod
    def get_previous(n = 1):
        today = datetime.now()
        last_week_date = today - timedelta(days=7 * n)
        return Weeks.get_week_dates(last_week_date)

    @staticmethod
    def get_week_string_from_date(reference_date):
        start, end = Weeks.get_week_dates(reference_date)
        return Weeks.get_week_string_from_interval(start, end)

    @staticmethod
    def get_week_string_from_interval(start, end):
        star_f = datetime.fromisoformat(start).strftime('%d/%m')
        end_f = datetime.fromisoformat(end).strftime('%d/%m')
        return f'{star_f} - {end_f}'

Adicionando semântica

O WordPress é uma plataforma de propósito geral. A classe que desenvolvi consegue lidar bem com qualquer WordPress, mas deixa um bocado de interpretações a cargo do desenvolvedor.

Quase sempre, considero criar uma “camada semântica” sobre classes de propósito geral como a que desenvolvemos, adicionando significado específico para o contexto (domínio) em que estou trabalhando.

Python
import pandas as pd
from datetime import datetime

from src.wordpress import WordPress
from src.weeks import Weeks

class Ontologia:
    def __init__(self):
        self.wp = WordPress('https://ontologia.eximia.co')

    def get_classes(self):
        df = self.wp.get_post_types()
        classes = df[
            ~(df['key'].str.startswith('wp_') |
              df['key'].str.startswith('nav_') |
              df['key'].str.contains('jet-engine') |
              df['key'].str.contains('assets') |
              df['key'].str.contains('classes') |
              df['key'].str.contains('page') |
              df['key'].str.contains('post') |
              df['key'].str.contains('links') |
              df['key'].str.contains('media') |
              df['key'].str.contains('attachment') |
              df['key'].str.contains('visibility_preset') |
              df['key'].str.endswith('_links') |
              df['key'].str.endswith('-links')
              )
        ]
        return classes

    def get_authors(self):
        df = self.wp.get_users()
        return df[~(df['name'].str.contains('admin'))]

    def get_entries(self, start_date, end_date):
        classes_df = self.get_classes()
        entries_list = []

        for index, row in classes_df.iterrows():
            post_type_slug = row['key']
            posts_df = self.wp.get_posts(post_type_slug, start_date, end_date)

            posts_df['ClassKey'] = row['key']
            posts_df['ClassName'] = row['name']

            entries_list.append(posts_df)

        final_df = pd.concat(entries_list, ignore_index=True)
        final_df = final_df[~(final_df['AuthorId'] == 1)]

        user_name_map = self.get_authors().set_index('id')['name'].to_dict()
        final_df['AuthorName'] = final_df['AuthorId'].map(user_name_map)
        return final_df

    def get_summary_by_author(self, start_date, end_date):
        entries_df = self.get_entries(start_date, end_date)
        summary_df = entries_df.groupby('AuthorName').size().reset_index(name='Count')

        start_date_formatted = pd.to_datetime(start_date).strftime('%d/%m')
        end_date_formatted = pd.to_datetime(end_date).strftime('%d/%m')
        date_column_title = f"{start_date_formatted} - {end_date_formatted}"

        summary_df.columns = ['Author', date_column_title]

        return summary_df

    def get_summary_by_class(self, start_date, end_date):
        entries_df = self.get_entries(start_date, end_date)
        summary_df = entries_df.groupby('ClassName').size().reset_index(name='Count')

        start_date_formatted = pd.to_datetime(start_date).strftime('%d/%m')
        end_date_formatted = pd.to_datetime(end_date).strftime('%d/%m')
        date_column_title = f"{start_date_formatted} - {end_date_formatted}"

        summary_df.columns = ['Class', date_column_title]

        return summary_df

    def get_weekly_summary_by(self, by, alias, number_of_weeks):
        start, _ = Weeks.get_previous(number_of_weeks)
        _, end = Weeks.get_current()

        entries = self.get_entries(start, end)

        def week(row):
            ref = datetime.fromisoformat(row["Created"])
            return Weeks.get_week_string_from_date(ref)

        entries["Week"] = entries.apply(week, axis=1)

        result = pd.DataFrame(columns=[alias])

        for i in range(number_of_weeks):
            start, end = Weeks.get_previous(i)
            week = Weeks.get_week_string_from_interval(start, end)
            df = entries[entries['Week'] == week]

            summary_df = df.groupby(by).size().reset_index(name='Count')
            summary_df.columns = [alias, week]
            result = pd.merge(summary_df, result, on=alias, how='outer')

        result.fillna(0, inplace=True)

        return result

Aqui, a classe semântica substitui a ideia de “usuários” por “autores”, “tipos de postagem” por “classes”, “postagem” por “entradas”.

Além disso, adicionei algumas consultas de sumarização.

Últimos posts

Inscrição realizada com sucesso!

No dia da masterclass você receberá um e-mail com um link para acompanhar a aula ao vivo. Até lá!

A sua subscrição foi enviada com sucesso!

Aguarde, em breve entraremos em contato com você para lhe fornecer mais informações sobre como participar da mentoria.

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano anual do Clube de Estudos:

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano mensal do Clube de Estudos:

× Precisa de ajuda?