Skip to content

Riverfount/translate-bot

🌐 translate-bot

Bot para o Fediverso que traduz posts automaticamente quando mencionado.

Mencione @[email protected] em qualquer post e ele responde com o conteúdo traduzido para o idioma configurado.

@[email protected]
Bonjour tout le monde, comment ça va ?

@[email protected]
🌐 [FR → PT] Olá a todos, como vão vocês?

Testado e funcionando com Mastodon e instâncias compatíveis com ActivityPub.


Tecnologias

apkit Toolkit ActivityPub para Python — cuida de HTTP Signatures, WebFinger e NodeInfo
FastAPI Servidor web assíncrono (vem como dependência do apkit)
LibreTranslate Detecção automática de idioma e tradução — open source, self-hostável
Dynaconf Configuração por ambiente com suporte a secrets
SQLAlchemy + SQLite Persistência leve de followers, sem dependências externas
uv Gerenciamento de dependências e ambiente virtual

Pré-requisitos

  • Python 3.12+
  • uv instalado
  • make instalado (disponível na maioria dos sistemas Unix)
  • Acesso a uma instância LibreTranslate (pública ou self-hosted)
  • Um domínio com HTTPS apontando para o servidor (obrigatório para ActivityPub)

Instalação

1. Instalar o uv

curl -LsSf https://astral.sh/uv/install.sh | sh

2. Clonar o repositório

git clone https://github.com/Riverfount/translate-bot
cd translate-bot

3. Instalar as dependências

make install-dev

O uv cria automaticamente o ambiente virtual em .venv e instala tudo a partir do uv.lock. Não é necessário ativar o venv manualmente.

4. Gerar as chaves RSA do bot

make gen-keys

Isso cria keys/private.pem e keys/public.pem. A chave privada é usada para assinar as atividades enviadas — nunca a versione no git.

5. Configurar o ambiente

Edite o settings.toml com o domínio do seu bot:

[production]
domain = "bot.seu-dominio.com"

Crie o arquivo .secrets.toml com a API key da instância LibreTranslate, se necessário (já está no .gitignore):

[default]
libretranslate_api_key = "sua-chave-aqui"

Instâncias self-hosted sem autenticação podem deixar a chave em branco. A instância padrão https://libretranslate.com exige chave.

Para definir o ambiente ativo, crie um .env na raiz:

ENV_FOR_DYNACONF=production

6. Rodar o servidor

make run

Para desenvolvimento com hot-reload:

make dev

Configuração

Todas as configurações ficam em settings.toml. Os segredos ficam separados em .secrets.toml.

# settings.toml

[default]
bot_username         = "translatebot"        # usuário do bot no Fediverso
bot_display_name     = "Translate Bot 🌐"
bot_summary          = "Mencione-me para traduzir qualquer post!"
target_language      = "pt"                  # idioma padrão de destino
libretranslate_url   = "https://libretranslate.com"  # instância LibreTranslate
libretranslate_api_key = ""                  # deixe em branco se não exigir chave
database_url         = "sqlite+aiosqlite:///./bot.db"
private_key_path     = "keys/private.pem"
public_key_path      = "keys/public.pem"

[development]
domain       = "localhost"
database_url = "sqlite+aiosqlite:///./bot_dev.db"

[production]
domain = "bot.seu-dominio.com"               # ← altere aqui

Qualquer configuração pode ser sobrescrita via variável de ambiente com o prefixo TRANSLATEBOT_:

TRANSLATEBOT_TARGET_LANGUAGE=en uv run uvicorn app.main:api --host 0.0.0.0 --port 8000

Como funciona

Mastodon / Misskey / etc.                Translate Bot
        │                                      │
        │  POST /users/translatebot/inbox       │
        │  {type: "Create", object: Note} ─────▶│
        │                                      │
        │                        verifica HTTP Signature (apkit)
        │                        enfileira na fila assíncrona
        │                        retorna 202 Accepted imediatamente
        │                                      │
        │                        [worker em background]
        │                        extrai texto do post
        │                        detecta idioma de origem
        │                        traduz via LibreTranslate
        │                        monta Note de resposta
        │                        assina com draft-cavage e envia
        │                                      │
        │  ◀── resposta traduzida na thread ───│

O handler do inbox retorna 202 imediatamente — servidores Mastodon têm timeout curto. A tradução acontece em um worker asyncio em background.


Estrutura do projeto

translate-bot/
├── app/
│   ├── main.py                  # Servidor ActivityPub + endpoints FastAPI
│   ├── config.py                # Configurações via Dynaconf
│   ├── database.py              # Engine e sessão SQLAlchemy async
│   ├── activitypub/
│   │   ├── actor.py             # Perfil ActivityPub do bot
│   │   ├── keys.py              # Carregamento das chaves RSA
│   │   └── handlers.py          # Handlers de Follow e Create
│   ├── models/
│   │   └── follower.py          # ORM model de followers
│   └── services/
│       ├── translate.py         # Integração LibreTranslate
│       └── queue.py             # Fila assíncrona asyncio
├── workers/
│   └── inbox_worker.py          # Worker de tradução em background
├── scripts/
│   └── generate_keys.py         # Geração de chaves RSA
├── tests/                       # Suite de testes (pytest + anyio)
├── keys/                        # Chaves RSA — git-ignored
├── settings.toml                # Configurações (versionado)
├── .secrets.toml                # Segredos — git-ignored
├── .env.example                 # Exemplo de variáveis de ambiente
├── Dockerfile                   # Imagem para deploy
├── Makefile                     # Comandos de gerenciamento do projeto
├── pyproject.toml               # Dependências e metadados
└── uv.lock                      # Lockfile — deve ser versionado

Testes

# Rodar todos os testes (cobertura incluída automaticamente)
make test

# Modo verbose
make test-v

# Apenas um módulo
make test-file FILE=tests/test_handlers.py

# Sem relatório de cobertura (mais rápido)
make test-fast

A cobertura é configurada automaticamente via pyproject.toml (branch coverage). A suite cobre translate, inbox_worker, handlers, actor/keys e os endpoints principais do servidor.


Comandos úteis

# Listar todos os comandos disponíveis
make help

# Verificar o código com o linter
make lint

# Corrigir erros de lint automaticamente
make lint-fix

# Formatar o código
make format

# Verificar tipos com mypy
make typecheck

# Formatar + lint + typecheck de uma vez
make check

# Remover artefatos gerados (cache, cobertura, build)
make clean

# Adicionar uma dependência
uv add nome-do-pacote

# Adicionar dependência só de desenvolvimento
uv add --group dev nome-do-pacote

# Atualizar apenas o apkit
uv lock --upgrade-package apkit

Deploy com Docker

make docker-build
make docker-run

Para acompanhar os logs em tempo real:

make docker-logs

Para parar e remover o container:

make docker-stop

As variáveis IMAGE_NAME, IMAGE_TAG e PORT podem ser sobrescritas:

make docker-build IMAGE_NAME=meu-bot IMAGE_TAG=v1.0
make docker-run PORT=9000

HTTPS (obrigatório)

O protocolo ActivityPub exige HTTPS. Servidores Mastodon rejeitam conexões sem TLS.

A forma mais simples com Caddy:

# Caddyfile
bot.seu-dominio.com {
    reverse_proxy localhost:8000
}
caddy run

O Caddy obtém e renova o certificado Let's Encrypt automaticamente.


Teste local com ngrok

Para testar sem um servidor público, use o ngrok para expor o servidor local:

# Terminal 1 — túnel ngrok
ngrok http 8000

# Terminal 2 — servidor
make dev

Atualize o settings.toml com a URL do ngrok na seção [development] e defina ENV_FOR_DYNACONF=development no .env.


Notas

apkit ainda não é estável. A versão está fixada no pyproject.toml. Antes de atualizar, leia o CHANGELOG do projeto.

LibreTranslate é open source e self-hostável. Para maior controle e sem custos por caractere, considere rodar sua própria instância. Instruções em libretranslate.com. O limite de 500 caracteres por requisição é configurável no código.

uv.lock deve ser versionado no git. Ele garante que produção use exatamente as mesmas versões que desenvolvimento.


Autor

Vicente Marçal — @[email protected]


Licença

MIT

About

ActivityPub translation bot — mention it to get any post translated. Built with apkit, FastAPI and LibreTranslate.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors