{"id":35270271,"url":"https://github.com/igoropaniuk/teledigest","last_synced_at":"2026-07-07T10:03:30.127Z","repository":{"id":328019161,"uuid":"1112227753","full_name":"igoropaniuk/teledigest","owner":"igoropaniuk","description":"LLM-driven framework for building Telegram digest and channel-analysis bots","archived":false,"fork":false,"pushed_at":"2026-03-07T15:36:40.000Z","size":184,"stargazers_count":16,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-30T15:28:13.879Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/igoropaniuk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-08T10:30:39.000Z","updated_at":"2026-03-24T21:41:00.000Z","dependencies_parsed_at":"2026-03-07T14:02:54.084Z","dependency_job_id":null,"html_url":"https://github.com/igoropaniuk/teledigest","commit_stats":null,"previous_names":["igoropaniuk/teledigest"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/igoropaniuk/teledigest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igoropaniuk%2Fteledigest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igoropaniuk%2Fteledigest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igoropaniuk%2Fteledigest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igoropaniuk%2Fteledigest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igoropaniuk","download_url":"https://codeload.github.com/igoropaniuk/teledigest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igoropaniuk%2Fteledigest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35223385,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-30T12:00:29.170Z","updated_at":"2026-07-07T10:03:30.117Z","avatar_url":"https://github.com/igoropaniuk.png","language":"Python","funding_links":[],"categories":["Bots"],"sub_categories":["Bot Libs"],"readme":"# Teledigest\n\n[![License](https://img.shields.io/badge/licence-MIT-green)](https://opensource.org/license/mit)\n[![Build on push](https://github.com/igoropaniuk/teledigest/actions/workflows/ci.yml/badge.svg)](https://github.com/igoropaniuk/teledigest/actions/workflows/ci.yml/badge.svg)\n\nTeledigest is a framework for building Telegram bots that collect messages from channels,\nanalyze them, and generate readable digests using large language models.\n\n- **Channel ingestion**\n  Scrapes messages from one or more Telegram channels using a dedicated user session.\n\n- **Message storage \u0026 indexing**\n  Stores messages in SQLite with FTS5 full-text search, enabling fast filtering\n  (with configurable keywords for filtering) and relevance selection.\n\n- **LLM-powered analysis \u0026 summarization**\n  Uses configurable prompts for Large Language Models to analyze recent messages\n  and produce structured summaries or digests.\n\n- **Scheduled and on-demand digests**\n  - Automatic daily digests at a configured time\n  - Manual `/digest` command to generate a digest on demand\n\n- **Bot publishing**\n  Publishes generated digests to a configured target channel.\n\n\u003e **Using Teledigest only?**\n\u003e Install the latest release from PyPI \u003chttps://pypi.org/project/teledigest\u003e\n\u003e (see [Installing from PyPI](#installing-from-pypi-recommended))\n\n## Table of Contents\n\n- [Prerequisites](#prerequisites)\n- [Fetching the project](#fetching-the-project)\n- [Obtaining a Telegram Bot Token](#obtaining-a-telegram-bot-token)\n- [Obtaining Telegram Application Credentials](#obtaining-telegram-application-credentials)\n- [Obtaining an OpenAI API Key](#obtaining-an-openai-api-key)\n- [Using Local Ollama / LM Studio Models](#using-local-ollama--lm-studio-models)\n- [Preparing the configuration file](#preparing-the-configuration-file)\n- [Bot Architecture](#bot-architecture)\n- [Installing from PyPI (recommended)](#installing-from-pypi-recommended)\n- [Installing and running the project with Poetry](#installing-and-running-the-project-with-poetry)\n- [Running with Docker](#running-with-docker)\n- [Running as a systemd service](#running-as-a-systemd-service)\n- [First run \u0026 authentication](#first-run--authentication)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Prerequisites\n\nBefore installing and running Teledigest, ensure the following tools are\ninstalled on your system:\n\n### Python\n\nThe bot requires at least **3.12** version of **Python**.\nCheck your Python version:\n\n``` bash\npython3 --version\n```\n\nInstall examples:\n\n- **macOS (Homebrew)**\n\n  ``` bash\n  brew install python@3.12\n  ```\n\n- **Ubuntu/Debian**\n\n  ``` bash\n  sudo add-apt-repository ppa:deadsnakes/ppa\n  sudo apt-get update\n  sudo apt-get install python3.12 python3.12-venv python3.12-dev\n  ```\n\n### Poetry (needed for development)\n\nThe bot uses **Poetry** for dependency management and packaging. It requires at\nleast version **2.0** of Poetry.\n\nInstall Poetry:\n\n``` bash\ncurl -sSL https://install.python-poetry.org | python3 -\n```\n\nor:\n\n``` bash\npip install poetry\n```\n\nVerify installation:\n\n``` bash\npoetry --version\n```\n\n## Fetching the project\n\n``` bash\ngit clone https://github.com/igoropaniuk/teledigest.git\ncd teledigest\n```\n\n## Obtaining a Telegram Bot Token\n\n1. Open Telegram and start a chat with `@BotFather`\n2. Run `/newbot` and follow the instructions\n3. Copy the generated **bot token** - you will need it for the\n   configuration file\n\n## Obtaining Telegram Application Credentials\n\n1. Go to \u003chttps://my.telegram.org\u003e\n2. Log in with your phone number\n3. Open **API Development Tools**\n4. Create an application\n5. Save **api_id** and **api_hash**\n\nThese are required for the Telegram client that fetches channel\nmessages.\n\n## Obtaining an OpenAI API Key\n\n1. Visit \u003chttps://platform.openai.com/api-keys\u003e\n2. Create a new API key\n3. Copy the api key - you will need it for the\n   configuration file\n\n## Using Local Ollama / LM Studio Models\n\n1. Make sure Ollama or LM Studio is running locally and the model is loaded.\n2. Set the following fields in the `[llm]` section of your config file:\n   - `model` — local model name, e.g. `\"gemma3:1b\"`\n   - `api_key` — set to `\"ollama\"` or `\"lm-studio\"` respectively\n   - `base_url` — the local API endpoint:\n     - Ollama: `\"http://localhost:11434/v1\"`\n     - LM Studio: `\"http://localhost:1234/v1\"`\n\n\u003e **Note:** The port number may differ if you changed the default settings.\n\u003e Omit `base_url` entirely when using the standard OpenAI API.\n\n## Preparing the configuration file\n\nBefore running the bot, create a configuration file,\ne.g. `teledigest.conf`:\n\n``` toml\n[telegram]\napi_id = 123456\napi_hash = \"your_api_hash\"\nbot_token = \"123456:ABCDEF\"\n\n[bot]\nchannels = [\"@news\", \"@events\"]\nsummary_target = \"@digest_channel\" # your channel for the\n                                   # bot to post summary digest\nsummary_hour = 21\nsummary_minute = 0\ntime_zone = \"America/New_York\" # optional to configure for your timezone;\n                               # default is \"Europe/Warsaw\" if this flag\n                               # is empty or missing\nallowed_users = \"@admin,123456789\" # usernames for people\n                                   # allowed to communicate with the bot.\n\n[llm]\nmodel = \"gpt-5.1-mini\"\napi_key = \"YOUR_OPENAI_API_KEY\"\nbase_url = \"url_for_llm_api\" # Not needed when using OpenAI API.\n                             # Set only when using local models\ntemperature = 0.4            # optional; controls LLM output randomness (0.0-2.0)\n\n[storage.rag]\nkeywords = [\n    \"sanctions\", \"economy\", \"energy\",\n    \"market\", \"budget\",\n]\n\n[llm.prompts]\nsystem = \"\"\"\nYou are a Telegram digest bot. Produce concise, well-structured daily summaries.\n\"\"\"\n\nuser = \"\"\"\nSummarize the following messages for {DAY}:\n\n{MESSAGES}\n\"\"\"\n```\n\n`DAY` and `MESSAGES` will be automatically replaced by the bot while building\nthe final prompt.\n\n### Important\n\n**The bot must be added as an administrator to the target channel** so\nit can publish digests.\n\nTelegram Bot API doesn't permit joining channels automatically, so Teledigest\nstarts a regular user session requiring two-factor authentication specifically for\nscraping channels.\n**This will require inputting the phone number and 2FA dynamic password**\nduring the first run of the Teledigest.\n\nPlease check [First run \u0026 authentication](#first-run--authentication) section for\nmore details\n\n## Bot Architecture\n\nTeledigest uses **two separate Telegram clients**:\n\n1. **Bot client** - handles incoming bot commands and posts digests\n   to the target channel. Requires a correct `bot_token` to be provided.\n   Always starts automatically\n1. **User client** - authenticated with `api_id` and `api_hash`, used\n   to fetch posts from Telegram channels. An additional Telegram client\n   instance was introduced to overcome the limitations of the Telegram\n   Bot API, which doesn't allow bots to join channels.\n\nThis separation ensures correct access to the Telegram channels.\n\n## Installing from PyPI (recommended)\n\nTeledigest is available on PyPI and can be installed directly without cloning\nthe repository.\n\n### Using pipx (recommended)\n\n```bash\npipx install teledigest\n```\n\nVerify installation:\n\n```bash\nteledigest --help\n```\n\n### Using pip (virtual environment)\n\n```bash\npython3.12 -m venv venv\nsource venv/bin/activate\npip install teledigest\n```\n\n### Running after PyPI installation\n\n```bash\nteledigest --config teledigest.conf\n```\n\n\u003e **Note**\n\u003e Installing from PyPI is recommended for users who only want to run the bot.\n\u003e Cloning the repository and using Poetry is mainly intended for development.\n\n## Installing and running the project with Poetry\n\n### Install dependencies using Poetry\n\n``` bash\npoetry install\n```\n\n### Run the bot\n\n``` bash\npoetry run teledigest --config teledigest.conf\n```\n\n### Bot Commands\n\n| Command   | Description |\n|-----------|-----------------------------------------------------------------|\n| `/auth`   | Authorize the user client so it canto access and scrape channels|\n| `/start`  | Alias for `/help`                                               |\n| `/help`   | Lists all supported bot commands                                |\n| `/status` | Shows parsed/relevant counts (last 24h), schedule, model, ...   |\n| `/today`  | Immediately triggers digest generation for last 24 hours        |\n| `/digest` | Alias for `/today`                                              |\n\n## Running with Docker\n\nThe bot can be run fully containerized using Docker.\nConfiguration and persistent data (Telegram sessions + SQLite database) are mounted\nfrom the host.\n\nDocker is recommended for long-running or production deployments.\n\n### Requirements\n\n- Docker 20+\n- Docker Compose v2 (`docker compose`)\n\n### Configuration\n\nCreate a config file on the host, for example `teledigest.conf`:\n\n```toml\n[telegram]\napi_id = 123456\napi_hash = \"YOUR_API_HASH\"\nbot_token = \"YOUR_BOT_TOKEN\"\nsessions_dir = \"/data\"\n\n[storage]\ndb_path = \"/data/messages_fts.db\"\n\n[logging]\nlevel = \"INFO\"\n```\n\nAlways use absolute paths (`/data`) inside the container for persistent files.\n\nCreate a directory for persistent data:\n\n```bash\nmkdir -p data\n```\n\nThis directory stores:\n\n- Telegram `.session` files\n- SQLite database for scraped messages\n\n### Option A: Docker Compose (recommended)\n\n#### docker-compose.yml\n\n```yaml\nservices:\n  teledigest:\n    build: .\n    image: teledigest:latest\n    command: [\"--config\", \"/config/teledigest.conf\"]\n    volumes:\n      - ./teledigest.conf:/config/teledigest.conf:ro\n      - ./data:/data\n    user: \"${GID:-1000}:${UID:-1000}\"\n    restart: unless-stopped\n    environment:\n      TZ: ${TZ}\n```\n\n#### Start the bot\n\n```bash\ndocker compose up --build\n```\n\nYou can also provide timezone configuration before running docker compose:\n\n```bash\nexport TZ=$(cat /etc/timezone)\ndocker compose up --build\n```\n\nRun in background:\n\n```bash\ndocker compose up -d\n```\n\nView logs:\n\n```bash\ndocker compose logs -f\n```\n\nStop:\n\n```bash\ndocker compose down\n```\n\n### Option B: Plain Docker (no Compose)\n\nBuild the image:\n\n```bash\ndocker build -t teledigest .\n```\n\nRun the container:\n\n```bash\nexport TZ=$(cat /etc/timezone)\ndocker run -e TZ=$TZ --rm \\\n   --user \"$(id -u):$(id -g)\" \\\n   -v \"$(pwd)/teledigest.conf:/config/teledigest.conf:ro\" \\\n   -v \"$(pwd)/data:/data\" teledigest:latest\n```\n\n### Permissions model\n\nThe container runs using the same UID/GID as the host user.\nThis avoids permission issues with bind-mounted volumes and prevents errors\nsuch as:\n\n- Permission denied\n- SQLite readonly database errors\nFirst run \u0026 authentication\nIf needed, ensure the data directory is writable:\n\n```bash\nchmod -R a+rwX data\n```\n\n## Running as a systemd service\n\nFor production deployments on Linux, you can manage the Teledigest Docker\nCompose stack with a systemd service. This ensures the bot starts automatically\non boot and is restarted by the init system if the host reboots.\n\n### Creating the service file\n\nCreate `/etc/systemd/system/teledigest.service` with the following content,\nreplacing `youruser` and `/path/to/your/teledigest/repository` with the actual\nvalues for your system:\n\n```ini\n[Unit]\nDescription=Teledigest service\nRequires=docker.service\nAfter=docker.service\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nUser=youruser\nWorkingDirectory=/path/to/your/teledigest/repository\nExecStart=/usr/bin/docker compose up -d\nExecStop=/usr/bin/docker compose down\nTimeoutStartSec=0\n\n[Install]\nWantedBy=multi-user.target\n```\n\n\u003e **Note:** The user specified in `User=` must have permission to manage\nDocker containers. This typically means adding the user to the `docker`\ngroup: `sudo usermod -aG docker youruser`.\n\n### Enabling and starting the service\n\nReload systemd to pick up the new unit file, then enable and start the service:\n\n```bash\nsudo systemctl daemon-reload\nsudo systemctl enable teledigest.service\nsudo systemctl start teledigest.service\n```\n\n### Managing the service\n\nCheck the current status:\n\n```bash\nsudo systemctl status teledigest.service\n```\n\nView logs (forwarded from Docker via journald):\n\n```bash\nsudo journalctl -u teledigest.service -f\n```\n\nStop the bot:\n\n```bash\nsudo systemctl stop teledigest.service\n```\n\nRestart the bot (e.g. after a config change):\n\n```bash\nsudo systemctl restart teledigest.service\n```\n\nUpdate the bot after a code change (rebuilds image):\n\n```bash\nsudo systemctl reload teledigest.service\n```\n\nDisable autostart on boot:\n\n```bash\nsudo systemctl disable teledigest.service\n```\n\n\u003e **Note:** `Type=oneshot` with `RemainAfterExit=yes` is intentional — the\n\u003e `ExecStart` command returns immediately after Docker Compose launches the\n\u003e containers in detached mode (`-d`). systemd then treats the service as\n\u003e *active* for as long as the containers are running, and correctly invokes\n\u003e `ExecStop` on shutdown or `systemctl stop`.\n\n## First run \u0026 authentication\n\nOn first run, if the user session is missing:\n\n- The bot starts normally\n- Scraping is disabled\n- `/status` explicitly shows that authorization is required\n\n### Authorizing via Telegram bot (recommended)\n\nAuthorization can be performed interactively via bot chat dialog:\n\n1. `/auth`\n2. Send your phone number (`+123456789`)\n3. Send the 2FA code you receive.\n\nWhen you authorize the user client via the `/auth` command, the bot asks you to\ntype the Telegram login code with spaces between each digit, for example:\n\n`1 2 3 4 5`\n\nThis is **not** a protocol requirement, but a practical workaround for Telegram's\nsecurity system.\n\nTelegram tries to detect situations where a login code might have been leaked or\nshared. If the code is **forwarded** or **shared** from your account and then used\nto log in from another client, Telegram may treat that as suspicious and block\nthe login, even though the code itself is correct. In that case you may see a\nmessage similar to:\n\n\u003e the code was entered correctly, but the login was not allowed because the code\n\u003e was previously shared from your account.\n\nBy asking you to **type the code manually with spaces**, the bot encourages a\npattern that is clearly different from simply forwarding or copy-pasting the\noriginal message with the code. On the bot side, those spaces are removed\nbefore the code is sent to Telegram, so Telegram still receives the exact code\nit issued.\n\nIn short:\n\n- You type: `1 2 3 4 5`\n- The bot converts it to: `12345`\n- This reduces the chance of Telegram treating the login as a suspicious\n  \"shared code\" login and blocking it.\n\nIf authorization fails, repeat `/auth`.\n\n### CLI authorization (`--auth`)\n\nIt's possible to perform authentication via CLI and then exit:\n\n```bash\npoetry run teledigest --config teledigest.conf --auth\n```\n\nOr do this inside docker container:\n\n```bash\ndocker run -it --rm --user \"$(id -u):$(id -g)\" \\\n   -v \"$(pwd)/teledigest.conf:/config/teledigest.conf:ro\" \\\n   -v \"$(pwd)/data:/data\" teledigest:latest \\\n   --config /config/teledigest.conf --auth\n```\n\nExpect this output during initial session registration:\n\n```bash\n$ poetry run teledigest --config teledigest.conf --auth\n[INFO] teledigest - Logging configured at INFO level\n[INFO] teledigest - Using session paths: user=data/user.session, bot=data/bot.session\n[INFO] teledigest - Starting user \u0026 bot clients...\n[INFO] teledigest - Channels to scrape (user account): @channel1, @channel2\n[INFO] telethon.network.mtprotosender - Connecting to 0.0.0.0/TcpFull...\n[INFO] telethon.network.mtprotosender - Connection to 0.0.0.0/TcpFull complete!\nPlease enter your phone (or bot token): +48888888888\nPlease enter the code you received: 12345\nSigned in successfully as User; remember to not break the ToS!\n[INFO] teledigest - Auth-only mode: skipping channel joins and handler registration.\n[INFO] telethon.network.mtprotosender - Disconnecting from 0.0.0.0/TcpFull...\n[INFO] telethon.network.mtprotosender - Not disconnecting (already have no connection)\n[INFO] telethon.network.mtprotosender - Disconnection from 0.0.0.0/TcpFull complete!\n[INFO] teledigest - Authentication completed\n```\n\nThen you can restart the bot without `--auth` param and it will use existing\nsessions files.\n\nDo not delete the `data/` directory unless you want to re-authenticate.\n\n### Why bot-based authorization is preferred over CLI auth (especially in Docker)\n\nEven CLI auth mode (`teledigest --auth`) still exists and works fine for local\ndevelopment on your machine, it is **not recommended** as the primary method\nin Docker / containerized environments.\n\nThere are a few reasons for that:\n\n1. **Docker often has no usable stdin**\n\n   The boot CLI-style `--auth` expects to read the phone number,\n   login code and (optional) 2FA password from `stdin` (your terminal). In a\n   typical Docker setup you will run the container in detached mode, or under\n   an orchestrator (Kubernetes, docker-compose, etc.) with **no interactive\n   TTY attached**.\n\n   In that situation there is nowhere for Telethon to read from, so the process\n   either blocks waiting on stdin or fails with an error. Attaching manually to\n   container stdin just to type a one-time code is awkward and fragile.\n\n2. **Non-interactive / automated deployments**\n\n   Containers are usually started by scripts or orchestration tools, not by a\n   human at a terminal. An interactive login step in the startup path breaks\n   this model and makes fully automated deployments impossible. The bot-based\n   `/auth` flow lets you keep the container fully non-interactive: you authorize\n   once via Telegram, and the session file is reused next time the container\n   starts.\n\n3. **Clear separation of concerns**\n\n   With bot-based auth, the container just runs the bot and user clients using\n   existing session files. All interactive steps (phone, code, password) happen\n   in Telegram itself, where you already expect to handle sensitive login\n   information. The container only sees the resulting session, not the raw\n   codes.\n\nBecause of these constraints, the recommended approach is:\n\n- use `teledigest --auth` only for **local, manual** login when you are\n  actually sitting at a terminal; or when you are deliberately managing\n  sessions outside Docker, and\n- use the `/auth` bot command for **normal Docker / production** deployments,\n  where stdin is not reliably available and the process must remain\n  non-interactive.\n\n## Contributing\n\nDevelopment setup, coding standards, testing, and pull request workflow live in\n[`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## License\n\nThis project is licensed under the **MIT License**.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figoropaniuk%2Fteledigest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figoropaniuk%2Fteledigest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figoropaniuk%2Fteledigest/lists"}