Files
obsidian-yanxin/notes/martial_arts/TELEGRAM_BOT_PLAN.md
2026-02-11 12:38:36 -08:00

5.1 KiB

Plan: Telegram Bot for Martial Arts Note Conversion

Goal

Build a Telegram bot (bot.py, ~100 lines of Python) that receives photos of handwritten martial arts notes, uses Claude API to transcribe them, and commits the resulting markdown files to the Gitea repo on your VPS.

How It Works

Your Phone (Telegram)      bot.py (VPS)                External
─────────────────          ────────────                ────────
Send photos                Bot polls Telegram ─────────→ Telegram API
              ←────────────  Download photos
                             Send to Claude API ───────→ Claude (vision)
                             ← JSON response ←───────── Returns markdown +
                                                          art/instructor/date
                             Create file via ──────────→ Gitea API (localhost)
                             Gitea API
Reply "Done!" ←────────────

User Flow

  1. Finish martial arts class, take photos of notebook pages
  2. Open Telegram, send photos to your bot
  3. Bot replies: "Done! Committed 八极拳/baji-2025.02.12-vincent.md"
  4. Next time you open Obsidian or pull the repo, the note is there

Tech Stack

  • Python 3 (already on VPS) with 3 libraries:
    • python-telegram-bot — polls Telegram for photos (no port/SSL needed)
    • anthropic — send photos to Claude for transcription
    • requests — call Gitea API (localhost)
  • Runs on: your Vultr VPS, in a tmux/screen session
  • Cost: only Claude API usage (~$0.01-0.05 per set of photos)

Three Tokens (one-time setup)

  1. Telegram bot token — message @BotFather on Telegram, free
  2. Claude API key — from console.anthropic.com
  3. Gitea API token — from your Gitea instance (Settings > Applications > Generate Token)

Code Structure

Single-file bot (bot.py) with clear separation between handlers. To add new features later, add a new handler function and register it — no restructuring needed.

Structure of bot.py

# --- Config ---
# Load .env tokens

# --- Handlers ---
# Each feature is a handler function registered with the bot

async def handle_photos(update, context):
    """Martial arts note conversion: photos → markdown → Gitea"""
    ...

# async def handle_future_feature(update, context):
#     """Add new features here"""
#     ...

# --- Main ---
# Register handlers and start polling
app.add_handler(MessageHandler(filters.PHOTO, handle_photos))
# app.add_handler(...)  # register new handlers here
app.run_polling()

1. handle_photos() — Telegram handler

  • Triggered when user sends photos
  • Groups multiple photos sent within 30 seconds as pages of one lesson
  • Downloads photos from Telegram
  • Calls transcribe() then commit_to_gitea()
  • Replies with confirmation

2. transcribe(photos) — Claude API call

  • Sends all photos to Claude API in one vision call
  • Prompt asks Claude to:
    • Transcribe the handwritten notes (English + Chinese)
    • Identify: martial art, instructor, date, lesson number
    • Return structured JSON with metadata + full markdown
  • Uses the same format template and title conventions from CONVERSION_PLAN.md

3. commit_to_gitea(metadata, markdown) — Gitea API call

  • Determines directory from art type:
    • FMA/Silat/SEAMA → notes/martial_arts/FMA/
    • 八极拳 → notes/martial_arts/八极拳/
    • 劈挂拳 → notes/martial_arts/八极拳/
    • Other → notes/martial_arts/
  • Constructs filename: <art>-<YYYY.MM.DD>-<instructor>.md
  • Calls Gitea API to create the file:
    POST http://localhost:8003/api/v1/repos/{owner}/{repo}/contents/{filepath}
    Body: { "content": base64(markdown), "message": "Add note: ..." }
    

Files to Create

telegram-bot/
└── bot.py              # Everything in one file (config + logic)

Config

Tokens are defined at the top of bot.py:

# --- Config (edit these) ---
TELEGRAM_TOKEN = "your-telegram-token"
ANTHROPIC_API_KEY = "your-claude-key"
GITEA_URL = "http://localhost:8003"
GITEA_TOKEN = "your-gitea-token"
GITEA_REPO = "lyx/obsidian-yanxin"

Note: Since tokens are in the source file, don't commit bot.py to a public repo. Your Gitea instance is private, so this is fine there.

Deployment

  1. Create Telegram bot via @BotFather
  2. Get Claude API key from console.anthropic.com
  3. Generate Gitea API token from your Gitea instance
  4. On the VPS:
    pip install python-telegram-bot anthropic requests
    # Copy bot.py to the VPS and edit the config section at the top with your tokens
    python bot.py        # run in tmux/screen to keep alive
    

Resource Usage

  • Memory: ~30MB Python process
  • CPU: Near zero when idle
  • Fine for 1vCPU / 2GB VPS

Verification

  1. Send a test photo of handwritten notes to the bot on Telegram
  2. Bot replies with filename and summary
  3. Check Gitea web UI — new .md file appears in the correct directory
  4. Pull in Obsidian on your computer — note shows up with correct frontmatter