Download ASP/db.py from mahendra0120/Agentic_Serial-killer_Profiler: direct link, hf CLI and curl.
- Browser
- Download file 6.56 kB
-
https://huggingface.co/mahendra0120/Agentic_Serial-killer_Profiler/resolve/main/ASP/db.py
- Command line
-
hf download hf://mahendra0120/Agentic_Serial-killer_Profiler/ASP/db.py
-
curl -L -o db.py https://huggingface.co/mahendra0120/Agentic_Serial-killer_Profiler/resolve/main/ASP/db.py
6.56 kB
| import asyncio | |
| import os | |
| from typing import Any, Optional | |
| import asyncpg | |
| DATABASE_URL = os.getenv( | |
| "DATABASE_URL", | |
| "postgresql://asp_user:asp_password@localhost:5432/asp", | |
| ) | |
| PIPE_SCHEMA = """ | |
| CREATE TABLE IF NOT EXISTS pipeline_steps ( | |
| case_id TEXT NOT NULL, | |
| step TEXT NOT NULL, | |
| status TEXT NOT NULL CHECK (status IN ('partial', 'complete')), | |
| content TEXT NOT NULL, | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), | |
| PRIMARY KEY (case_id, step) | |
| ); | |
| """ | |
| class CheckpointDB: | |
| def __init__( | |
| self, | |
| url: str = DATABASE_URL, | |
| min_size: int = 1, | |
| max_size: int = 10, | |
| timeout: float = 5, | |
| command_timeout: float = 30, | |
| ): | |
| self.url = url | |
| self.min_size = min_size | |
| self.max_size = max_size | |
| self.timeout = timeout | |
| self.command_timeout = command_timeout | |
| self._pool: Optional[asyncpg.Pool] = None | |
| self._loop: Optional[asyncio.AbstractEventLoop] = None | |
| self._lock: Optional[asyncio.Lock] = None | |
| self._lock_loop: Optional[asyncio.AbstractEventLoop] = None | |
| def lock_for(self, loop: asyncio.AbstractEventLoop) -> asyncio.Lock: | |
| if self._lock is None or self._lock_loop is not loop: | |
| self._lock, self._lock_loop = asyncio.Lock(), loop | |
| return self._lock | |
| async def pool(self) -> asyncpg.Pool: | |
| loop = asyncio.get_running_loop() | |
| if self._pool is not None and self._loop is loop: | |
| return self._pool | |
| async with self.lock_for(loop): | |
| if self._pool is None or self._loop is not loop: | |
| self.discard_pool() | |
| pool = await asyncpg.create_pool( | |
| self.url, | |
| min_size=self.min_size, | |
| max_size=self.max_size, | |
| timeout=self.timeout, | |
| command_timeout=self.command_timeout, | |
| ) | |
| async with pool.acquire() as conn: | |
| await conn.execute(PIPE_SCHEMA) | |
| self._pool, self._loop = pool, loop | |
| return self._pool | |
| def discard_pool(self) -> None: | |
| stale, self._pool, self._loop = self._pool, None, None | |
| if stale is not None: | |
| try: | |
| stale.terminate() | |
| except Exception: | |
| pass | |
| async def close(self) -> None: | |
| pool, self._pool, self._loop = self._pool, None, None | |
| if pool is not None: | |
| await pool.close() | |
| async def save_step(self, case_id: str, step: str, content: str, status: str) -> bool: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| row = await conn.fetchval( | |
| """ | |
| INSERT INTO pipeline_steps (case_id, step, status, content, updated_at) | |
| VALUES ($1, $2, $3, $4, now()) | |
| ON CONFLICT (case_id, step) DO UPDATE | |
| SET status = EXCLUDED.status, | |
| content = EXCLUDED.content, | |
| updated_at = now() | |
| WHERE NOT (pipeline_steps.status = 'complete' AND EXCLUDED.status = 'partial') | |
| RETURNING 1 | |
| """, | |
| case_id, step, status, content | |
| ) | |
| return row is not None | |
| async def load_steps(self, case_id: str) -> dict[str, dict[str, Any]]: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| rows = await conn.fetch( | |
| "SELECT step, status, content, updated_at FROM pipeline_steps WHERE case_id = $1", | |
| case_id | |
| ) | |
| return { | |
| r["step"]: { | |
| "status": r["status"], | |
| "content": r["content"], | |
| "updated_at": r["updated_at"].isoformat() | |
| } | |
| for r in rows | |
| } | |
| async def delete_steps(self, case_id: str, steps: list[str]) -> None: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| await conn.execute( | |
| "DELETE FROM pipeline_steps WHERE case_id = $1 AND step = ANY($2::text[])", | |
| case_id, steps | |
| ) | |
| async def list_cases(self, limit: int = 25) -> list[dict[str, Any]]: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| rows = await conn.fetch( | |
| """ | |
| SELECT case_id, | |
| max(updated_at) AS updated_at, | |
| string_agg(step || ':' || status, ',' ORDER BY step) AS steps, | |
| max(content) FILTER (WHERE step = 'meta') AS meta | |
| FROM pipeline_steps | |
| GROUP BY case_id | |
| ORDER BY max(updated_at) DESC | |
| LIMIT $1 | |
| """, | |
| limit | |
| ) | |
| return [ | |
| { | |
| "case_id": r["case_id"], | |
| "updated_at": r["updated_at"].isoformat(), | |
| "steps": r["steps"], | |
| "meta": r["meta"] | |
| } | |
| for r in rows | |
| ] | |
| async def forget_case(self, case_id: str) -> int: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| n = await conn.fetchval( | |
| "WITH d AS (DELETE FROM pipeline_steps WHERE case_id = $1 RETURNING 1) SELECT count(*) FROM d", | |
| case_id | |
| ) | |
| return int(n or 0) | |
| async def delete_cases_older_than(self, days: int) -> int: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| ids = [ | |
| r["case_id"] | |
| for r in await conn.fetch( | |
| """ | |
| DELETE FROM pipeline_steps WHERE case_id IN ( | |
| SELECT case_id FROM pipeline_steps | |
| GROUP BY case_id | |
| HAVING max(updated_at) < now() - make_interval(days => $1) | |
| ) RETURNING case_id | |
| """, | |
| int(days) | |
| ) | |
| ] | |
| return len(set(ids)) | |
| async def delete_all_cases(self) -> int: | |
| pool = await self.pool() | |
| async with pool.acquire() as conn: | |
| rows = await conn.fetch("DELETE FROM pipeline_steps RETURNING case_id") | |
| return len({r["case_id"] for r in rows}) | |
| checkpoint_db = CheckpointDB() | |