Skip to main content

Telegram + FastAPI ingestion core with pluggable publication backends

Project description

telegras

Standalone Telegram ingestion core extracted from tg-wp-bridge.

telegras architecture

telegras is a focused Telegram + FastAPI ingestion core offering:

  • Async ingestion service and backend abstraction (PublishBackend)
  • Async SQLAlchemy persistence (default sqlite+aiosqlite:///./data/telegras.db)
  • OpenAPI endpoints for persisted interactions/publications
  • Alembic migrations (telegras db-init, telegras backends)

The plugin-capable handler registry lets downstream packages (like tg-wp-bridge) register WordPress publishing via telegras.default_handlers.handler_plugin.

Concept

[Telegram Channel]
        |
        | (forwarded via bot)
        v
[Telegram Bot Webhook (our service, in Docker)]
        |
        | 1. Parse message (text + media URLs)
        | 2. Optionally download media
        | 3. POST to WordPress REST API
        v
[WordPress REST API]
        |
        v
[New Post in Category X]

Each channel message becomes a WordPress post:

  • Text → post title & content
  • Media (photos, videos, documents) → uploaded to WordPress and embedded

No WordPress plugin required; uses built-in REST API + Application Passwords.

Parsed Telegram API

The generated Telegram Bot API models live in tg_api_parsed. They are copied from the reviewed telegram-api-extract artifacts and expose only the types used by telegras:

  • tg_api_parsed.Update
  • tg_api_parsed.WebhookInfo
  • tg_api_parsed.SetWebhookRequest
  • tg_api_parsed.SendMessageRequest
  • tg_api_parsed.GetMeResponse

CI & Releases

  • CI: ci.yml runs uv run pytest -q and uv run --extra docs mkdocs build --strict on pushes/PRs against main.
  • Releases: publish.yml triggers on push tags v*, builds the package, checks artifacts, and publishes to PyPI. Configure a PyPI trusted publisher (OIDC) so secrets.PYPI_TOKEN can stay empty while GitHub forwards identity securely. If you prefer the classic API token, create a repository secret named PYPI_TOKEN.

Local development

  • Install: uv pip install -e .[dev]
  • Run API: uv run uvicorn telegras.app:app --reload
  • Run tests: uv run pytest

Bot mode

Set BOT_MODE to control update transport:

  • webhook (default)
  • polling

Examples:

  • BOT_MODE=webhook uv run uvicorn telegras.app:app --reload
  • BOT_MODE=polling uv run uvicorn telegras.app:app --reload

API submodule

telegras now includes a curated Telegram API runtime subset in telegras.api:

  • telegras.api.client.TelegramBotAPI
  • telegras.api.getting_updates (Update, WebhookInfo, SetWebhookRequest)
  • telegras.api.methods (SendMessageRequest, GetMeResponse)

This subset is extracted from reviewed generated specs in docs/telegram_api/ and used by telegras.telegram_api.

Webhook Attachments

Webhook attachments are composable match rules bound to handler identifiers.

Attachment schema

{
  "name": "blog-channel",
  "handler": "handlers.python:eval",
  "handler_args": ["result = '{{ message.title }}'"],
  "enabled": true,
  "priority": 10,
  "stop_on_match": false,
  "when": {
    "op": "all",
    "children": [
      {
        "op": "leaf",
        "leaf": {
          "field": "chat.type",
          "match": "eq",
          "value": "channel"
        }
      },
      {
        "op": "leaf",
        "leaf": {
          "field": "message.text",
          "match": "regex",
          "value": "#blog\\b"
        }
      }
    ]
  }
}

API endpoints

  • GET /v1/webhook-attachments
  • POST /v1/webhook-attachments
  • DELETE /v1/webhook-attachments/{name}
  • POST /v1/webhook-attachments/match
  • POST /v1/webhook-attachments/execute

Protected introspection API

Set INTROSPECTION_TOKEN and call with Authorization: Bearer <token>.

  • GET /internal/introspection/config
  • GET /internal/introspection/attachments
  • POST /internal/introspection/attachments
  • PUT /internal/introspection/attachments/{name}
  • DELETE /internal/introspection/attachments/{name}
  • GET /internal/introspection/webhook-executions
  • GET /internal/introspection/handlers
  • GET /internal/introspection/match-criteria

Exact examples

Register a shell listing handler:

{
  "name": "list-temp",
  "handler": "handlers.shell:ls",
  "handler_args": ["/home", "/tmp"],
  "when": {
    "op": "leaf",
    "leaf": {
      "field": "chat.type",
      "match": "eq",
      "value": "group"
    }
  }
}

Register a Python eval handler with parse-result templates:

{
  "name": "mail-on-title",
  "handler": "handlers.python:eval",
  "handler_args": [
    "import mails",
    "mails.send_mail('{{ message.title }}')",
    "log.info(f\"full message: {{ message.full }}\")"
  ],
  "when": {
    "op": "all",
    "children": [
      {
        "op": "leaf",
        "leaf": {
          "field": "chat.type",
          "match": "eq",
          "value": "group"
        }
      },
      {
        "op": "leaf",
        "leaf": {
          "field": "message.text",
          "match": "contains",
          "value": "urgent"
        }
      }
    ]
  }
}

Register a grouped handler chain with parser extraction:

{
  "name": "grouped-mail",
  "handler_chain": [
    {
      "handler": "handlers.python:eval",
      "handler_args": ["title = '{{ match.title }}'"]
    },
    {
      "handler": "handlers.python:eval",
      "handler_args": ["log.info('full=' + '{{ message.full }}')"]
    }
  ],
  "execution_mode": "sequential",
  "stop_on_error": true,
  "parse": {
    "regex": {
      "title": "^(?P<title>[^\\n]+)"
    },
    "parser_ref": null,
    "allow_partial": true
  },
  "parse_mode": "warn",
  "when": {
    "op": "leaf",
    "leaf": {
      "field": "chat.type",
      "match": "eq",
      "value": "group"
    }
  }
}

Execute matching attachments for an incoming update:

{
  "update": {
    "update_id": 10001,
    "message": {
      "message_id": 33,
      "date": 1700000000,
      "chat": {
        "id": 444,
        "type": "group",
        "title": "Ops"
      },
      "text": "Status report\nEverything looks green."
    }
  }
}

Built-in handlers

  • handlers.shell:ls
    • Args: path strings
    • Result: map of path to directory entries (or error)
  • handlers.shell:sh
    • Args: shell command fragments, joined with &&
    • Result: returncode, stdout, stderr, command
  • handlers.python:eval
    • Args: Python snippets executed in order
    • Available variables: message, chat, update, log
    • Result: serializable locals snapshot

For the complete user guide to matcher expressions and handler execution, see:

  • docs/webhook-attachments.md

Template fields for handler_args

{{ ... }} placeholders are supported:

  • {{ message.title }} first line of text/caption
  • {{ message.full }} full text/caption
  • {{ message.text }} full text/caption
  • {{ message.has_media }} boolean
  • {{ message.media_type }} detected media kind
  • {{ chat.id }} chat id
  • {{ chat.type }} chat type
  • {{ chat.title }} chat title
  • {{ update.update_id }} Telegram update id
  • {{ update.kind }} detected update kind
  • {{ match.<key> }} parser output values

Telegram API extraction tooling

Extraction and generation scripts that parse Telegram HTML API docs were moved to:

  • docs/telegram_api_extraction/

Purpose and script-level documentation:

  • docs/telegram_api_extraction/README.md

Backward-compatible wrappers remain in docs/*.py.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

telegras-0.3.2.tar.gz (625.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

telegras-0.3.2-py3-none-any.whl (126.5 kB view details)

Uploaded Python 3

File details

Details for the file telegras-0.3.2.tar.gz.

File metadata

  • Download URL: telegras-0.3.2.tar.gz
  • Upload date:
  • Size: 625.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for telegras-0.3.2.tar.gz
Algorithm Hash digest
SHA256 d68112493537556ea2c4367d896f1d8305ecc8e9a56322634c658d5195feda76
MD5 067d61dea7bafbf47921adad7d0a08dd
BLAKE2b-256 84a7cf1655a1d6161ad12f98198f42d437368c43d19f4bbe231b6b11662d2a42

See more details on using hashes here.

Provenance

The following attestation bundles were made for telegras-0.3.2.tar.gz:

Publisher: publish.yml on fkr-0/telegras

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file telegras-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: telegras-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 126.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for telegras-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d2b8dedfe7eb71c4163d645246c8dd11d3757ef61fde34b1b45ebb1022216d38
MD5 07a246b63a9ef889c9dd32db7416c209
BLAKE2b-256 c90fcdc1389b0089803de2d7efb16eba633f793a0684a71ae9e732e9a2e11f01

See more details on using hashes here.

Provenance

The following attestation bundles were made for telegras-0.3.2-py3-none-any.whl:

Publisher: publish.yml on fkr-0/telegras

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page