Spaces:
Sleeping
Sleeping
| # File: data_persistence.py | |
| # Location: /data_persistence.py | |
| # Description: Robust data persistence and serialization for book writing project | |
| import os | |
| import json | |
| import sqlite3 | |
| from typing import Dict, Any | |
| import streamlit as st | |
| class ProjectPersistenceManager: | |
| def __init__(self, project_id: str = None): | |
| """ | |
| Initialize persistent storage for book writing projects | |
| Args: | |
| project_id (str, optional): Unique identifier for the project | |
| """ | |
| # Ensure data directory exists | |
| os.makedirs('project_data', exist_ok=True) | |
| # SQLite Database Setup | |
| self.db_path = 'project_data/book_projects.db' | |
| self.conn = sqlite3.connect(self.db_path) | |
| self._create_tables() | |
| def _create_tables(self): | |
| """ | |
| Create necessary tables for project persistence | |
| """ | |
| cursor = self.conn.cursor() | |
| # Project Metadata 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 | |
| ) | |
| ''') | |
| # Chapters Table | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS chapters ( | |
| project_id TEXT, | |
| chapter_number INTEGER, | |
| content TEXT, | |
| status TEXT, | |
| generated_at DATETIME DEFAULT CURRENT_TIMESTAMP, | |
| PRIMARY KEY (project_id, chapter_number), | |
| FOREIGN KEY (project_id) REFERENCES projects (project_id) | |
| ) | |
| ''') | |
| # Book Concept Table | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS book_concepts ( | |
| project_id TEXT PRIMARY KEY, | |
| concept_data TEXT, | |
| FOREIGN KEY (project_id) REFERENCES projects (project_id) | |
| ) | |
| ''') | |
| self.conn.commit() | |
| def save_project_metadata(self, project_data: Dict[str, Any]): | |
| """ | |
| Save project metadata to persistent storage | |
| Args: | |
| project_data (Dict): Project metadata dictionary | |
| """ | |
| cursor = self.conn.cursor() | |
| # Upsert project metadata | |
| cursor.execute(''' | |
| INSERT OR REPLACE INTO projects | |
| (project_id, title, genre, total_chapters) | |
| VALUES (?, ?, ?, ?) | |
| ''', ( | |
| project_data.get('project_id', 'unknown'), | |
| project_data.get('title', 'Untitled'), | |
| project_data.get('genre', 'Unspecified'), | |
| project_data.get('total_chapters', 0) | |
| )) | |
| self.conn.commit() | |
| def save_book_concept(self, project_id: str, concept_data: Dict[str, Any]): | |
| """ | |
| Save book concept to persistent storage | |
| Args: | |
| project_id (str): Unique project identifier | |
| concept_data (Dict): Book concept details | |
| """ | |
| cursor = self.conn.cursor() | |
| # Upsert book concept | |
| cursor.execute(''' | |
| INSERT OR REPLACE INTO book_concepts | |
| (project_id, concept_data) | |
| VALUES (?, ?) | |
| ''', ( | |
| project_id, | |
| json.dumps(concept_data) | |
| )) | |
| self.conn.commit() | |
| def save_chapter( | |
| self, | |
| project_id: str, | |
| chapter_number: int, | |
| content: str, | |
| status: str = 'Generated' | |
| ): | |
| """ | |
| Save chapter content to persistent storage | |
| Args: | |
| project_id (str): Unique project identifier | |
| chapter_number (int): Chapter number | |
| content (str): Chapter content | |
| status (str): Chapter status | |
| """ | |
| cursor = self.conn.cursor() | |
| # Upsert chapter | |
| cursor.execute(''' | |
| INSERT OR REPLACE INTO chapters | |
| (project_id, chapter_number, content, status) | |
| VALUES (?, ?, ?, ?) | |
| ''', ( | |
| project_id, | |
| chapter_number, | |
| content, | |
| status | |
| )) | |
| self.conn.commit() | |
| def load_project_metadata(self, project_id: str) -> Dict[str, Any]: | |
| """ | |
| Load project metadata from persistent storage | |
| Args: | |
| project_id (str): Unique project identifier | |
| Returns: | |
| Dict containing project metadata | |
| """ | |
| cursor = self.conn.cursor() | |
| cursor.execute('SELECT * FROM projects WHERE project_id = ?', (project_id,)) | |
| project = cursor.fetchone() | |
| if project: | |
| return { | |
| 'project_id': project[0], | |
| 'title': project[1], | |
| 'genre': project[2], | |
| 'total_chapters': project[3] | |
| } | |
| return {} | |
| def load_book_concept(self, project_id: str) -> Dict[str, Any]: | |
| """ | |
| Load book concept from persistent storage | |
| Args: | |
| project_id (str): Unique project identifier | |
| Returns: | |
| Dict containing book concept | |
| """ | |
| cursor = self.conn.cursor() | |
| cursor.execute('SELECT concept_data FROM book_concepts WHERE project_id = ?', (project_id,)) | |
| concept = cursor.fetchone() | |
| return json.loads(concept[0]) if concept else {} | |
| def load_chapters(self, project_id: str) -> Dict[int, Dict]: | |
| """ | |
| Load all chapters for a project | |
| Args: | |
| project_id (str): Unique project identifier | |
| Returns: | |
| Dict of chapters with chapter number as key | |
| """ | |
| cursor = self.conn.cursor() | |
| cursor.execute('SELECT chapter_number, content, status FROM chapters WHERE project_id = ?', (project_id,)) | |
| chapters = {} | |
| for chapter_num, content, status in cursor.fetchall(): | |
| chapters[chapter_num] = { | |
| 'content': content, | |
| 'status': status | |
| } | |
| return chapters | |
| def close(self): | |
| """ | |
| Close database connection | |
| """ | |
| self.conn.close() | |
| # Test functionality | |
| def test_persistence(): | |
| """ | |
| Run comprehensive tests for data persistence | |
| """ | |
| # Initialize persistence manager | |
| pm = ProjectPersistenceManager() | |
| # Test project metadata | |
| test_project = { | |
| 'project_id': 'test_project_1', | |
| 'title': 'Test Book', | |
| 'genre': 'Science Fiction', | |
| 'total_chapters': 10 | |
| } | |
| # Save project metadata | |
| pm.save_project_metadata(test_project) | |
| # Load and verify project metadata | |
| loaded_project = pm.load_project_metadata('test_project_1') | |
| assert loaded_project == test_project, "Project metadata not saved/loaded correctly" | |
| # Test book concept | |
| test_concept = { | |
| 'narrative_premise': 'A story about AI and humanity', | |
| 'core_themes': ['Technology', 'Ethics'] | |
| } | |
| pm.save_book_concept('test_project_1', test_concept) | |
| # Load and verify book concept | |
| loaded_concept = pm.load_book_concept('test_project_1') | |
| assert loaded_concept == test_concept, "Book concept not saved/loaded correctly" | |
| # Test chapter saving and loading | |
| pm.save_chapter('test_project_1', 1, "Chapter 1 content", "Generated") | |
| pm.save_chapter('test_project_1', 2, "Chapter 2 content", "In Review") | |
| # Load chapters | |
| loaded_chapters = pm.load_chapters('test_project_1') | |
| assert len(loaded_chapters) == 2, "Chapters not saved/loaded correctly" | |
| assert loaded_chapters[1]['content'] == "Chapter 1 content", "Chapter 1 content mismatch" | |
| print("All persistence tests passed successfully!") | |
| # Run tests if script is executed directly | |
| if __name__ == "__main__": | |
| test_persistence() |