image input pipeline: content-hash cache, data-url vision, picture_edit real
This commit is contained in:
@@ -13,7 +13,7 @@ from contextlib import closing
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
SCHEMA_VERSION = 3
|
||||
SCHEMA_VERSION = 4
|
||||
|
||||
|
||||
class PersistentStore:
|
||||
@@ -60,6 +60,12 @@ class PersistentStore:
|
||||
)
|
||||
# Legacy single-string memories carry over as one episode each (MEM-08)
|
||||
conn.execute("INSERT INTO episodes (channel, summary) SELECT channel, content FROM memory")
|
||||
if version < 4:
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS images (id INTEGER PRIMARY KEY, sha256 TEXT UNIQUE NOT NULL, channel TEXT NOT NULL,"
|
||||
" user TEXT NOT NULL, message_id TEXT, ext TEXT NOT NULL, bytes INTEGER NOT NULL,"
|
||||
" created_at TEXT NOT NULL DEFAULT (datetime('now')))"
|
||||
)
|
||||
if version < SCHEMA_VERSION:
|
||||
conn.execute(f"PRAGMA user_version = {SCHEMA_VERSION}")
|
||||
os.chmod(self.db_path, 0o600) # conversation data (PER-04)
|
||||
@@ -189,6 +195,53 @@ class PersistentStore:
|
||||
)
|
||||
return cursor.rowcount
|
||||
|
||||
# --- image cache index (SPEC-004, FDB-010) ---
|
||||
|
||||
def image_add(self, sha256: str, channel: str, user: str, message_id: Optional[str], ext: str, nbytes: int) -> None:
|
||||
with closing(self._connect()) as conn, conn:
|
||||
conn.execute(
|
||||
"INSERT OR IGNORE INTO images (sha256, channel, user, message_id, ext, bytes) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
(sha256, channel, user, message_id, ext, nbytes),
|
||||
)
|
||||
|
||||
def images_recent(self, channel: str, count: int) -> List[Dict[str, Any]]:
|
||||
with closing(self._connect()) as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT sha256, user, ext FROM images WHERE channel = ? ORDER BY id DESC LIMIT ?", (channel, count)
|
||||
).fetchall()
|
||||
return [{"sha256": row[0], "user": row[1], "ext": row[2]} for row in rows]
|
||||
|
||||
def images_total_bytes(self) -> int:
|
||||
with closing(self._connect()) as conn:
|
||||
row = conn.execute("SELECT COALESCE(SUM(bytes), 0) FROM images").fetchone()
|
||||
return int(row[0])
|
||||
|
||||
def images_oldest(self, count: int) -> List[Dict[str, Any]]:
|
||||
with closing(self._connect()) as conn:
|
||||
rows = conn.execute("SELECT sha256, ext, bytes FROM images ORDER BY id LIMIT ?", (count,)).fetchall()
|
||||
return [{"sha256": row[0], "ext": row[1], "bytes": row[2]} for row in rows]
|
||||
|
||||
def images_expired(self, ttl_days: int) -> List[Dict[str, Any]]:
|
||||
with closing(self._connect()) as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT sha256, ext FROM images WHERE created_at < datetime('now', ?)", (f"-{int(ttl_days)} days",)
|
||||
).fetchall()
|
||||
return [{"sha256": row[0], "ext": row[1]} for row in rows]
|
||||
|
||||
def images_delete(self, sha256: str) -> None:
|
||||
with closing(self._connect()) as conn, conn:
|
||||
conn.execute("DELETE FROM images WHERE sha256 = ?", (sha256,))
|
||||
|
||||
def images_for_user(self, user: str) -> List[Dict[str, Any]]:
|
||||
with closing(self._connect()) as conn:
|
||||
rows = conn.execute("SELECT sha256, ext FROM images WHERE user = ?", (user,)).fetchall()
|
||||
return [{"sha256": row[0], "ext": row[1]} for row in rows]
|
||||
|
||||
def images_for_message(self, message_id: str) -> List[Dict[str, Any]]:
|
||||
with closing(self._connect()) as conn:
|
||||
rows = conn.execute("SELECT sha256, ext FROM images WHERE message_id = ?", (message_id,)).fetchall()
|
||||
return [{"sha256": row[0], "ext": row[1]} for row in rows]
|
||||
|
||||
def purge_user_memory(self, user: str) -> int:
|
||||
"""Facts, observations and episode traces of one user (MEM-09)."""
|
||||
removed = 0
|
||||
|
||||
Reference in New Issue
Block a user