Spaces:
Runtime error
Runtime error
| """ | |
| db.py — SQLite persistence for chat history | |
| Stored in /data/chat.db (persistent HF Space volume) | |
| """ | |
| import sqlite3 | |
| import json | |
| import os | |
| from datetime import datetime | |
| DB_PATH = os.environ.get("DB_PATH", "/data/chat.db") | |
| def get_conn(): | |
| os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) | |
| conn = sqlite3.connect(DB_PATH, check_same_thread=False) | |
| conn.row_factory = sqlite3.Row | |
| return conn | |
| def init_db(): | |
| with get_conn() as conn: | |
| conn.executescript(""" | |
| CREATE TABLE IF NOT EXISTS conversations ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| user_id TEXT NOT NULL, | |
| title TEXT NOT NULL DEFAULT 'Nouvelle conversation', | |
| model_id TEXT, | |
| created_at TEXT NOT NULL, | |
| updated_at TEXT NOT NULL | |
| ); | |
| CREATE TABLE IF NOT EXISTS messages ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| conversation_id INTEGER NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, | |
| role TEXT NOT NULL CHECK(role IN ('user','assistant','system')), | |
| content TEXT NOT NULL, | |
| created_at TEXT NOT NULL | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_conv_user ON conversations(user_id, updated_at DESC); | |
| CREATE INDEX IF NOT EXISTS idx_msg_conv ON messages(conversation_id, id ASC); | |
| """) | |
| # ── Conversations ────────────────────────────────────────────── | |
| def list_conversations(user_id: str) -> list[dict]: | |
| with get_conn() as conn: | |
| rows = conn.execute( | |
| """SELECT c.id, c.title, c.model_id, c.updated_at, | |
| COUNT(m.id) as msg_count | |
| FROM conversations c | |
| LEFT JOIN messages m ON m.conversation_id = c.id | |
| WHERE c.user_id = ? | |
| GROUP BY c.id | |
| ORDER BY c.updated_at DESC | |
| LIMIT 100""", | |
| (user_id,), | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def create_conversation(user_id: str, title: str = "Nouvelle conversation", model_id: str = "") -> int: | |
| now = datetime.utcnow().isoformat() | |
| with get_conn() as conn: | |
| cur = conn.execute( | |
| "INSERT INTO conversations(user_id, title, model_id, created_at, updated_at) VALUES(?,?,?,?,?)", | |
| (user_id, title, model_id, now, now), | |
| ) | |
| return cur.lastrowid | |
| def rename_conversation(conv_id: int, user_id: str, title: str): | |
| now = datetime.utcnow().isoformat() | |
| with get_conn() as conn: | |
| conn.execute( | |
| "UPDATE conversations SET title=?, updated_at=? WHERE id=? AND user_id=?", | |
| (title[:80], now, conv_id, user_id), | |
| ) | |
| def delete_conversation(conv_id: int, user_id: str): | |
| with get_conn() as conn: | |
| conn.execute( | |
| "DELETE FROM conversations WHERE id=? AND user_id=?", | |
| (conv_id, user_id), | |
| ) | |
| def update_conversation_model(conv_id: int, model_id: str): | |
| now = datetime.utcnow().isoformat() | |
| with get_conn() as conn: | |
| conn.execute( | |
| "UPDATE conversations SET model_id=?, updated_at=? WHERE id=?", | |
| (model_id, now, conv_id), | |
| ) | |
| # ── Messages ─────────────────────────────────────────────────── | |
| def get_messages(conv_id: int) -> list[dict]: | |
| with get_conn() as conn: | |
| rows = conn.execute( | |
| "SELECT role, content, created_at FROM messages WHERE conversation_id=? ORDER BY id ASC", | |
| (conv_id,), | |
| ).fetchall() | |
| return [dict(r) for r in rows] | |
| def add_message(conv_id: int, role: str, content: str): | |
| now = datetime.utcnow().isoformat() | |
| with get_conn() as conn: | |
| conn.execute( | |
| "INSERT INTO messages(conversation_id, role, content, created_at) VALUES(?,?,?,?)", | |
| (conv_id, role, content, now), | |
| ) | |
| conn.execute( | |
| "UPDATE conversations SET updated_at=? WHERE id=?", | |
| (now, conv_id), | |
| ) | |
| def auto_title_from_message(msg: str) -> str: | |
| """Generate a short title from the first user message.""" | |
| title = msg.strip().replace("\n", " ") | |
| return title[:60] + ("…" if len(title) > 60 else "") | |