cryogenic22 commited on
Commit
88e4af9
·
verified ·
1 Parent(s): 33b731b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +299 -362
app.py CHANGED
@@ -1,414 +1,351 @@
1
  # File: app.py
2
- # Location: /app.py (root directory for Hugging Face Spaces)
3
- # Description: Main Streamlit application for AI Book Writing Assistant
4
 
5
  import streamlit as st
6
- import os
7
  import json
8
- import uuid
9
-
10
- from multi_agent_book_workflow import BookWritingOrchestrator
11
- from persistence_manager import ProjectPersistenceManager
12
 
13
- class BookWritingApp:
14
  def __init__(self):
15
- """
16
- Initialize the Streamlit application for book writing
17
-
18
- Manages session state and persistence
19
- """
20
- # Set page configuration
21
  st.set_page_config(
22
- page_title="AI Book Writing Assistant",
23
- page_icon="📖",
24
  layout="wide"
25
  )
26
 
27
- # Initialize persistence manager
28
- self.persistence_manager = ProjectPersistenceManager()
29
 
30
  # Initialize session state
31
  self._initialize_session_state()
32
-
33
- # Set up project orchestrator
34
- self._setup_project_orchestrator()
35
-
36
- def _setup_project_orchestrator(self):
37
- """
38
- Initialize project orchestrator with proper error handling
39
- """
40
- try:
41
- if 'project_orchestrator' not in st.session_state or st.session_state.project_orchestrator is None:
42
- st.session_state.project_orchestrator = BookWritingOrchestrator()
43
- except ValueError as ve:
44
- st.error(f"API Key Error: {str(ve)}")
45
- st.info("Please ensure your API keys are properly set in the environment variables.")
46
- st.session_state.project_orchestrator = None
47
- except Exception as e:
48
- st.error(f"Error setting up project orchestrator: {e}")
49
- st.session_state.project_orchestrator = None
50
-
51
  def _initialize_session_state(self):
52
- """
53
- Initialize and manage Streamlit session state
54
- """
55
- # Project tracking
56
- if 'active_project_id' not in st.session_state:
57
- st.session_state.active_project_id = None
58
-
59
- # Restore last active project if exists
60
- if st.session_state.active_project_id:
61
- self._load_project(st.session_state.active_project_id)
62
-
63
- # Ensure core session state variables exist
64
- session_defaults = {
65
- 'project_orchestrator': None,
66
- 'book_concept': None,
67
- 'generated_chapters': {},
68
- 'total_chapters': 10, # Default value
69
- 'project_metadata': {
70
- 'title': 'Untitled Project',
71
- 'genre': 'Unspecified',
72
- 'total_chapters': 10
73
  }
74
- }
75
-
76
- for key, default in session_defaults.items():
77
- if key not in st.session_state:
78
- st.session_state[key] = default
79
-
80
- def _load_project(self, project_id):
81
- """
82
- Load a project from persistent storage
83
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  try:
85
- loaded_project = self.persistence_manager.load_project(project_id)
 
 
 
86
 
87
- if loaded_project:
88
- # Update session state with loaded project
89
- st.session_state.active_project_id = project_id
90
- st.session_state.book_concept = loaded_project.get('book_concept')
91
- st.session_state.generated_chapters = loaded_project.get('chapters', {})
92
- st.session_state.total_chapters = loaded_project.get('total_chapters', 10)
93
- st.session_state.project_metadata = {
94
- 'title': loaded_project.get('title', 'Untitled Project'),
95
- 'genre': loaded_project.get('genre', 'Unspecified'),
96
- 'total_chapters': loaded_project.get('total_chapters', 10)
97
- }
98
-
99
- st.success(f"Loaded project: {loaded_project.get('title', 'Untitled')}")
100
- else:
101
- st.warning("Could not load project.")
102
-
103
- except Exception as e:
104
- st.error(f"Error loading project: {e}")
105
-
106
- def _save_current_project(self):
107
- """
108
- Save the current project to persistent storage
109
- """
110
- try:
111
- # Prepare project data for saving
112
- project_data = {
113
- 'project_id': st.session_state.active_project_id or str(uuid.uuid4()),
114
- 'title': st.session_state.project_metadata.get('title', 'Untitled Project'),
115
- 'genre': st.session_state.project_metadata.get('genre', 'Unspecified'),
116
- 'book_concept': st.session_state.book_concept,
117
- 'chapters': st.session_state.generated_chapters,
118
- 'total_chapters': st.session_state.total_chapters
119
- }
120
 
121
- # Save project
122
- project_id = self.persistence_manager.save_project(project_data)
 
 
 
123
 
124
- if project_id:
125
- # Update active project ID
126
- st.session_state.active_project_id = project_id
127
- st.success(f"Project saved successfully!")
128
- else:
129
- st.error("Failed to save project.")
130
-
131
  except Exception as e:
132
- st.error(f"Error saving project: {e}")
133
-
134
- def render_project_management(self):
135
- """
136
- Render project management interface
137
- """
138
- st.sidebar.header("Project Management")
139
-
140
- # New Project Button
141
- if st.sidebar.button("Start New Project"):
142
- # Reset session state
143
- st.session_state.active_project_id = None
144
- st.session_state.book_concept = None
145
- st.session_state.generated_chapters = {}
146
- st.session_state.total_chapters = 10
147
- st.session_state.project_metadata = {
148
- 'title': 'Untitled Project',
149
- 'genre': 'Unspecified',
150
- 'total_chapters': 10
151
- }
152
- st.experimental_rerun()
153
-
154
- # Load Project
155
- project_list = self.persistence_manager.list_projects()
156
- if project_list:
157
- selected_project = st.sidebar.selectbox(
158
- "Load Existing Project",
159
- options=[p['title'] for p in project_list],
160
- index=None,
161
- placeholder="Select a project..."
162
- )
163
 
164
- if selected_project:
165
- # Find project ID
166
- project_id = next(
167
- (p['project_id'] for p in project_list if p['title'] == selected_project),
168
- None
169
- )
170
 
171
- if project_id and st.sidebar.button("Load Selected Project"):
172
- self._load_project(project_id)
173
-
174
- # Save Current Project
175
- if st.sidebar.button("Save Current Project"):
176
- self._save_current_project()
177
-
178
- def render_book_generation_interface(self):
179
- """
180
- Render the main book generation interface
181
- """
182
- # Tabs for different stages of book writing
183
- tab1, tab2, tab3 = st.tabs([
184
- "Book Concept",
185
- "Chapter Generation",
186
- "Project Progress"
187
- ])
188
-
189
- with tab1:
190
- self._render_concept_development()
191
-
192
- with tab2:
193
- self._render_chapter_generation()
194
-
195
- with tab3:
196
- self._render_project_progress()
197
-
198
- def _render_concept_development(self):
199
- """
200
- Render the book concept development interface
201
- """
202
- st.header("📘 Book Concept Development")
203
-
204
- # Initial concept input
205
- initial_concept = st.text_area(
206
- "Describe Your Book Idea",
207
- height=200,
208
- placeholder="Enter a comprehensive description of your book concept..."
209
- )
210
-
211
- if st.button("Generate Book Concept"):
212
- if st.session_state.project_orchestrator is None:
213
- st.error("Project orchestrator is not properly initialized. Please check your API keys.")
214
- return
215
 
216
- with st.spinner("Developing Book Concept..."):
217
- try:
218
- # Generate book concept using multi-agent approach
219
- book_concept = st.session_state.project_orchestrator.generate_book_concept(
220
- initial_concept
221
- )
222
-
223
- if book_concept:
224
- # Update session state
225
- st.session_state.book_concept = book_concept
226
- st.session_state.project_metadata.update({
227
- 'title': book_concept.get('title', 'Untitled Project'),
228
- 'genre': book_concept.get('genre', 'Unspecified')
229
- })
230
-
231
- # Display generated concept
232
- st.subheader("Generated Book Concept")
233
- st.json(book_concept)
234
- else:
235
- st.error("Failed to generate book concept.")
236
 
237
- except Exception as e:
238
- st.error(f"Error generating book concept: {e}")
239
-
240
- def _render_chapter_generation(self):
241
- """
242
- Render the chapter generation interface
243
- """
244
- st.header("✍️ Chapter Generation")
245
-
246
- # Check if book concept exists
247
- if not st.session_state.book_concept:
248
- st.warning("Please generate a book concept first.")
249
- return
250
 
251
- # Chapter generation controls
252
- col1, col2 = st.columns(2)
253
 
254
  with col1:
255
- # Chapter number selection
256
- max_chapters = 20 # Can be adjusted
257
- current_chapter = len(st.session_state.generated_chapters) + 1
258
- chapter_number = st.number_input(
259
- "Select Chapter to Generate",
260
- min_value=1,
261
- max_value=max_chapters,
262
- value=min(current_chapter, max_chapters)
263
  )
 
 
 
264
 
265
  with col2:
266
- # Total chapters planning
267
- total_chapters = st.number_input(
268
- "Total Planned Chapters",
269
- min_value=1,
270
- max_value=max_chapters,
271
- value=st.session_state.total_chapters
272
- )
273
 
274
- # Update session state
275
- if total_chapters != st.session_state.total_chapters:
276
- st.session_state.total_chapters = total_chapters
277
- st.session_state.project_metadata['total_chapters'] = total_chapters
278
-
279
- # Generate Chapter Button
280
- if st.button("Generate Chapter"):
281
- if st.session_state.project_orchestrator is None:
282
- st.error("Project orchestrator is not properly initialized. Please check your API keys.")
283
- return
284
-
285
- with st.spinner(f"Generating Chapter {chapter_number}..."):
286
  try:
287
- # Generate chapter content
288
- chapter_content = st.session_state.project_orchestrator.generate_chapter_content(
289
- st.session_state.book_concept,
290
- chapter_number
291
- )
292
-
293
- if chapter_content:
294
- # Store generated chapter
295
- st.session_state.generated_chapters[chapter_number] = {
296
- 'content': chapter_content,
297
- 'status': 'Generated'
298
- }
299
-
300
- # Display Chapter Content
301
- st.subheader(f"Chapter {chapter_number}")
302
- st.write(chapter_content)
303
-
304
- # Create a unique key for the text area
305
- edit_key = f"edit_chapter_{chapter_number}"
306
-
307
- # Optional: Edit Chapter
308
- edited_content = st.text_area(
309
- "Edit Chapter Content",
310
- value=chapter_content,
311
- height=400,
312
- key=edit_key
313
- )
314
-
315
- # Save button with unique key
316
- save_key = f"save_chapter_{chapter_number}"
317
- if st.button(f"Save Chapter {chapter_number}", key=save_key):
318
- st.session_state.generated_chapters[chapter_number]['content'] = edited_content
319
- st.success(f"Chapter {chapter_number} saved!")
320
- else:
321
- st.error("Failed to generate chapter content.")
322
-
323
  except Exception as e:
324
- st.error(f"Error generating chapter: {e}")
325
-
326
- def _render_project_progress(self):
327
- """
328
- Render project progress and tracking interface
329
- """
330
- st.header("📊 Project Progress")
 
 
 
 
 
 
 
 
 
331
 
332
- # Project Metadata Overview
333
- st.subheader("Project Overview")
334
- col1, col2 = st.columns(2)
335
 
336
- with col1:
337
- st.metric("Book Title", st.session_state.project_metadata.get('title', 'Untitled'))
338
- st.metric("Genre", st.session_state.project_metadata.get('genre', 'Unspecified'))
339
 
340
- with col2:
341
- total_chapters = st.session_state.total_chapters
342
- generated_chapters = len(st.session_state.generated_chapters)
343
 
344
- st.metric("Total Planned Chapters", total_chapters)
345
- st.metric("Chapters Generated", generated_chapters)
 
 
 
 
 
 
 
 
 
346
 
347
- # Progress Bar
348
- progress = generated_chapters / total_chapters if total_chapters > 0 else 0
349
- st.progress(progress)
350
-
351
- # Chapter Navigation and Details
352
- st.subheader("Generated Chapters")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
- # Create tabs for each generated chapter
355
- if st.session_state.generated_chapters:
356
- chapter_tabs = st.tabs([
357
- f"Chapter {ch_num}" for ch_num in sorted(st.session_state.generated_chapters.keys())
358
- ])
359
 
360
- for i, ch_num in enumerate(sorted(st.session_state.generated_chapters.keys())):
361
- with chapter_tabs[i]:
362
- chapter_data = st.session_state.generated_chapters[ch_num]
363
- st.write(chapter_data['content'])
 
364
 
365
- # Chapter status and actions
366
- col1, col2 = st.columns(2)
367
- with col1:
368
- status = st.selectbox(
369
- "Chapter Status",
370
- ["Generated", "In Review", "Completed"],
371
- key=f"status_{ch_num}"
372
- )
373
- if status != chapter_data['status']:
374
- chapter_data['status'] = status
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
 
376
- with col2:
377
- if st.button(f"Export Chapter {ch_num}", key=f"export_{ch_num}"):
378
- try:
379
- # Export chapter functionality
380
- export_path = os.path.join('data', f"chapter_{ch_num}.txt")
381
- os.makedirs('data', exist_ok=True)
382
- with open(export_path, "w") as f:
383
- f.write(chapter_data['content'])
384
- st.success(f"Chapter {ch_num} exported to {export_path}")
385
- except Exception as e:
386
- st.error(f"Error exporting chapter: {e}")
387
  else:
388
- st.info("No chapters generated yet. Start writing your book!")
389
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  def run(self):
391
- """
392
- Run the main Streamlit application
393
- """
394
- # Render project management sidebar
395
- self.render_project_management()
396
 
397
- # Main title
398
- st.title("🚀 AI-Powered Book Writing Assistant")
 
 
399
 
400
- # Check if project orchestrator is initialized
401
- if st.session_state.project_orchestrator is None:
402
- st.warning("Please ensure your API keys are properly set in the environment variables.")
403
 
404
- # Render the main interface
405
- self.render_book_generation_interface()
 
 
 
 
 
406
 
407
  def main():
408
- """
409
- Initialize and run the application
410
- """
411
- app = BookWritingApp()
412
  app.run()
413
 
414
  if __name__ == "__main__":
 
1
  # File: app.py
 
 
2
 
3
  import streamlit as st
 
4
  import json
5
+ import os
6
+ from selfapi_writer import SelfApiWriter
7
+ from data_manager import DataManager
 
8
 
9
+ class SelfApiApp:
10
  def __init__(self):
11
+ """Initialize the Streamlit application"""
 
 
 
 
 
12
  st.set_page_config(
13
+ page_title="Self.api Book Generator",
14
+ page_icon="📚",
15
  layout="wide"
16
  )
17
 
18
+ # Initialize data manager
19
+ self.data_manager = DataManager()
20
 
21
  # Initialize session state
22
  self._initialize_session_state()
23
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  def _initialize_session_state(self):
25
+ """Initialize session state variables"""
26
+ if 'current_tab' not in st.session_state:
27
+ st.session_state.current_tab = 'Blueprint'
28
+
29
+ if 'blueprint' not in st.session_state:
30
+ st.session_state.blueprint = self.default_blueprint
31
+
32
+ if 'book_content' not in st.session_state:
33
+ st.session_state.book_content = {
34
+ "introduction": "",
35
+ "parts": []
 
 
 
 
 
 
 
 
 
 
36
  }
37
+
38
+ @property
39
+ def default_blueprint(self):
40
+ """Get default blueprint content"""
41
+ return """# Editorial Blueprint: Self.api - A Modern Spiritual Operating System
42
+
43
+ ## Core Editorial Vision
44
+ Transform "Self.api" from a conceptual framework into a revolutionary guide that speaks to the modern seeker - the stressed executive who downloads meditation apps but can't stick to them, the engineering lead who understands distributed systems better than their own emotions, and the consultant who can optimize anything except their own life satisfaction.
45
+
46
+ ### Target Reader Profile
47
+ - Primary: Tech professionals, entrepreneurs, and knowledge workers (25-45)
48
+ - Secondary: Anyone feeling disconnected in our hyper-connected world
49
+ - Psychographic: Analytical minds seeking spiritual depth without the woo-woo
50
+
51
+ ## Book Structure
52
+ ### Introduction: "System Requirements: A Human's Guide to Being Human"
53
+ - Opening hook: "In a world where we can Google anything except our own purpose..."
54
+ - Key narrative: Author's journey from debugging code to debugging consciousness
55
+
56
+ ### Part 1: The Human Input/Output System
57
+ - Rate Limiting Your Reality
58
+ - Debugging Your Attention Span
59
+ - The Mindfulness Microservice
60
+
61
+ ### Part 2: Your Internal Neural Network
62
+ - Training Your Gut Algorithm
63
+ - The Wisdom Cache
64
+ - Pattern Recognition Beyond Logic
65
+
66
+ ### Part 3: The Source Code of Being
67
+ - Quantum Mechanics of Consciousness
68
+ - The Purpose Protocol
69
+ - Refactoring Your Reality
70
+
71
+ ### Part 4: The Universal Runtime Environment
72
+ - Distributed Consciousness Systems
73
+ - The Empathy Protocol
74
+ - Scaling Your Impact
75
+
76
+ ## Style Guidelines
77
+ 1. Technical Authenticity
78
+ - Use API and tech metaphors naturally
79
+ - Example: "Think of meditation as a daily health check for your consciousness microservices"
80
+
81
+ 2. Voice & Tone
82
+ - Witty But Wise
83
+ - Blend humor with depth
84
+ - Style: Think Douglas Adams meets Deepak Chopra
85
+
86
+ 3. Chapter Structure
87
+ - System Log (personal story)
88
+ - Documentation (teaching)
89
+ - Implementation Guide (practical steps)
90
+
91
+ ## Content Requirements
92
+ 1. Each chapter should have:
93
+ - 3 "aha" moments
94
+ - 2-3 quotable passages
95
+ - Practical exercises every 5 pages
96
+ - Balance: 60% practical, 40% philosophical
97
+ - Links to both ancient wisdom and modern science"""
98
+
99
+ def save_current_state(self):
100
+ """Save current state to data directory"""
101
  try:
102
+ # Save blueprint if it exists
103
+ if st.session_state.blueprint:
104
+ blueprint_file = self.data_manager.save_blueprint(st.session_state.blueprint)
105
+ st.success(f"Blueprint saved: {blueprint_file}")
106
 
107
+ # Save book content if it exists
108
+ if st.session_state.book_content:
109
+ content_file = self.data_manager.save_book_content(st.session_state.book_content)
110
+ st.success(f"Book content saved: {content_file}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
+ # Save individual chapters
113
+ for part_idx, part in enumerate(st.session_state.book_content.get('parts', [])):
114
+ for ch_idx, chapter in enumerate(part.get('chapters', [])):
115
+ if chapter.get('content'):
116
+ self.data_manager.save_chapter(part_idx, ch_idx, chapter)
117
 
 
 
 
 
 
 
 
118
  except Exception as e:
119
+ st.error(f"Error saving state: {e}")
120
+
121
+ def load_latest_state(self):
122
+ """Load latest state from data directory"""
123
+ try:
124
+ # Load latest blueprint
125
+ blueprint = self.data_manager.load_latest_blueprint()
126
+ if blueprint:
127
+ st.session_state.blueprint = blueprint
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
+ # Load latest book content
130
+ content = self.data_manager.load_latest_book_content()
131
+ if content:
132
+ st.session_state.book_content = content
 
 
133
 
134
+ st.success("Latest state loaded successfully!")
135
+
136
+ except Exception as e:
137
+ st.error(f"Error loading state: {e}")
138
+
139
+ def export_book(self):
140
+ """Export book in markdown format"""
141
+ try:
142
+ # Export as markdown
143
+ if st.session_state.book_content:
144
+ filepath = self.data_manager.export_markdown(st.session_state.book_content)
145
+ st.success(f"Book exported to: {filepath}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
+ # Create download link
148
+ with open(filepath, 'r') as f:
149
+ markdown_content = f.read()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
+ st.download_button(
152
+ label="Download Markdown",
153
+ data=markdown_content,
154
+ file_name="self_api_book.md",
155
+ mime="text/markdown"
156
+ )
157
+ except Exception as e:
158
+ st.error(f"Error exporting book: {e}")
159
+
160
+ def render_blueprint_editor(self):
161
+ """Render the blueprint editor interface"""
162
+ st.header("�� Editorial Blueprint Editor")
 
163
 
164
+ col1, col2 = st.columns([7, 3])
 
165
 
166
  with col1:
167
+ # Blueprint Editor
168
+ edited_blueprint = st.text_area(
169
+ "Edit Blueprint",
170
+ value=st.session_state.blueprint,
171
+ height=600
 
 
 
172
  )
173
+
174
+ if edited_blueprint != st.session_state.blueprint:
175
+ st.session_state.blueprint = edited_blueprint
176
 
177
  with col2:
178
+ st.subheader("Blueprint Controls")
 
 
 
 
 
 
179
 
180
+ # Reset Blueprint
181
+ if st.button("Reset to Default"):
182
+ st.session_state.blueprint = self.default_blueprint
183
+ st.experimental_rerun()
184
+
185
+ # Save Blueprint
186
+ if st.button("Save Blueprint"):
 
 
 
 
 
187
  try:
188
+ filename = self.data_manager.save_blueprint(st.session_state.blueprint)
189
+ st.success(f"Blueprint saved as: {filename}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  except Exception as e:
191
+ st.error(f"Error saving blueprint: {e}")
192
+
193
+ # Load Blueprint
194
+ if st.button("Load Latest"):
195
+ try:
196
+ blueprint = self.data_manager.load_latest_blueprint()
197
+ if blueprint:
198
+ st.session_state.blueprint = blueprint
199
+ st.success("Latest blueprint loaded!")
200
+ st.experimental_rerun()
201
+ except Exception as e:
202
+ st.error(f"Error loading blueprint: {e}")
203
+
204
+ def render_generator_interface(self):
205
+ """Render the book generation interface"""
206
+ st.header("⚙️ Content Generator")
207
 
208
+ # Initialize writer if needed
209
+ if 'writer' not in st.session_state:
210
+ st.session_state.writer = SelfApiWriter()
211
 
212
+ # Generation controls
213
+ col1, col2 = st.columns([2, 1])
 
214
 
215
+ with col1:
216
+ st.subheader("Generation Controls")
 
217
 
218
+ # Introduction Generation
219
+ intro_col1, intro_col2 = st.columns([3, 1])
220
+ with intro_col1:
221
+ st.markdown("### Introduction")
222
+ with intro_col2:
223
+ if st.button("Generate Introduction"):
224
+ with st.spinner("Generating introduction..."):
225
+ intro_content = st.session_state.writer.write_introduction()
226
+ st.session_state.book_content["introduction"] = intro_content
227
+ self.save_current_state()
228
+ st.success("Introduction generated!")
229
 
230
+ # Parts and Chapters Generation
231
+ for part_idx, part in enumerate(st.session_state.writer.book_structure["parts"]):
232
+ st.markdown(f"### Part {part_idx + 1}: {part['title']}")
233
+
234
+ for ch_idx, ch_title in enumerate(part["chapters"]):
235
+ ch_col1, ch_col2 = st.columns([3, 1])
236
+ with ch_col1:
237
+ st.markdown(f"- {ch_title}")
238
+ with ch_col2:
239
+ if st.button(f"Generate", key=f"gen_{part_idx}_{ch_idx}"):
240
+ with st.spinner(f"Generating {ch_title}..."):
241
+ chapter_content = st.session_state.writer.write_chapter(part_idx, ch_idx)
242
+
243
+ # Ensure part exists
244
+ while len(st.session_state.book_content["parts"]) <= part_idx:
245
+ st.session_state.book_content["parts"].append({
246
+ "title": part["title"],
247
+ "chapters": []
248
+ })
249
+
250
+ # Ensure chapter exists
251
+ while len(st.session_state.book_content["parts"][part_idx]["chapters"]) <= ch_idx:
252
+ st.session_state.book_content["parts"][part_idx]["chapters"].append({
253
+ "title": "",
254
+ "content": ""
255
+ })
256
+
257
+ # Update chapter
258
+ st.session_state.book_content["parts"][part_idx]["chapters"][ch_idx] = {
259
+ "title": ch_title,
260
+ "content": chapter_content
261
+ }
262
+ self.save_current_state()
263
+ st.success(f"{ch_title} generated!")
264
 
265
+ with col2:
266
+ st.subheader("Quick Actions")
 
 
 
267
 
268
+ if st.button("Generate All"):
269
+ with st.spinner("Generating entire book..."):
270
+ # Generate introduction
271
+ intro_content = st.session_state.writer.write_introduction()
272
+ st.session_state.book_content["introduction"] = intro_content
273
 
274
+ # Generate all chapters
275
+ for part_idx, part in enumerate(st.session_state.writer.book_structure["parts"]):
276
+ # Initialize part
277
+ if len(st.session_state.book_content["parts"]) <= part_idx:
278
+ st.session_state.book_content["parts"].append({
279
+ "title": part["title"],
280
+ "chapters": []
281
+ })
282
+
283
+ for ch_idx, ch_title in enumerate(part["chapters"]):
284
+ chapter_content = st.session_state.writer.write_chapter(part_idx, ch_idx)
285
+
286
+ # Ensure chapter exists
287
+ while len(st.session_state.book_content["parts"][part_idx]["chapters"]) <= ch_idx:
288
+ st.session_state.book_content["parts"][part_idx]["chapters"].append({
289
+ "title": "",
290
+ "content": ""
291
+ })
292
+
293
+ # Update chapter
294
+ st.session_state.book_content["parts"][part_idx]["chapters"][ch_idx] = {
295
+ "title": ch_title,
296
+ "content": chapter_content
297
+ }
298
 
299
+ self.save_current_state()
300
+ st.success("Full book generated!")
301
+
302
+ def render_content_preview(self):
303
+ """Render the book content preview"""
304
+ st.header("📚 Generated Content Preview")
305
+
306
+ # Display any generated content here
307
+ if not st.session_state.book_content["introduction"] and not st.session_state.book_content["parts"]:
308
+ st.info("No content generated yet. Use the Generator tab to create content.")
 
309
  else:
310
+ # Add export button
311
+ if st.button("Export Current Content"):
312
+ self.export_book()
313
+
314
+ # Show introduction if it exists
315
+ if st.session_state.book_content["introduction"]:
316
+ st.subheader("Introduction")
317
+ with st.expander("View Introduction", expanded=True):
318
+ st.markdown(st.session_state.book_content["introduction"])
319
+
320
+ # Show generated parts and chapters
321
+ for part_idx, part in enumerate(st.session_state.book_content["parts"]):
322
+ st.subheader(f"Part {part_idx + 1}: {part['title']}")
323
+ for chapter in part["chapters"]:
324
+ if chapter["content"]:
325
+ with st.expander(f"Chapter: {chapter['title']}", expanded=False):
326
+ st.markdown(chapter["content"])
327
+
328
  def run(self):
329
+ """Run the Streamlit application"""
330
+ st.title("🚀 Self.api Book Generator")
 
 
 
331
 
332
+ # Main navigation
333
+ tabs = ["Blueprint", "Generator", "Preview"]
334
+ selected_tab = st.radio("Navigation", tabs, horizontal=True)
335
+ st.session_state.current_tab = selected_tab
336
 
337
+ st.divider()
 
 
338
 
339
+ # Render appropriate content based on selected tab
340
+ if selected_tab == "Blueprint":
341
+ self.render_blueprint_editor()
342
+ elif selected_tab == "Generator":
343
+ self.render_generator_interface()
344
+ else:
345
+ self.render_content_preview()
346
 
347
  def main():
348
+ app = SelfApiApp()
 
 
 
349
  app.run()
350
 
351
  if __name__ == "__main__":