File size: 8,622 Bytes
3adc6ba
 
aee040f
3adc6ba
 
 
 
 
 
 
 
 
aee040f
b2d56e8
aee040f
b2d56e8
aee040f
b2d56e8
aee040f
3adc6ba
 
aee040f
aa9fdd5
aee040f
 
 
aa9fdd5
aee040f
 
aa9fdd5
aee040f
 
aa9fdd5
aee040f
3adc6ba
aee040f
3adc6ba
 
aee040f
 
 
3adc6ba
aee040f
3adc6ba
aee040f
3adc6ba
 
 
 
 
 
 
 
 
 
 
aee040f
 
3adc6ba
 
 
 
 
 
 
 
 
 
aee040f
 
3adc6ba
 
 
 
 
 
 
 
 
 
 
aee040f
3adc6ba
 
 
 
 
 
 
 
aee040f
3adc6ba
 
aee040f
3adc6ba
 
aee040f
3adc6ba
aee040f
3adc6ba
 
 
 
 
aee040f
3adc6ba
 
 
 
 
 
 
 
 
 
 
aee040f
 
 
3adc6ba
aee040f
3adc6ba
aee040f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3adc6ba
 
 
 
 
 
 
 
 
aee040f
3adc6ba
 
aee040f
3adc6ba
 
aee040f
3adc6ba
 
aee040f
3adc6ba
aee040f
3adc6ba
 
 
 
 
aee040f
 
3adc6ba
 
 
aee040f
 
 
 
 
 
 
 
 
 
aa9fdd5
aee040f
 
 
 
 
 
 
3adc6ba
aee040f
3adc6ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aee040f
3adc6ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa9fdd5
aee040f
aa9fdd5
0121a70
aee040f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa9fdd5
aee040f
 
 
3adc6ba
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# 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()