feat: scheduler /watch — watched_topics + scheduler loop + /watch /unwatch /watches
Build & Deploy ResearchOwl / build-and-push (push) Successful in 5s
Build & Deploy ResearchOwl / build-and-push (push) Successful in 5s
This commit is contained in:
@@ -99,6 +99,18 @@ CREATE TABLE IF NOT EXISTS api_usage (
|
||||
cost_usd REAL NOT NULL,
|
||||
created_at REAL NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS watched_topics (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
topic TEXT NOT NULL,
|
||||
chat_id INTEGER NOT NULL,
|
||||
interval_hours INTEGER NOT NULL DEFAULT 24,
|
||||
next_run_at REAL NOT NULL,
|
||||
last_run_at REAL,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at REAL NOT NULL,
|
||||
UNIQUE(topic, chat_id)
|
||||
);
|
||||
"""
|
||||
|
||||
|
||||
@@ -319,6 +331,57 @@ class ResearchDB:
|
||||
row = await cursor.fetchone()
|
||||
return dict(row) if row else {"sessions": 0, "total_cost": 0}
|
||||
|
||||
# --- Watched Topics ---
|
||||
|
||||
async def add_watch(self, topic: str, chat_id: int, interval_hours: int) -> int:
|
||||
now = time.time()
|
||||
cursor = await self.db.execute(
|
||||
"""INSERT OR REPLACE INTO watched_topics
|
||||
(topic, chat_id, interval_hours, next_run_at, created_at)
|
||||
VALUES (?, ?, ?, ?, ?)""",
|
||||
(topic, chat_id, interval_hours, now + interval_hours * 3600, now)
|
||||
)
|
||||
await self.db.commit()
|
||||
return cursor.lastrowid
|
||||
|
||||
async def remove_watch(self, topic: str, chat_id: int) -> bool:
|
||||
cursor = await self.db.execute(
|
||||
"DELETE FROM watched_topics WHERE topic = ? AND chat_id = ?",
|
||||
(topic, chat_id)
|
||||
)
|
||||
await self.db.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
async def list_watches(self, chat_id: int) -> list[dict]:
|
||||
cursor = await self.db.execute(
|
||||
"SELECT * FROM watched_topics WHERE chat_id = ? ORDER BY created_at ASC",
|
||||
(chat_id,)
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
async def get_due_watches(self) -> list[dict]:
|
||||
cursor = await self.db.execute(
|
||||
"SELECT * FROM watched_topics WHERE enabled = 1 AND next_run_at <= ?",
|
||||
(time.time(),)
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
async def update_watch_run(self, watch_id: int):
|
||||
cursor = await self.db.execute(
|
||||
"SELECT interval_hours FROM watched_topics WHERE id = ?", (watch_id,)
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if not row:
|
||||
return
|
||||
now = time.time()
|
||||
await self.db.execute(
|
||||
"UPDATE watched_topics SET last_run_at = ?, next_run_at = ? WHERE id = ?",
|
||||
(now, now + row[0] * 3600, watch_id)
|
||||
)
|
||||
await self.db.commit()
|
||||
|
||||
# --- Maintenance ---
|
||||
|
||||
async def purge_old_sessions(self, max_age_days: int = 30) -> dict:
|
||||
|
||||
Reference in New Issue
Block a user