Files
Gan, Jimmy c676c84bc1
Deploy Dashboard / deploy (push) Failing after 38s
feat: add chat group daily summarizer
- Telegram collector (Telethon MTProto) with checkpoint-based message fetching
- Claude API summarization via proxy (haiku model)
- Dashboard page with date picker, markdown summary, raw message drill-down
- Separate container lifecycle from dashboard for stable Telethon sessions
- Shared SQLite DB mounted read-only into dashboard
2026-02-27 02:51:52 +08:00

78 lines
2.5 KiB
Python

import os
import logging
from datetime import datetime, timedelta, timezone
import aiosqlite
import httpx
from db import DB_PATH
log = logging.getLogger(__name__)
API_KEY = os.environ.get("ANTHROPIC_API_KEY", "")
BASE_URL = os.environ.get("ANTHROPIC_BASE_URL", "https://www.bytecatcode.org")
MODEL = "claude-haiku-4-5-20251001"
CST = timezone(timedelta(hours=8))
PROMPT = """You are a chat group digest assistant. Summarize the following chat messages into a concise daily digest.
Rules:
- Group by topic/theme, not by chat group
- Highlight key decisions, shared links, and action items
- Skip greetings, small talk, and low-value chatter
- Use markdown formatting
- Write in the same language as the messages (likely Chinese)
- Be concise
Messages:
{messages}"""
async def summarize(date_str: str = None):
now = datetime.now(CST)
if not date_str:
date_str = now.strftime("%Y-%m-%d")
start = datetime.strptime(date_str, "%Y-%m-%d").replace(tzinfo=CST)
end = start + timedelta(days=1)
async with aiosqlite.connect(DB_PATH) as db:
cursor = await db.execute(
"SELECT group_name, sender_name, text, timestamp FROM messages WHERE timestamp >= ? AND timestamp < ? ORDER BY timestamp",
(start.isoformat(), end.isoformat())
)
rows = await cursor.fetchall()
if not rows:
log.info("No messages for %s, skipping summary", date_str)
return None
# Format messages for the prompt
formatted = []
for group_name, sender, text, ts in rows:
formatted.append(f"[{group_name}] {sender}: {text}")
messages_text = "\n".join(formatted)
# Call Claude API
async with httpx.AsyncClient(timeout=120) as client:
resp = await client.post(
f"{BASE_URL}/v1/messages",
headers={"x-api-key": API_KEY, "anthropic-version": "2023-06-01", "content-type": "application/json"},
json={
"model": MODEL,
"max_tokens": 4096,
"messages": [{"role": "user", "content": PROMPT.format(messages=messages_text)}]
}
)
resp.raise_for_status()
data = resp.json()
summary = data["content"][0]["text"]
# Store summary
async with aiosqlite.connect(DB_PATH) as db:
await db.execute(
"INSERT OR REPLACE INTO summaries (date, content, created_at) VALUES (?,?,?)",
(date_str, summary, now.isoformat())
)
await db.commit()
log.info("Generated summary for %s (%d messages)", date_str, len(rows))
return summary