| """SQLite persistence for saved stories (revisit; sharing is a post-MVP add-on). |
| |
| Kept tiny and dependency-free. On HF Spaces storage is ephemeral unless |
| persistent storage is enabled — saved stories survive a session regardless. |
| """ |
| from __future__ import annotations |
|
|
| import json |
| import os |
| import sqlite3 |
| import time |
|
|
| import config |
|
|
|
|
| def _conn() -> sqlite3.Connection: |
| os.makedirs(os.path.dirname(config.DB_PATH) or ".", exist_ok=True) |
| conn = sqlite3.connect(config.DB_PATH) |
| conn.row_factory = sqlite3.Row |
| return conn |
|
|
|
|
| def init_db() -> None: |
| with _conn() as c: |
| c.execute( |
| "CREATE TABLE IF NOT EXISTS stories (" |
| " id INTEGER PRIMARY KEY AUTOINCREMENT," |
| " name TEXT, style TEXT, difficulty TEXT," |
| " story_json TEXT, created REAL)") |
|
|
|
|
| def save_story(name: str, style: str, difficulty: str, story_dict: dict) -> int: |
| with _conn() as c: |
| cur = c.execute( |
| "INSERT INTO stories(name, style, difficulty, story_json, created) " |
| "VALUES(?,?,?,?,?)", |
| (name, style, difficulty, json.dumps(story_dict), time.time())) |
| return int(cur.lastrowid) |
|
|
|
|
| def list_stories(limit: int = 20) -> list[dict]: |
| with _conn() as c: |
| rows = c.execute( |
| "SELECT id, name, style, difficulty, created FROM stories " |
| "ORDER BY created DESC LIMIT ?", (limit,)).fetchall() |
| return [dict(r) for r in rows] |
|
|
|
|
| def get_story(story_id: int) -> dict | None: |
| with _conn() as c: |
| row = c.execute("SELECT * FROM stories WHERE id=?", (story_id,)).fetchone() |
| if not row: |
| return None |
| d = dict(row) |
| d["story"] = json.loads(d.pop("story_json")) |
| return d |
|
|