Shinobu-Whatsapp

module
v1.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 14, 2026 License: MIT

README

Shinobu

Status Go Último commit

Bot de WhatsApp escrito em Go, construído sobre whatsmeow. Possui router de comandos com middlewares, IA com personalidade via Groq, histórico de conversa por usuário, busca web via Tavily, gerenciamento de aniversários em grupo, efeitos de áudio com ffmpeg e reprodução de música via servidor remoto com yt-dlp.

Módulo Go: github.com/Turgho/Shinobu-Whatsapp O repositório pode ser clonado como Shinobu-Whatsapp — use sempre o caminho do módulo nos imports.


Sumário


Requisitos

Dependência Detalhe
Go 1.25+ Ver go.mod
ffmpeg Necessário para !sticker e !efeito. O binário deve estar em ./bin/ffmpeg relativo à raiz do projeto
webpmux Necessário para injetar metadados nos stickers. Binário em ./bin/webpmux
Servidor de música !play e !stats dependem de MUSIC_SERVER_URL (servidor com yt-dlp)
Groq Obrigatório para !shinobu e menções à IA
Tavily Opcional — habilita busca web na IA
Instalando ffmpeg
# Ubuntu / Debian
sudo apt install ffmpeg

# Fedora (requer RPM Fusion)
sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
sudo dnf install ffmpeg

# Arch / Manjaro / CachyOS
sudo pacman -S ffmpeg

# macOS
brew install ffmpeg

O pacote libwebp geralmente inclui o webpmux. Copie ou crie um link simbólico para ./bin/webpmux caso não esteja no PATH global.


Instalação

git clone https://github.com/Turgho/Shinobu-Whatsapp.git
cd Shinobu-Whatsapp
go mod tidy

Configuração

config.yaml
cp config.example.yaml config.yaml

O arquivo cobre bot, database, log, usersJID e apiUrls. Os campos podem ser sobrescritos por variáveis de ambiente via Viper (ex: OWNER_JID, COMMAND_PREFIX, DB_DSN).

.env
# Groq — obrigatório para a IA
GROQ_URL=https://api.groq.com/openai/v1/chat/completions
GROQ_API_KEY=gsk_sua_chave_aqui

# Tavily — opcional, habilita busca web
TAVILY_API_KEY=tvly-sua-chave-aqui

# Número do dono (somente dígitos)
OWNER_NUMBER=5511999999999

# Servidor de música (yt-dlp)
# POST /play  → baixa e retorna áudio
# GET  /stats → métricas do servidor remoto
MUSIC_SERVER_URL=http://seu-servidor:porta

JID do dono: inicie o bot, envie uma mensagem e copie o JID que aparece nos logs. Cole em usersJID.owner no config.yaml.

Groq: obtenha uma API key gratuita em console.groq.com.

Tavily: plano free disponível em tavily.com.


Execução

go run cmd/bot/main.go

Na primeira execução, escaneie o QR Code exibido no terminal. A sessão WhatsApp é persistida em SQLite conforme database.dsn (padrão: storage/storage.db). O histórico da IA usa storage/message_history.db.


Comandos

Públicos
Comando Descrição
!menu Lista todos os comandos registrados
!ping Verifica latência e disponibilidade
!clima <cidade> Clima atual via Nominatim + Open-Meteo
!sticker Converte imagem ou vídeo em figurinha
!play <nome ou URL> Reproduz música via servidor remoto (yt-dlp)
!efeito [nome] [intensidade] Aplica efeito em um áudio. Sem args, lista os disponíveis. Intensidades: leve, medio, forte
!shinobu <texto> Conversa com a IA
Menção "shinobu" Atalho para o mesmo handler do !shinobu
!aniversário Gerencia aniversários do grupo (ver abaixo)
!mambo, !dio, !cafe Reproduz áudios OGG de assets/audios/
!aniversário — detalhamento
Uso Quem pode
!aniversário DD/MM Qualquer membro — salva o próprio
!aniversário lista Qualquer membro
!aniversário remover Qualquer membro — remove o próprio
!aniversário salvar @pessoa DD/MM Dono / admin
!aniversário remover @pessoa Dono / admin
Administrativos
Comando Descrição
!stats Métricas de runtime do bot + servidor remoto
!shutdown Encerra o processo
!fig <nome> Envia figurinha salva
!fig salvar <nome> Salva figurinha (enviar ou citar)
!fig remover <nome> Remove figurinha salva
!fig lista Lista figurinhas salvas

Comandos administrativos exigem que o remetente seja owner ou admin configurado em usersJID.

Efeitos de áudio disponíveis
Efeito Descrição
reverb Slowed + reverb
deep Mais lento e grave
echo Eco pronunciado
nightcore Mais rápido e agudo
bass Boost de graves
lofi Lofi com filtro e reverb leve

IA — Oshino Shinobu

  • Personalidade definida via system prompt.
  • Histórico por usuário armazenado em SQLite com limpeza periódica.
  • Resumo de conversa persistido entre sessões.
  • Busca web via Tavily acionada automaticamente quando a pergunta exige dados atuais.
  • Tom diferenciado para o owner.
Modelos
Uso Modelo
Conversa e resumo meta-llama/llama-4-scout-17b-16e-instruct
Resposta com contexto web llama-3.3-70b-versatile
Classificação de busca Scout com MaxTokens reduzido

Aniversários

Dados persistidos em JSON pelo pacote internal/domain/birthday.

O scheduler roda em background e notifica os grupos com aniversariantes todos os dias às 08:00 (horário local do processo), mencionando os aniversariantes e todos do grupo.


Estrutura do projeto

.
├── cmd/bot/
│   └── main.go                              # Entry point — chama app.Run()
├── config.example.yaml                      # Modelo de configuração
├── scripts
│   └── setup.sh                             # Instala ffmpeg e webpmux em ./bin/
├── go.mod                                   # Módulo: github.com/Turgho/YuukoWhatsapp
│
├── assets/
│   ├── audios/                              # OGGs estáticos (!mambo, !dio, !cafe)
│   │   ├── hora_cafe.ogg
│   │   ├── mambo.ogg
│   │   └── zawarudo.ogg
│   ├── images/                              # Imagens estáticas (ex: banner do !menu)
│   │   └── shinobu_banner.png
│   ├── stickers/                            # JSON do store de figurinhas salvas
│   └── videos/                              # Vídeos estáticos (uso futuro)
│
├── storage/                                 # Gerado em runtime — não commitar
│   └── message_history.db                   # Histórico SQLite da IA por JID
│
└── internal/
    ├── app/
    │   └── app.go                           # Inicialização de deps, router e handlers
    │
    ├── bot/
    │   ├── client.go                        # Sessão whatsmeow (QR, reconexão)
    │   └── handler.go                       # Dispatcher de eventos do WhatsApp
    │
    ├── commands/                            # Camada de comandos
    │   ├── router.go                        # Roteamento por prefixo + middlewares
    │   ├── middleware.go                    # IgnoreOld, NotFound, PrivateCommands
    │   ├── types.go                         # CommandMeta, HandlerFunc, ArgMeta
    │   ├── admin/
    │   │   ├── save_sticker.go              # !fig — gerencia figurinhas salvas
    │   │   ├── shutdown.go                  # !shutdown
    │   │   └── stats.go                     # !stats — runtime + servidor remoto
    │   └── public/
    │       ├── audio_effects.go             # !efeito — reverb, lofi, nightcore, etc.
    │       ├── birthday.go                  # !aniversário — wrapper do domain
    │       ├── bundled_audio.go             # !mambo, !dio, !cafe
    │       ├── menu.go                      # !menu — banner + lista de comandos
    │       ├── ping.go                      # !ping
    │       ├── play.go                      # !play — encaminha para servidor yt-dlp
    │       ├── shinobu.go                   # !shinobu / menção — IA com personalidade
    │       ├── sticker.go                   # !sticker — imagem/vídeo → figurinha
    │       └── weather.go                   # !clima
    │
    ├── domain/                             # Regras de negócio
    │   ├── birthday/
    │   │   ├── handler.go                   # Subcomandos do grupo (salvar, remover, lista)
    │   │   ├── scheduler.go                 # Loop diário às 08:00 — notifica grupos
    │   │   └── store.go                     # Persistência JSON + helpers (parseDate, etc.)
    │   ├── geocoding/
    │   │   └── geocode.go                   # Nominatim — coordenadas por nome de cidade
    │   ├── history/
    │   │   └── message_history.go           # Histórico por JID em SQLite (contexto da IA)
    │   ├── ia/
    │   │   ├── groq.go                      # Client HTTP Groq
    │   │   ├── ia.go                        # Orquestração: histórico, busca, resposta
    │   │   ├── keywords.go                  # Detecção de intent de busca web
    │   │   ├── models.go                    # Constantes de modelos e parâmetros
    │   │   ├── prompts.go                   # System prompts da Shinobu
    │   │   ├── search.go                    # Busca web via Tavily
    │   │   ├── summary.go                   # Resumo persistente por usuário
    │   │   ├── tavily.go                    # Client HTTP Tavily
    │   │   └── utils.go                     # Helpers internos da IA
    │   ├── music/
    │   │   ├── audio_effects.go             # Efeitos ffmpeg (reverb, lofi, nightcore…)
    │   │   ├── mimetype.go                  # Resolução de MIME por extensão
    │   │   └── ytdlp_request.go             # Requisição HTTP ao servidor de música
    │   ├── sticker/
    │   │   ├── convert.go                   # ffmpeg → WebP + injeção de metadados EXIF
    │   │   ├── handler.go                   # Subcomandos !fig (salvar, remover, lista)
    │   │   ├── send.go                      # Envio de figurinha salva
    │   │   └── store.go                     # Persistência JSON das figurinhas
    │   └── weather/
    │       ├── weather.go                   # Open-Meteo — previsão por coordenadas
    │       └── weather_code.go              # Mapeamento de códigos WMO para texto
    │
    ├── infra/                              # Infraestrutura transversal
    │   ├── configs/
    │   │   └── config.go                    # Viper + .env — carregamento de configuração
    │   ├── database/
    │   │   └── database.go                  # Conexão SQLite para o whatsmeow
    │   ├── ffmpeg/
    │   │   ├── ffmpeg_exec.go               # exec.Cmd para ./bin/ffmpeg
    │   │   └── linux_process.go             # SysProcAttr — prioridade baixa no Linux
    │   ├── logger/
    │   │   └── logger.go                    # Zap — configuração de log
    │   └── uptime/
    │       └── uptime.go                    # Timestamp de início do processo (!stats)
    │
    └── integration/                        # Adaptadores WhatsApp
        ├── media/
        │   ├── doc.go                       # Documentação do pacote
        │   └── download.go                  # DownloadFromEvent — imagem, vídeo, áudio, doc
        └── whatsapp/
            ├── audio.go                     # SendAudio
            ├── context.go                   # buildContext, replyContext, mentionContext
            ├── doc.go                       # Documentação do pacote
            ├── document.go                  # SendDocument
            ├── image.go                     # SendImage + geração de thumbnail JPEG
            ├── location.go                  # SendLocation
            ├── message_text.go              # PlainTextFromProto — extrai texto da mensagem
            ├── presence.go                  # withTyping — indicador de digitação
            ├── reaction.go                  # SendReaction
            ├── reply.go                     # Reply (atalho com quote)
            ├── sticker.go                   # SendSticker
            ├── text.go                      # SendText, SendTextWithMentions, SendTextToJID
            └── video.go                     # SendVideo

Criando um novo comando

1. Crie o handler em internal/commands/public/ ou internal/commands/admin/:

package public

import (
    "context"

    "github.com/Turgho/YuukoWhatsapp/internal/integration/whatsapp"
    "go.mau.fi/whatsmeow"
    "go.mau.fi/whatsmeow/types/events"
)

func HelloCommand(ctx context.Context, client *whatsmeow.Client, evt *events.Message, args []string) error {
    return whatsapp.Reply(ctx, client, evt, "Olá!")
}

2. Registre em internal/app/app.go:

r.RegisterCommand(commands.CommandMeta{
    Name:        "hello",
    Description: "Responde com uma saudação",
    Type:        commands.CommandTypeUtility,
}, public.HelloCommand)

O !menu lista automaticamente. Para restringir a owner/admins, adicione Private: true no CommandMeta.


Contato

Notificador de Gol do Brasil (Copa 2026)

O módulo de futebol adiciona um watcher que monitora partidas do Brasil na Copa 2026 e envia notificações via WhatsApp quando ocorre um gol.

Como obter e configurar a API key
  1. Acesse https://www.api-football.com/ e crie uma conta gratuita.
  2. Após o login, obtenha sua API key na seção "My Account".
  3. Defina a variável de ambiente FOOTBALL_API_KEY ou configure em config.yaml:
    football:
      api_key: "SUA_API_KEY_AQUI"
    
Como configurar watched_teams e notify_jid

No config.yaml, ajuste a seção football:

football:
  enabled: true
  api_key: "sua_api_key"
  notify_jid: "seu_jid@lid" # JID do grupo ou pessoa para receber notificações
  poll:
    idle_interval: "5m"
    live_interval: "15s"
  watched_teams:
    - name: "Brasil"
      api_team_id: 6
      flag: "🇧🇷"
    - name: "Argentina"
      api_team_id: 3
      flag: "🇦🇷"
  • enabled: ativa ou desativa o watcher.
  • api_key: chave da API-Football.
  • notify_jid: JID do destino da notificação (grupo ou pessoa).
  • poll.idle_interval: intervalo de consulta quando não há partidas ao vivo.
  • poll.live_interval: intervalo de consulta quando há partidas ao vivo (mínimo recomendado: 15s para o plano free).
  • watched_teams: lista de times a serem monitorados. Cada time requer:
    • name: nome do time (para exibição na notificação).
    • api_team_id: ID externo da equipe na API-Football.
    • flag: emoji da bandeira do time (opcional).
Comparação das opções de API avaliadas
API Custo Delay médio Confiabilidade Observações
API-Football (api-football.com) Plano free: 100 req/dia ~15-30s (dependendo do intervalo de polling) Alta Requer chave; plano free insuficiente para polling agressivo durante partidas inteiras.
API comunitária (github.com/rezarahiminia/worldcup2026) Gratuito Variável Baixa Projeto pequeno; pode ter instabilidade e atrasos maiores.

Por que a API-Football foi escolhida? Apesar do limite de requisições no plano free, ela oferece dados oficiais, baixa latência e alta confiabilidade. Para uso em produção durante partidas, recomenda-se um plano pago ou limitar o monitoramento a jogos específicos.

Delay estimado

O delay médio entre o gol real e a notificação está entre 15 e 30 segundos, considerando:

  • Intervalo de polling de 15 segundos durante partidas ao vivo (mínimo permitido pelo plano free).
  • Tempo de processamento da requisição e resposta da API (geralmente < 2s).
  • Tempo de envio da mensagem via WhatsApp (geralmente < 5s).

O delay pode ser reduzido aumentando a frequência de polling, mas o plano free da API-Football permite apenas 100 requisições por dia. Com intervalo de 15 segundos, são consumidas 5760 requisições por dia (24h * 60min * 4req/min), o que excede o limite. Portanto, o intervalo deve ser ajustado conforme o plano contratado.

O que foi feito

  • Adicionado novo domínio internal/domain/football com estrutura seguindo os padrões existentes (birthday, weather).
  • Implementado watcher de gols com polling adaptativo (idle/live) e deduplicação de eventos via JSON store.
  • Integração com WhatsApp utilizando a infraestrutura existente (integration/whatsapp/text.go).
  • Atualização de config.yaml e config.example.yaml com a seção football.
  • Documentação detalhada no README.md sobre configuração, uso e limitações.
  • Inicialização do watcher em internal/app/app.go (via internal/domain/football/handler.Start).

Possíveis melhorias futuras

  • Monitorar múltiplos times em paralelo (já suportado via watched_teams).
  • Substituir polling por webhook/websocket quando disponível na API-Football.
  • Notificar outros eventos (cartão vermelho, início/fim de jogo).
  • Adicionar comando para consultar próximo jogo/placar atual (ex: !futebol próximo).
  • Permitir múltiplos destinos de notificação.
  • Internacionalização da mensagem de notificação (suporte a múltiplos idiomas).
  • Métricas de upto do watcher (tempo de atividade, última verificação, etc.).
  • Fallback automático para API comunitária quando a API-Football atingir o limite de requisições.
  • Otimização de deduplicação usando hash de eventos além do ID.

Directories

Path Synopsis
cmd
bot command
internal
app
bot
domain/history
Package history guarda mensagens por chat e um resumo textual para contexto da IA.
Package history guarda mensagens por chat e um resumo textual para contexto da IA.
infra/uptime
Package uptime regista o instante de arranque do processo (para !stats e filtro de mensagens antigas).
Package uptime regista o instante de arranque do processo (para !stats e filtro de mensagens antigas).
infra/version
version/version.go
version/version.go
integration/media
Package media descarrega bytes de mídia a partir de mensagens ou citações (whatsmeow).
Package media descarrega bytes de mídia a partir de mensagens ou citações (whatsmeow).
integration/whatsapp
Package whatsapp encapsula envio de mensagens WhatsApp (texto, mídia, reações, localização) e helpers para ler texto visível dos protos/eventos (router, comandos em DM).
Package whatsapp encapsula envio de mensagens WhatsApp (texto, mídia, reações, localização) e helpers para ler texto visível dos protos/eventos (router, comandos em DM).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL