# db.py - Database Configuration and Operations import sqlite3 from flask import g from contextlib import contextmanager from config import DATABASE def get_db(): """Get database connection for current request.""" if 'db' not in g: g.db = sqlite3.connect(DATABASE) g.db.row_factory = sqlite3.Row return g.db def close_db(error=None): """Close database connection at end of request.""" db = g.pop('db', None) if db is not None: db.close() @contextmanager def get_db_connection(): """Context manager for database connections outside request context.""" conn = sqlite3.connect(DATABASE) conn.row_factory = sqlite3.Row try: yield conn finally: conn.close() def init_db(): """Initialize database tables.""" with get_db_connection() as conn: cursor = conn.cursor() # Projects table cursor.execute(''' CREATE TABLE IF NOT EXISTS projects ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') # Chapters table cursor.execute(''' CREATE TABLE IF NOT EXISTS chapters ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, chapter_number INTEGER NOT NULL, voice TEXT DEFAULT 'af_heart', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE, UNIQUE(project_id, chapter_number) ) ''') # Markdown blocks table cursor.execute(''' CREATE TABLE IF NOT EXISTS markdown_blocks ( id INTEGER PRIMARY KEY AUTOINCREMENT, chapter_id INTEGER NOT NULL, block_order INTEGER NOT NULL, block_type TEXT NOT NULL DEFAULT 'paragraph', content TEXT NOT NULL, tts_text TEXT, audio_data TEXT, audio_format TEXT DEFAULT 'mp3', transcription TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE CASCADE ) ''') # Images table cursor.execute(''' CREATE TABLE IF NOT EXISTS block_images ( id INTEGER PRIMARY KEY AUTOINCREMENT, block_id INTEGER NOT NULL, image_data TEXT NOT NULL, image_format TEXT DEFAULT 'png', alt_text TEXT, position TEXT DEFAULT 'before', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (block_id) REFERENCES markdown_blocks(id) ON DELETE CASCADE ) ''') # PDF Documents table cursor.execute(''' CREATE TABLE IF NOT EXISTS pdf_documents ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER, filename TEXT NOT NULL, page_count INTEGER DEFAULT 0, metadata TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL ) ''') conn.commit() print("✅ Database initialized") def vacuum_db(): """Run VACUUM to reclaim space after deletions.""" with get_db_connection() as conn: conn.execute('VACUUM') def init_app(app): """Initialize database with Flask app.""" app.teardown_appcontext(close_db) init_db() # Initialize users table from auth import init_users_table init_users_table()