跳到正文
GitHub·· 5 天前AI 评分36

onhazrat/tg-workspace:面向公开 Telegram 频道的自托管 AI 工作区

onhazrat/tg-workspace

AI 导读

开发者开源了自托管工作区 tg-workspace,通过读取 Telegram 公开网页版(t.me/s/)同步频道帖子到 PostgreSQL,无需账号、API 凭证或 MTProto,可生成摘要、对话、标签和频道发现四类产物。

正文

A self-hosted workspace for public Telegram channels. It follows the channels you care about, syncs their posts into PostgreSQL, and runs AI over whatever slice of them you select: summaries, a chat you can ask questions of, automatic tagging, and discovery of channels you are not following yet.

It reads Telegram's public web view (t.me/s/<channel>). No account, no API credentials, no MTProto.

The channels view, showing followed channels with their bios, post counts and sync state

Screenshots are a local instance seeded from the committed test fixtures, which are captures of Telegram's own public channels.

Not a supported product. I built this for myself and I am not supporting deployments of it. Issues are open and I read them, but expect no SLA. It needs PostgreSQL with pgmq, and its sync tier is pinned to a single replica on purpose.

MIT licensed.

What it does

You Follow channels. A background worker walks each one's page history and stores every Post. You then pick a Scope, which is a set of channels crossed with a date range and a set of filters, and produce one of four Artifacts from it:

Artifact What it is
Summary AI prose about the posts in the scope, optionally published back to a Telegram channel
Chat A conversation about those posts, either full-scope or retrieval-backed over embeddings
Tag run AI-proposed channel tags, with execution state, because it can fail
Discovery report Channels found by scanning your posts for outward references

The posts view, filtering a corpus down to the slice an artifact will be built from

Every artifact freezes the scope it was made from, so reopening one restores that selection rather than reinterpreting it against today's data. The vocabulary above is precise and enforced; CONTEXT.md is the glossary.

Why the repo might interest you

The interesting part of this codebase is not the Telegram features. It is that roughly 182,000 lines of Python and TypeScript were built almost entirely through agent-assisted development, and that the architecture is held together by executable guards rather than by documentation nobody rereads.

There are 1,693 backend test functions across 180 files, plus 118 frontend test files. A large share of them assert architectural claims rather than behaviour: that every service module declares one of five kinds, that no route returns an untyped dict, that every mounted operation is probed for cross-account leakage or excused with a typed reason, that a fix applied to one of two twin modules also covers the twin. CLAUDE.md indexes every one of those invariants with a pointer to the test that enforces it.

The reasoning is on disk too, not just the results. .scratch/ holds the ticket-by-ticket plan for the multi-account programme. docs/ holds the architecture decision records and the performance investigations, including the one where a scheduled job was found burning 69 minutes of database time every 10 hours computing statistics it discarded.

If you want to see what building this way actually looks like, including the parts that went wrong, those directories are the reason the repo is public.

Architecture in one screen

Two processes. The API serves requests; a separate worker owns the scheduler and drains the queue. Sync work is enqueued one message per channel across six pgmq lanes, drained strictly between priority tiers and weighted 3:2:1 within one, so a trickle of interactive work never starves auto-sync. One sync per channel at a time, claimed by a row rather than by process memory, so a second request coalesces onto the first instead of duplicating it.

Every request to Telegram leaves through an acquired Lane, which is one proxy with a concurrency limit. A worker binds to its proxy for a whole channel walk and never hops, including on retry, because moving a struggling proxy's load onto healthy ones is the worst thing to do exactly when Telegram is pushing back. Rate limiting is adaptive per proxy and distinguishes seven outcomes, because a 404 is Telegram answering, not a proxy fault.

Row visibility has one seam. Every table is classified as user-owned, follow-scoped, or shared corpus, and dispatch is by model class rather than by hand-written where clauses. Over-quota degrades an account to a slower lane rather than refusing it; past a hard ceiling nothing runs.

Stack

Backend is FastAPI, SQLModel, Alembic, PostgreSQL with pgmq, and APScheduler, managed by uv. Embeddings live in an ordinary table and are searched with numpy rather than a vector extension. Frontend is React 19, Vite, TanStack Query and Router, managed by bun, with an OpenAPI-generated client. AI providers are pluggable and Gemini is the one implemented.

Running it

cp .env.example .env      # every tunable is documented in there
docker compose watch      # frontend :5173, API :8000, docs :8000/docs

Native development, tests, migrations and the Playwright suite are in development.md. Traefik, the production compose stack and the deploy workflow are in deployment.md.

Documentation

Where What
CONTEXT.md The glossary. Start here if a term looks overloaded
CLAUDE.md Every architectural invariant, with the test that enforces it
docs/migration/ Architecture decision records
docs/ Performance investigations and design plans
.scratch/ The multi-account programme, ticket by ticket
docs/pr-archive/ All 176 pull requests, one written rationale per change

The documentation still calls the product "TG Summarizer" in places. The repository was renamed because a summary is only one of the four artifacts; the docs will catch up.

Credit

Built on fastapi/full-stack-fastapi-template.

Post languages are detected with fastText's lid.176 language identification model by Facebook AI Research, installed through fast-langdetect. The model is distributed under CC BY-SA 3.0; see fastText's language identification page. It ships inside the installed package, not this repository.

来源:GitHub · github.com