Spaces:
Sleeping
Sleeping
| # File: persistence_manager.py | |
| # Location: /persistence_manager.py | |
| # Description: Manages persistent storage for book writing projects | |
| import os | |
| import json | |
| import streamlit as st | |
| import sqlite3 | |
| from typing import Dict, Any, List | |
| import uuid | |
| from datetime import datetime | |
| class ProjectPersistenceManager: | |
| """ | |
| Manages project persistence using filesystem and SQLite | |
| """ | |
| def __init__(self, base_path: str = '/data'): | |
| """ | |
| Initialize persistence manager | |
| Args: | |
| base_path (str): Base directory for storing project data | |
| """ | |
| # Ensure base path exists | |
| self.base_path = base_path | |
| self._ensure_directories() | |
| # Setup database path | |
| self.db_path = os.path.join(self.base_path, 'book_projects.db') | |
| # Initialize database connection | |
| self.conn = self._initialize_database() | |
| def _ensure_directories(self): | |
| """ | |
| Create necessary directories for project storage | |
| """ | |
| directories = [ | |
| self.base_path, | |
| os.path.join(self.base_path, 'projects'), | |
| os.path.join(self.base_path, 'chapters') | |
| ] | |
| for dir_path in directories: | |
| os.makedirs(dir_path, exist_ok=True) | |
| def _initialize_database(self): | |
| """ | |
| Initialize SQLite database for project tracking | |
| Returns: | |
| sqlite3.Connection: Database connection | |
| """ | |
| try: | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| # Create projects table | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS projects ( | |
| project_id TEXT PRIMARY KEY, | |
| title TEXT, | |
| genre TEXT, | |
| total_chapters INTEGER, | |
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP, | |
| last_modified DATETIME DEFAULT CURRENT_TIMESTAMP | |
| ) | |
| ''') | |
| # Create chapters table | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS chapters ( | |
| project_id TEXT, | |
| chapter_number INTEGER, | |
| content TEXT, | |
| status TEXT DEFAULT 'DRAFT', | |
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY(project_id) REFERENCES projects(project_id), | |
| PRIMARY KEY(project_id, chapter_number) | |
| ) | |
| ''') | |
| conn.commit() | |
| return conn | |
| except Exception as e: | |
| st.error(f"Database initialization error: {e}") | |
| return None | |
| def save_project(self, project_data: Dict[str, Any]) -> str: | |
| """ | |
| Save project data to both filesystem and database | |
| Args: | |
| project_data (Dict): Project information to save | |
| Returns: | |
| str: Project ID | |
| """ | |
| # Generate project ID if not provided | |
| project_id = project_data.get('project_id') or str(uuid.uuid4()) | |
| try: | |
| # Save to JSON file | |
| project_file = os.path.join( | |
| self.base_path, | |
| 'projects', | |
| f'{project_id}.json' | |
| ) | |
| # Prepare save data | |
| save_data = { | |
| **project_data, | |
| 'project_id': project_id, | |
| 'last_modified': datetime.now().isoformat() | |
| } | |
| # Write JSON file | |
| with open(project_file, 'w') as f: | |
| json.dump(save_data, f, indent=4) | |
| # Save to database | |
| if self.conn: | |
| cursor = self.conn.cursor() | |
| # Insert/update project metadata | |
| cursor.execute(''' | |
| INSERT OR REPLACE INTO projects | |
| (project_id, title, genre, total_chapters) | |
| VALUES (?, ?, ?, ?) | |
| ''', ( | |
| project_id, | |
| save_data.get('title', 'Untitled'), | |
| save_data.get('genre', 'Unspecified'), | |
| save_data.get('total_chapters', 0) | |
| )) | |
| # Save chapters | |
| if 'chapters' in save_data: | |
| for chapter_num, chapter_content in save_data['chapters'].items(): | |
| cursor.execute(''' | |
| INSERT OR REPLACE INTO chapters | |
| (project_id, chapter_number, content) | |
| VALUES (?, ?, ?) | |
| ''', (project_id, chapter_num, chapter_content)) | |
| self.conn.commit() | |
| return project_id | |
| except Exception as e: | |
| st.error(f"Error saving project: {e}") | |
| return None | |
| def load_project(self, project_id: str) -> Dict[str, Any]: | |
| """ | |
| Load project data from filesystem or database | |
| Args: | |
| project_id (str): Project identifier | |
| Returns: | |
| Dict: Project data or None | |
| """ | |
| try: | |
| # Try loading from JSON file first | |
| project_file = os.path.join( | |
| self.base_path, | |
| 'projects', | |
| f'{project_id}.json' | |
| ) | |
| if os.path.exists(project_file): | |
| with open(project_file, 'r') as f: | |
| return json.load(f) | |
| # Fallback to database | |
| if self.conn: | |
| cursor = self.conn.cursor() | |
| # Fetch project details | |
| cursor.execute('SELECT * FROM projects WHERE project_id = ?', (project_id,)) | |
| project = cursor.fetchone() | |
| if project: | |
| # Fetch chapters | |
| cursor.execute('SELECT * FROM chapters WHERE project_id = ?', (project_id,)) | |
| chapters = cursor.fetchall() | |
| return { | |
| 'project_id': project[0], | |
| 'title': project[1], | |
| 'genre': project[2], | |
| 'total_chapters': project[3], | |
| 'chapters': { | |
| chapter[1]: chapter[2] for chapter in chapters | |
| } | |
| } | |
| return None | |
| except Exception as e: | |
| st.error(f"Error loading project: {e}") | |
| return None | |
| def list_projects(self) -> List[Dict[str, Any]]: | |
| """ | |
| List all saved projects | |
| Returns: | |
| List of project metadata | |
| """ | |
| projects = [] | |
| try: | |
| # Check JSON files | |
| projects_dir = os.path.join(self.base_path, 'projects') | |
| # Scan JSON files | |
| for filename in os.listdir(projects_dir): | |
| if filename.endswith('.json'): | |
| try: | |
| with open(os.path.join(projects_dir, filename), 'r') as f: | |
| project = json.load(f) | |
| projects.append({ | |
| 'project_id': project.get('project_id'), | |
| 'title': project.get('title', 'Untitled'), | |
| 'last_modified': project.get('last_modified') | |
| }) | |
| except Exception as e: | |
| st.warning(f"Could not load project {filename}: {e}") | |
| except Exception as e: | |
| st.error(f"Error listing projects: {e}") | |
| return projects | |
| def main(): | |
| """ | |
| Demonstration of persistence manager | |
| """ | |
| # Initialize persistence manager | |
| pm = ProjectPersistenceManager() | |
| # Example: Save a project | |
| project_data = { | |
| 'title': 'My First Book', | |
| 'genre': 'Science Fiction', | |
| 'total_chapters': 5, | |
| 'chapters': { | |
| 1: 'First chapter content', | |
| 2: 'Second chapter content' | |
| } | |
| } | |
| # Save project | |
| project_id = pm.save_project(project_data) | |
| print(f"Saved project with ID: {project_id}") | |
| # Load project | |
| loaded_project = pm.load_project(project_id) | |
| print("Loaded Project:", loaded_project) | |
| if __name__ == "__main__": | |
| main() |