image

Bootcamps ilimitados e +750 cursos pra sempre

70
%OFF
Wandreson Silva
Wandreson Silva01/11/2026 21:13
Compartilhe

Agente de Produtividade com IA — Google ADK, Trello e Telegram

    🤖 Agente de Produtividade com IA — Google ADK, Trello e Telegram

    📌 Sobre o projeto

    O Agente de Produtividade é uma aplicação desenvolvida em Python que utiliza inteligência artificial por meio do Google ADK e do Gemini para auxiliar no gerenciamento de tarefas.

    O projeto integra a API do Trello para organizar atividades e a API do Telegram para enviar notificações sobre operações realizadas.

    """
    Agente de Produtividade
    Integra Google ADK/Gemini, Trello e Telegram.
    
    
    Estrutura esperada:
    
    
    Agente_de_Produtividade_com_IA_Google_ADK_Trello_Telegram/
    │
    ├── .env
    ├── .gitignore
    ├── requirements.txt
    │
    └── agente_produtividade/
      ├── __init__.py
      └── agent.py
    
    
    Execute a partir da raiz do projeto com:
      adk web app
    ou conforme a forma de execução da sua instalação do Google ADK.
    """
    
    
    from __future__ import annotations
    
    
    import logging
    import os
    from datetime import date, datetime, time
    from pathlib import Path
    from typing import Any
    from zoneinfo import ZoneInfo
    
    
    import requests
    from dotenv import load_dotenv
    from trello import TrelloClient
    from google.adk.agents import Agent
    
    
    
    
    # ============================================================
    # CONFIGURAÇÃO
    # ============================================================
    
    
    BASE_DIR = Path(__file__).resolve().parent.parent
    ENV_FILE = BASE_DIR / ".env"
    
    
    if not ENV_FILE.is_file():
      raise FileNotFoundError(
          f"Arquivo .env não encontrado em: {ENV_FILE}. "
          "Crie o arquivo na raiz do projeto."
      )
    
    
    load_dotenv(dotenv_path=ENV_FILE, override=False)
    
    
    TIMEZONE_NAME = os.getenv("APP_TIMEZONE", "America/Sao_Paulo")
    DEFAULT_TRELLO_LIST = os.getenv("TRELLO_DEFAULT_LIST", "A Fazer")
    GOOGLE_MODEL = os.getenv("GOOGLE_MODEL", "").strip()
    
    
    try:
      APP_TIMEZONE = ZoneInfo(TIMEZONE_NAME)
    except Exception as exc:
      raise RuntimeError(
          f"Fuso horário inválido em APP_TIMEZONE: {TIMEZONE_NAME}"
      ) from exc
    
    
    
    
    # ============================================================
    # LOGGING
    # ============================================================
    
    
    LOG_DIR = BASE_DIR / "logs"
    LOG_DIR.mkdir(parents=True, exist_ok=True)
    
    
    logging.basicConfig(
      level=os.getenv("LOG_LEVEL", "INFO").upper(),
      format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
      handlers=[
          logging.StreamHandler(),
          logging.FileHandler(LOG_DIR / "agente_produtividade.log", encoding="utf-8"),
      ],
    )
    
    
    logger = logging.getLogger("agente_produtividade")
    
    
    
    
    # ============================================================
    # VALIDAÇÃO DAS CONFIGURAÇÕES
    # ============================================================
    
    
    REQUIRED_ENV = (
      "GOOGLE_API_KEY",
      "TRELLO_API_KEY",
      "TRELLO_TOKEN",
      "TRELLO_BOARD_ID",
      "TELEGRAM_BOT_TOKEN",
      "TELEGRAM_CHAT_ID",
    )
    
    
    missing_vars = [name for name in REQUIRED_ENV if not os.getenv(name, "").strip()]
    
    
    if missing_vars:
      raise RuntimeError(
          "Variáveis ausentes no arquivo .env: " + ", ".join(missing_vars)
      )
    
    
    if not GOOGLE_MODEL:
      raise RuntimeError(
          "Defina GOOGLE_MODEL no .env com um identificador de modelo Gemini "
          "atualmente disponível para sua conta e versão do Google ADK."
      )
    
    
    # O Google ADK normalmente lê GOOGLE_API_KEY diretamente do ambiente.
    # Não registre nem imprima o conteúdo dessa chave.
    
    
    
    
    # ============================================================
    # CLIENTES E ACESSO AO TRELLO
    # ============================================================
    
    
    try:
      trello = TrelloClient(
          api_key=os.environ["TRELLO_API_KEY"],
          token=os.environ["TRELLO_TOKEN"],
      )
      board = trello.get_board(os.environ["TRELLO_BOARD_ID"])
    except Exception as exc:
      logger.exception("Não foi possível inicializar a conexão com o Trello.")
      raise RuntimeError(
          "Falha ao conectar ao Trello. Verifique TRELLO_API_KEY, "
          "TRELLO_TOKEN e TRELLO_BOARD_ID."
      ) from exc
    
    
    
    
    def _normalizar_texto(valor: str, campo: str, limite: int) -> str:
      """Valida e normaliza um campo textual."""
      if not isinstance(valor, str):
          raise ValueError(f"O campo '{campo}' deve ser um texto.")
    
    
      valor = valor.strip()
    
    
      if not valor:
          raise ValueError(f"O campo '{campo}' não pode ficar vazio.")
    
    
      if len(valor) > limite:
          raise ValueError(
              f"O campo '{campo}' excede o limite de {limite} caracteres."
          )
    
    
      return valor
    
    
    
    
    def _get_list_by_name(nome_lista: str):
      """Localiza uma lista do quadro pelo nome, sem diferenciar maiúsculas."""
      nome = _normalizar_texto(nome_lista, "nome_lista", 200).casefold()
    
    
      for lista in board.all_lists():
          if lista.name.strip().casefold() == nome:
              return lista
    
    
      return None
    
    
    
    
    def _parse_data_vencimento(data_vencimento: str) -> datetime | None:
      """
      Converte YYYY-MM-DD para o final daquele dia no fuso configurado.
      A validação ocorre antes de qualquer criação/movimentação no Trello.
      """
      if data_vencimento is None:
          return None
    
    
      if not isinstance(data_vencimento, str):
          raise ValueError("A data de vencimento deve ser um texto YYYY-MM-DD.")
    
    
      data_vencimento = data_vencimento.strip()
      if not data_vencimento:
          return None
    
    
      try:
          data = date.fromisoformat(data_vencimento)
      except ValueError as exc:
          raise ValueError(
              "Data inválida. Informe uma data real no formato YYYY-MM-DD."
          ) from exc
    
    
      return datetime.combine(
          data,
          time(hour=23, minute=59, second=0),
          tzinfo=APP_TIMEZONE,
      )
    
    
    
    
    def _enviar_telegram(mensagem: str) -> dict[str, Any]:
      """Envia uma notificação pelo Telegram sem expor o token nos logs."""
      token = os.environ["TELEGRAM_BOT_TOKEN"]
      chat_id = os.environ["TELEGRAM_CHAT_ID"]
      url = f"https://api.telegram.org/bot{token}/sendMessage"
    
    
      try:
          response = requests.post(
              url,
              json={
                  "chat_id": chat_id,
                  "text": mensagem,
              },
              timeout=(5, 15),
          )
          response.raise_for_status()
    
    
          try:
              resultado = response.json()
          except requests.exceptions.JSONDecodeError:
              logger.error("Telegram retornou uma resposta que não é JSON.")
              return {
                  "sucesso": False,
                  "erro": "Resposta inválida recebida do Telegram.",
              }
    
    
          if not resultado.get("ok"):
              descricao = resultado.get("description", "Erro não especificado.")
              logger.warning("Telegram recusou a notificação: %s", descricao)
              return {"sucesso": False, "erro": descricao}
    
    
          return {"sucesso": True, "mensagem": "Notificação enviada."}
    
    
      except requests.Timeout:
          logger.warning("Tempo limite excedido ao enviar mensagem ao Telegram.")
          return {"sucesso": False, "erro": "Tempo limite excedido no Telegram."}
      except requests.RequestException as exc:
          logger.warning("Falha de comunicação com o Telegram: %s", exc)
          return {
              "sucesso": False,
              "erro": "Não foi possível enviar a notificação ao Telegram.",
          }
    
    
    
    
    def _resultado_erro(mensagem: str, exc: Exception | None = None) -> dict[str, Any]:
      """Monta respostas de erro sem devolver detalhes internos ao agente."""
      if exc is not None:
          logger.exception("%s", mensagem, exc_info=exc)
      return {"sucesso": False, "mensagem": mensagem}
    
    
    
    
    # ============================================================
    # FERRAMENTA: CRIAR TAREFA
    # ============================================================
    
    
    def criar_card_trello(
      nome_tarefa: str,
      descricao: str = "",
      data_vencimento: str = "",
    ) -> dict[str, Any]:
      """
      Cria uma tarefa na lista padrão do Trello e tenta notificar pelo Telegram.
    
    
      Args:
          nome_tarefa: Título da tarefa.
          descricao: Descrição opcional.
          data_vencimento: Data opcional no formato YYYY-MM-DD.
      """
      try:
          nome = _normalizar_texto(nome_tarefa, "nome_tarefa", 200)
    
    
          if not isinstance(descricao, str):
              raise ValueError("A descrição deve ser um texto.")
          descricao = descricao.strip()
          if len(descricao) > 10000:
              raise ValueError("A descrição excede 10.000 caracteres.")
    
    
          vencimento = _parse_data_vencimento(data_vencimento)
    
    
          lista = _get_list_by_name(DEFAULT_TRELLO_LIST)
          if lista is None:
              return {
                  "sucesso": False,
                  "mensagem": (
                      f"A lista '{DEFAULT_TRELLO_LIST}' não foi encontrada "
                      "no quadro Trello."
                  ),
              }
    
    
          card = lista.add_card(name=nome, desc=descricao)
    
    
          if vencimento is not None:
              try:
                  card.set_due(vencimento)
              except Exception:
                  # O card já existe; comunicar explicitamente o estado parcial.
                  logger.exception(
                      "Card %s criado, mas houve falha ao configurar vencimento.",
                      card.id,
                  )
                  return {
                      "sucesso": False,
                      "criado": True,
                      "card_id": card.id,
                      "mensagem": (
                          "A tarefa foi criada, mas não foi possível configurar "
                          "a data de vencimento. Verifique o card no Trello."
                      ),
                  }
    
    
          data_formatada = (
              vencimento.strftime("%d/%m/%Y") if vencimento else "Não definido"
          )
    
    
          mensagem = (
              "📌 Nova tarefa criada no Trello!\n\n"
              f"📋 Tarefa: {nome}\n"
              f"📝 Descrição: {descricao or 'Não informada'}\n"
              f"📅 Vencimento: {data_formatada}"
          )
          notificacao = _enviar_telegram(mensagem)
    
    
          return {
              "sucesso": True,
              "mensagem": "Tarefa criada no Trello.",
              "card_id": card.id,
              "nome": nome,
              "lista": lista.name,
              "vencimento": data_formatada,
              "notificacao_telegram": notificacao,
          }
    
    
      except ValueError as exc:
          return {"sucesso": False, "mensagem": str(exc)}
      except Exception:
          logger.exception("Erro inesperado ao criar tarefa no Trello.")
          return {
              "sucesso": False,
              "mensagem": "Não foi possível criar a tarefa no Trello.",
          }
    
    
    
    
    # ============================================================
    # FERRAMENTA: LISTAR TAREFAS
    # ============================================================
    
    
    def listar_tarefas() -> dict[str, Any]:
      """Lista os cards abertos do quadro Trello, incluindo lista e vencimento."""
      try:
          cards = board.open_cards()
          tarefas = []
    
    
          for card in cards:
              vencimento = card.due
              if vencimento:
                  vencimento = str(vencimento)
    
    
              tarefas.append(
                  {
                      "id": card.id,
                      "nome": card.name,
                      "lista": card.list_name,
                      "vencimento": vencimento,
                      "url": getattr(card, "url", None),
                  }
              )
    
    
          return {
              "sucesso": True,
              "total": len(tarefas),
              "tarefas": tarefas,
          }
    
    
      except Exception:
          logger.exception("Erro ao listar tarefas do Trello.")
          return {
              "sucesso": False,
              "mensagem": "Não foi possível listar as tarefas do Trello.",
          }
    
    
    
    
    # ============================================================
    # FERRAMENTA: MOVER TAREFA
    # ============================================================
    
    
    def mover_card(
      identificador: str,
      lista_destino: str,
    ) -> dict[str, Any]:
      """
      Move um card para outra lista do Trello.
    
    
      Args:
          identificador: ID do card ou nome exato da tarefa.
          lista_destino: Nome da lista de destino.
      """
      try:
          identificador = _normalizar_texto(
              identificador, "identificador", 200
          )
          lista_destino = _normalizar_texto(
              lista_destino, "lista_destino", 200
          )
    
    
          cards = board.open_cards()
    
    
          # Prioriza correspondência exata pelo ID.
          card = next((item for item in cards if item.id == identificador), None)
    
    
          if card is None:
              encontrados = [
                  item
                  for item in cards
                  if item.name.strip().casefold() == identificador.casefold()
              ]
    
    
              if not encontrados:
                  return {
                      "sucesso": False,
                      "mensagem": "Tarefa não encontrada entre os cards abertos.",
                  }
    
    
              if len(encontrados) > 1:
                  return {
                      "sucesso": False,
                      "mensagem": (
                          "Há várias tarefas com esse nome. Informe o ID "
                          "do card para evitar mover a tarefa errada."
                      ),
                      "cards_encontrados": [
                          {"id": item.id, "nome": item.name}
                          for item in encontrados
                      ],
                  }
    
    
              card = encontrados[0]
    
    
          destino = _get_list_by_name(lista_destino)
          if destino is None:
              return {
                  "sucesso": False,
                  "mensagem": f"A lista de destino '{lista_destino}' não existe.",
              }
    
    
          if getattr(card, "list_id", None) == destino.id:
              return {
                  "sucesso": True,
                  "mensagem": "A tarefa já está na lista solicitada.",
                  "card_id": card.id,
                  "lista_destino": destino.name,
              }
    
    
          card.change_list(destino.id)
    
    
          # Recarrega os dados para confirmar a alteração no Trello.
          card_atualizado = trello.get_card(card.id)
          lista_confirmada = getattr(card_atualizado, "list_name", None)
    
    
          mensagem = (
              "🔄 Tarefa movimentada no Trello!\n\n"
              f"📋 Tarefa: {card.name}\n"
              f"📍 Nova lista: {destino.name}"
          )
          notificacao = _enviar_telegram(mensagem)
    
    
          return {
              "sucesso": True,
              "mensagem": "Solicitação de movimentação concluída.",
              "card_id": card.id,
              "lista_destino": lista_confirmada or destino.name,
              "notificacao_telegram": notificacao,
          }
    
    
      except ValueError as exc:
          return {"sucesso": False, "mensagem": str(exc)}
      except Exception:
          logger.exception("Erro ao mover tarefa no Trello.")
          return {
              "sucesso": False,
              "mensagem": "Não foi possível mover a tarefa no Trello.",
          }
    
    
    
    
    # ============================================================
    # AGENTE GOOGLE ADK
    # ============================================================
    
    
    root_agent = Agent(
      name="agente_produtividade",
      model=GOOGLE_MODEL,
      description=(
          "Assistente de produtividade integrado ao Trello e Telegram. "
          "Cria, consulta e movimenta tarefas."
      ),
      instruction="""
    Você é um assistente pessoal de produtividade integrado ao Trello.
    
    
    FERRAMENTAS DISPONÍVEIS:
    1. criar_card_trello: cria uma tarefa na lista padrão configurada.
    2. listar_tarefas: consulta os cards abertos do quadro.
    3. mover_card: move uma tarefa para outra lista.
    
    
    REGRAS OBRIGATÓRIAS:
    - Use as ferramentas para consultar ou alterar dados do Trello.
    - Nunca diga que uma tarefa foi criada ou movida sem retorno de sucesso
    da ferramenta.
    - Diferencie falha total de operação parcial. Por exemplo, a tarefa pode
    ter sido criada mesmo que a configuração do vencimento tenha falhado.
    - Não invente IDs, nomes de listas, datas ou informações de tarefas.
    - Antes de criar uma tarefa, obtenha o título. A descrição e a data são
    opcionais; não invente esses dados.
    - A data deve ser enviada no formato YYYY-MM-DD. Se o usuário disser
    "amanhã" ou outra data relativa, determine a data somente se o contexto
    de data atual estiver disponível; caso contrário, peça esclarecimento.
    - Para mover uma tarefa, obtenha o identificador e a lista de destino.
    - Se houver tarefas com nomes duplicados, peça o ID do card.
    - Não exclua tarefas: não existe ferramenta de exclusão disponível.
    - Informe quando a notificação do Telegram falhar, sem afirmar que a
    operação principal falhou se o Trello confirmou a alteração.
    - Responda em português, com clareza e objetividade.
    """,
      tools=[
          criar_card_trello,
          listar_tarefas,
          mover_card,
      ],
    )
    
    
    

    A proposta é facilitar a organização pessoal e profissional, permitindo que o usuário gerencie tarefas por meio de comandos em linguagem natural.

    🎯 Objetivos

    • Automatizar a criação de tarefas.
    • Consultar tarefas cadastradas no Trello.
    • Movimentar cartões entre listas.
    • Enviar notificações pelo Telegram.
    • Integrar inteligência artificial a ferramentas de produtividade.
    • Praticar desenvolvimento Python e integração com APIs.

    ✨ Funcionalidades

    1. Criar tarefas no Trello

    A ferramenta criar_card_trello permite criar cartões na lista A Fazer, incluindo:

    image

    • Nome da tarefa.
    • Descrição.
    • Data de vencimento opcional.

    Lista A Fazer

    image

    Após a criação, o sistema tenta enviar uma notificação pelo Telegram.

    image

    2. Listar tarefas

    A ferramenta listar_tarefas consulta os cartões abertos do quadro Trello e retorna informações como:

    • Identificador do cartão.
    • Nome da tarefa.
    • Lista em que está localizada.
    • Data de vencimento, quando disponível.

    3. Mover tarefas entre listas

    A ferramenta mover_card permite transferir um cartão para outra lista do quadro.

    image

    A tarefa pode ser identificada pelo ID ou pelo nome exato. Quando existem tarefas com nomes duplicados, o sistema solicita o identificador para evitar ambiguidades.

    image

    4. Notificações pelo Telegram

    A função _enviar_telegram envia mensagens por meio da API oficial do Telegram.

    As notificações incluem informações sobre tarefas criadas ou movimentadas. Falhas de comunicação são tratadas pela aplicação.

    image

    5. Configuração por variáveis de ambiente

    As credenciais e configurações são carregadas de um arquivo .env, evitando a necessidade de inserir chaves de API diretamente no código-fonte.

    6. Registro de eventos

    O módulo logging registra informações e erros que ajudam na identificação de problemas durante a execução.

    🏗️ Arquitetura do projeto

    Agente_de_Produtividade_com_IA_Google_ADK_Trello_Telegram/
    │
    ├── .env
    ├── .gitignore
    ├── requirements.txt
    │
    └── agente_produtividade/
      ├── __init__.py
      └── agent.py
    

    📋 Pré-requisitos

    Antes de executar o projeto, você precisará de:

    • Python instalado.
    • Uma chave de API do Google AI.
    • Uma conta Trello com acesso ao quadro desejado.
    • Uma chave de API e um token de acesso do Trello.
    • Um bot do Telegram e o respectivo ID do chat.
    • Acesso à internet para comunicação com as APIs.

    🚀 Instalação

    1. Clonar o repositório

    git clone https://github.com/wandreson-silva/Agente_de_Produtividade_com_IA_Google_ADK_Trello_Telegram
    cd Agente_de_Produtividade_com_IA_Google_ADK_Trello_Telegram
    

    2. Criar um ambiente virtual

    No Windows PowerShell:

    python -m venv .venv
    

    Ative o ambiente:

    .\.venv\Scripts\Activate.ps1
    

    3. Instalar as dependências

    python -m pip install --upgrade pip
    python -m pip install google-adk py-trello requests python-dotenv
    

    4. Configurar as variáveis de ambiente

    Crie um arquivo .env na raiz do projeto:

    # Google Gemini
    GOOGLE_API_KEY=SUA_CHAVE_GOOGLE
    GOOGLE_MODEL=MODELO_GEMINI_DISPONIVEL
    
    # Trello
    TRELLO_API_KEY=SUA_CHAVE_TRELLO
    TRELLO_TOKEN=SEU_TOKEN_TRELLO
    TRELLO_BOARD_ID=ID_DO_QUADRO
    
    # Telegram
    TELEGRAM_BOT_TOKEN=TOKEN_DO_BOT
    TELEGRAM_CHAT_ID=ID_DO_CHAT
    

    Utilize credenciais válidas e substitua os valores de exemplo. O nome do modelo deve corresponder a um modelo disponível para sua conta e compatível com a versão instalada do Google ADK.

    ▶️ Executar o agente

    Na raiz do projeto, com o ambiente virtual ativado:

    adk run agente_produtividade2
    

    Para iniciar a interface web de desenvolvimento do Google ADK:

    adk web
    

    Siga as instruções exibidas no terminal para acessar a interface.

    🧪 Exemplos de utilização

    Os exemplos abaixo ilustram solicitações que o agente pode interpretar, desde que as integrações estejam configuradas corretamente.

    Criar tarefa:

    Crie uma tarefa chamada "Revisar projeto elétrico",
    com descrição "Verificar os diagramas e circuitos"
    e vencimento em 2026-12-15.
    

    Listar tarefas:

    Liste as tarefas abertas do meu quadro Trello.
    

    Mover tarefa:

    Mova a tarefa "Revisar projeto elétrico"
    para a lista "Em andamento".
    

    Os nomes das listas precisam corresponder às listas existentes no quadro Trello.

    🔐 Segurança

    Para proteger credenciais e informações de acesso:

    • Nunca publique o arquivo .env.
    • Não insira tokens ou chaves de API diretamente no código.
    • Utilize um arquivo .gitignore.
    • Não compartilhe logs que possam conter informações confidenciais.
    • Restrinja o acesso às credenciais do Trello e do Telegram.
    • Revogue e substitua imediatamente qualquer credencial exposta.
    • Utilize apenas quadros e contas para os quais tenha autorização.

    Exemplo de .gitignore:

    .env
    .venv/
    __pycache__/
    *.py[cod]
    *.log
    logs/
    

    ⚠️ Limitações conhecidas

    • A criação de tarefas utiliza a lista configurada como A Fazer.
    • A listagem considera cartões abertos do quadro.
    • A movimentação depende da existência da lista de destino.
    • As notificações dependem da disponibilidade da API do Telegram.
    • O envio de uma notificação pode falhar mesmo quando a operação no Trello foi concluída.
    • O projeto depende de credenciais válidas, conectividade e compatibilidade entre as dependências instaladas.
    • O script original não implementa exclusão de tarefas, autenticação de usuários na aplicação ou persistência local adicional.

    🔧 Possíveis melhorias futuras

    • Adicionar prioridades e etiquetas às tarefas.
    • Implementar edição de cartões e atualização de vencimentos.
    • Criar lembretes automáticos.
    • Implementar relatórios diários e semanais.
    • Adicionar testes automatizados com pytest.
    • Implementar validação mais rigorosa dos dados de entrada.
    • Criar uma interface web com FastAPI.
    • Adicionar persistência complementar com SQLite.
    • Implementar monitoramento e histórico de operações.
    • Adicionar controle de acesso e mecanismos contra operações duplicadas.

    📚 Aprendizados

    Este projeto permite explorar conceitos importantes de desenvolvimento e automação:

    • Desenvolvimento de agentes de inteligência artificial.
    • Integração de APIs REST.
    • Programação em Python.
    • Gerenciamento de variáveis de ambiente.
    • Automação de tarefas.
    • Tratamento de exceções.
    • Registro de eventos e diagnóstico de erros.
    • Integração entre serviços digitais.

    👨‍💻 Autor

    Wandreson Silva

    Engenharia Elétrica | Automação | Tecnologia | Python | Inteligência Artificial | Cibersegurança

    https://github.com/wandreson-silva/Agente_de_Produtividade_com_IA_Google_ADK_Trello_Telegram

    Compartilhe
    Recomendados para você
    Neo4j - Certification
    DXC - IA do Zero ao Primeiro Agente
    Reclame AQUI - Dados e IA na Prática
    Comentários (0)