This bot allows you to log daily health metrics (like weight, sleep, steps) and meals via Telegram. It parses meal descriptions, looks up nutritional information (using Google Gemini), and records the data in a designated Google Sheet.
- Multi-Bot Support: Run multiple independent bot instances from a single application deployment. Each bot uses its own configuration (Google Sheet, allowed users).
- Log various health metrics for specific dates (defaults to today).
- Log meals using natural language descriptions (e.g., "150g chicken and 1 cup broccoli"), by sending photos, or via voice/audio messages within the /newlog conversation.
- Automatically calculates estimated Calories, Protein, Carbs, Fat, and Fiber for meals using Google Gemini.
- Adds meal nutrition data cumulatively to the specified date in the bot's designated Google Sheet.
- Updates other metrics (Weight, Sleep, etc.) by overwriting the value for the specified date in the bot's designated Google Sheet.
- Uses Google Sheets as the data backend (one sheet per configured bot).
- Optional configuration to restrict bot usage to specific Telegram User IDs.
-
Prerequisites:
- Python 3.10+
- Google Cloud Platform (GCP) Account
- Telegram Account
- Docker and Docker Compose
jqcommand-line tool (for local webhook setup inrun_local.sh, e.g.,brew install jqorsudo apt-get install jq)
-
Clone the Repository:
git clone <your-repo-url> cd <your-repo-directory>
-
Create Telegram Bots:
- Talk to
@BotFatheron Telegram. - Create one or more new bots using
/newbot. - Note down the HTTP API Token for each bot.
- Talk to
-
Google Cloud Setup (for Google Sheets):
- Create a GCP Project (or use an existing one).
- Enable APIs: Enable the Google Sheets API.
- Create Service Account:
- Create a service account (e.g.,
sheets-multi-bot-writer). - Grant it the "Editor" role (or more granular permissions) for the project or specific Sheets.
- Create and download a JSON key file for this service account.
- Create a service account (e.g.,
- Store Service Account Key: Securely store this key file (e.g., as a secret file in Render, or accessible via path locally). DO NOT commit it to Git.
-
Google Sheets:
- Create a separate Google Sheet for each bot you plan to configure.
- Ensure each sheet has the correct header rows and column order (see example
Sai Metrics - Metrics.csv). - Note down the Sheet ID for each sheet from its URL.
- Share each Sheet: Share each Google Sheet with the client_email found inside the service account JSON file, giving it Editor access.
-
API Keys:
- Gemini API Key: Obtain from Google AI Studio.
-
Configuration:
- Environment Variables (Required for Deployment & Local):
GEMINI_API_KEY: Your Gemini API Key.- Set ONE of the following for the Google Service Account:
GOOGLE_APPLICATION_CREDENTIALS: Path to the service account JSON key file (e.g.,/etc/secrets/service-account.jsonin Render, or a local path).SERVICE_ACCOUNT_JSON: The content (string) of the service account JSON key.
BOT_CONFIG_PATH(Optional): Path to the bot configuration JSON file. Defaults tobot_configs.jsonin the project root.
bot_configs.jsonfile (Required):- Create a file named
bot_configs.jsonin the project root (or the path specified byBOT_CONFIG_PATH). - This file contains a JSON array (
[]) of configuration objects, one for each bot. - Structure:
[ { "bot_token": "YOUR_FIRST_BOT_TOKEN_HERE", "google_sheet_id": "YOUR_FIRST_BOT_SHEET_ID_HERE", "schema_type": "template", // Optional: "template" (default) or "legacy" "worksheet_name": "Sheet1", // Optional, defaults to Sheet1 "allowed_users": [123456789] // Optional, empty list [] allows all users }, { "bot_token": "YOUR_SECOND_BOT_TOKEN_HERE", "google_sheet_id": "YOUR_SECOND_BOT_SHEET_ID_HERE", "schema_type": "legacy" // Example: Use the legacy schema // worksheet_name defaults to Sheet1 // allowed_users defaults to [] (allow all) } // Add more bot configurations as needed ] schema_type: Determines column mapping and the first data row (0-based index: 1 for "template", 9 for "legacy"). Use"template"for new sheets based on the provided template, or"legacy"for the original format.- Ensure
bot_configs.jsonis added to your.gitignorefile!
- Create a file named
- Local
.envfile (For Development ONLY):- You can place the environment variables (
GEMINI_API_KEY,GOOGLE_APPLICATION_CREDENTIALSorSERVICE_ACCOUNT_JSON,BOT_CONFIG_PATH) in a.envfile for local development convenience. Therun_local.shscript also requiresNGROK_AUTH_TOKENin.env. - Example
.env:GEMINI_API_KEY=YOUR_GEMINI_API_KEY_PLACEHOLDER GOOGLE_APPLICATION_CREDENTIALS=./path/to/your/local-service-account.json # Or use SERVICE_ACCOUNT_JSON="{...}" BOT_CONFIG_PATH=./bot_configs.json # Optional, defaults to ./bot_configs.json NGROK_AUTH_TOKEN=YOUR_NGROK_TOKEN_FROM_NGROK_DASHBOARD
- Ensure
.envis added to your.gitignorefile!
- You can place the environment variables (
- Environment Variables (Required for Deployment & Local):
This application is designed to be deployed as a Docker container using Render.
Render deploys automatically based on commits to the linked Git repository branch (e.g., main).
- Prerequisites:
- Code pushed to a Git provider (GitHub, GitLab, Bitbucket).
- Render account created and connected to the Git provider.
- A "Web Service" created on Render, linked to the correct repository and branch.
- Configuration (Render Dashboard):
- Runtime: Set to
Docker. - Health Check Path: Set to
/health. - Environment Variables & Secrets: Configure the following in the service's "Environment" section:
- Regular Variables:
GEMINI_API_KEY,PYTHON_VERSION(e.g.,3.10),PORT(e.g.,8080). - Secret Files:
- Add a secret file named
service-account.jsoncontaining the Google Service Account JSON key content. - Add another secret file named
bot_configs.jsoncontaining the JSON array of your bot configurations.
- Add a secret file named
- Add Environment Variables:
GOOGLE_APPLICATION_CREDENTIALSwith the value/etc/secrets/service-account.json.BOT_CONFIG_PATHwith the value/etc/secrets/bot_configs.json.
- Regular Variables:
- Runtime: Set to
- Deployment Workflow:
- Commit and push changes to the linked branch.
- Render automatically builds and deploys.
- Initial Webhook Setup (Per Bot): After the first successful deployment, manually set the Telegram webhook for each bot to point to its specific Render service URL path:
(This only needs to be done once per bot, not for subsequent code deployments).
# For Bot 1: curl -F "url=https://<your-render-service-url>/webhook/<YOUR_FIRST_BOT_TOKEN>" \ https://api.telegram.org/bot<YOUR_FIRST_BOT_TOKEN>/setWebhook # For Bot 2: curl -F "url=https://<your-render-service-url>/webhook/<YOUR_SECOND_BOT_TOKEN>" \ https://api.telegram.org/bot<YOUR_SECOND_BOT_TOKEN>/setWebhook # Repeat for all configured bots...
Talk to any of your configured bots on Telegram:
/start: Get a welcome message./help: See command usage details./log [date] [metric] [value]: Log data (see/helpfor examples). Note: Does not support audio logging./newlog: Start a guided conversation to log multiple items. Supports text, photo, and voice/audio input for meals./daily_summary: Show today's calories, macros (Protein, Carbs, Fat, Fiber), and steps./weekly_summary: Show average sleep, weight, steps, and calories for the current week (starting from the most recent Sunday)./cancel: Cancel the current conversation if it's stuck or you want to start over.
Data will be logged to the Google Sheet associated with the specific bot you are interacting with.
There are two ways to run the application locally:
Use the provided run_local.sh script:
# Ensure Docker Desktop is running
# Run locally
./scripts/run_local.sh
# Run locally with live code reloading
./scripts/run_local.sh --watchThis script handles:
- Checking for
NGROK_AUTH_TOKENin.env(required). - Starting the
botandngrokservices viadocker compose. - Waiting for the ngrok tunnel to be ready.
- Automatically setting the webhook for each bot listed in
bot_configs.jsonto point to the correct ngrok URL (e.g.,https://<random-id>.ngrok.io/webhook/<BOT_TOKEN>). This requiresjqto be installed locally. - Providing live reload in
--watchmode.
Important: Ensure your .env file and bot_configs.json are correctly set up locally before running the script.
Logs & Control:
- Follow logs:
docker compose logs -f bot - Stop:
docker compose down - Ngrok UI:
http://localhost:4040
Use the run_local_no_docker.sh script. This runs the application directly on your machine using your local Python installation.
Prerequisites:
- Python 3.10+ installed locally.
pipinstalled locally.ngrokcommand-line tool installed locally and authenticated (orNGROK_AUTH_TOKENset in.env).jqcommand-line tool installed locally.
Steps:
- Create and activate a Python virtual environment (Recommended):
python3 -m venv .venv source .venv/bin/activate - Ensure
.envandbot_configs.jsonare configured. - Run the script:
bash scripts/run_local_no_docker.sh
This script handles:
- Checking for local dependencies (
python3,pip,ngrok,jq). - Loading
.envvariables. - Configuring
ngrokwithNGROK_AUTH_TOKENif found. - Upgrading
pipand installing dependencies fromrequirements.txt(within the virtual environment if active). - Starting
ngrokand the FastAPI application (uvicorn) as background processes. - Waiting for both services to become ready.
- Automatically setting the webhook for each bot listed in
bot_configs.jsonto point to the correct ngrok URL.
Logs & Control:
- Follow app logs:
tail -f uvicorn.log - Follow ngrok logs:
tail -f ngrok.log - Stop: Press
Ctrl+Cin the terminal where the script is running. - Ngrok UI:
http://localhost:4040
Unit tests are located in the tests/ directory. To run them locally:
-
Install Dependencies: Ensure you have installed the project dependencies, preferably in a virtual environment:
# If not already done for local development python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt
-
Run All Tests: Use the
unittestdiscovery mechanism from the project root directory:python -m unittest discover tests
-
Run Tests for a Specific Module: To run tests only for a specific part (e.g., the command handlers):
python -m unittest discover tests/bot/commands
-
Run a Specific Test File:
python -m unittest tests/bot/commands/test_log_command.py
.
├── src/ # Source code directory
│ ├── app.py # FastAPI application entry point & webhook handlers
│ ├── bot/ # Bot logic and handlers
│ │ ├── bot_logic.py # Main PTB Application setup, conversation handler structure
│ │ ├── direct_commands.py # Handlers for direct commands (/start, /help, /log)
│ │ ├── conversation_handlers.py # Handlers for /newlog conversation states
│ │ ├── helpers.py # Helper functions used by bot handlers
│ │ └── __init__.py
│ ├── config/ # Configuration loading and definitions
│ │ ├── config_loader.py # Loads bot configurations from file/env
│ │ ├── config.py # Defines dataclasses for config, constants
│ │ └── __init__.py
│ ├── services/ # Core services (external APIs, parsing)
│ │ ├── sheets_handler.py # Interacts with Google Sheets API
│ │ ├── meal_parser.py # Parses meal text/images using Gemini
│ │ ├── audio_processor.py # Transcribes voice/audio messages using Gemini
│ │ ├── nutrition_api.py # Fetches nutrition data from USDA API
│ │ ├── ai_models.py # Initializes AI models (e.g., Gemini)
│ │ └── __init__.py
│ ├── utils.py # Shared utility functions
│ └── __init__.py
├── scripts/ # Utility scripts
│ └── run_local.sh # Local development runner & multi-webhook setup
├── tests/ # Unit/integration tests (Placeholder)
├── .github/ # GitHub Actions workflows (e.g., CI/CD)
├── .env # Local environment variables (DO NOT COMMIT!)
├── .gitignore # Git ignore rules
├── .dockerignore # Docker ignore rules
├── .python-version # Specifies Python version (e.g., for pyenv)
├── bot_configs.json # Bot configurations (DO NOT COMMIT!)
├── docker-compose.yml # Docker Compose configuration for local dev
├── Dockerfile # Docker configuration for deployment
├── requirements.txt # Python dependencies
├── README.md # This file
├── service-account-key.json # Google Service Account Key (DO NOT COMMIT!)
├── setup_webhook.sh # Manual script to set webhook (e.g., for Render initial setup)
src/app.py: FastAPI app, handles dynamic/webhook/{bot_token}requests, initializes the correctBotinstance per request, routes updates to PTB.src/bot/directory: Contains all logic related to the Telegram bot interaction usingpython-telegram-bot.bot_logic.py: Sets up the maintelegram.ext.Applicationand registers all command, message, and conversation handlers.direct_commands.py: Implements handlers for simple, one-off commands like/start,/help, and/log.conversation_handlers.py: Implements the state machine and handlers for the multi-step/newlogconversation.helpers.py: Contains utility functions specifically for the bot handlers (e.g., getting bot config, error handling).
src/config/config_loader.py: Loads shared config and bot-specific configs frombot_configs.jsonand environment variables.src/services/directory: Contains modules responsible for interacting with external APIs and performing core data processing.sheets_handler.py: Interacts with Google Sheets API.meal_parser.py: Parses meal text/images using Gemini.audio_processor.py: Transcribes voice/audio messages using Gemini.nutrition_api.py: Fetches nutrition data from USDA API.ai_models.py: Initializes AI models (e.g., Gemini).
src/utils.py: Contains general utility functions used across the application.bot_configs.json: Defines configurations for multiple bots (tokens, sheet IDs, allowed users, schema_type).scripts/run_local.sh: Sets up local dev environment and configures webhooks for all bots defined inbot_configs.jsonusing ngrok.setup_webhook.sh: Manual script primarily for setting webhooks in a deployed environment like Render whererun_local.shisn't applicable.- (Other components as previously described - Docker config etc.)
- "Chat not found" errors: Ensure the correct bot token is being used (check logs vs
bot_configs.json), the bot hasn't been blocked by the user, and the webhook is set correctly for that specific bot token (/webhook/<TOKEN>). - Config not found: Verify
BOT_CONFIG_PATHenvironment variable (if used) points to the correct location, or thatbot_configs.jsonexists at the project root/container path. Check file permissions. - Webhook errors: Check the output of
./scripts/run_local.shor your manualcurlcommands when setting webhooks. Ensure the ngrok/Render URL is correct and reachable. - Docker errors: Check
docker compose logsfor build or runtime errors.
This directory contains template files for setting up your Google Sheet to work with the Calorie Tracker Bot:
-
docs/template_sheet_schema.md- Detailed documentation of the required Google Sheets structure, including:- Column specifications and data types
- Setup instructions
- Configuration steps
- Tips and troubleshooting
-
docs/template_sheet.csv- A CSV file that you can import into Google Sheets to quickly create a properly formatted sheet:- Contains all required column headers
- Includes an example row showing correct data formats
- Can be imported directly into Google Sheets
- Create a new Google Sheet
- Go to File > Import > Upload > Select
docs/template_sheet.csv - Choose "Replace current sheet" when importing
- Name your worksheet "Daily Tracking" (or update the config to match your chosen name)
- Share the sheet with your bot's service account email
- Copy the Google Sheet ID from the URL
- Update your bot's configuration with the Sheet ID
For complete setup instructions and schema details, please refer to docs/template_sheet_schema.md.