cryogenic22 commited on
Commit
5feebe5
·
verified ·
1 Parent(s): af10f17

Update selfapi_writer.py

Browse files
Files changed (1) hide show
  1. selfapi_writer.py +209 -149
selfapi_writer.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  from anthropic import Anthropic
2
  import streamlit as st
3
  import json
@@ -10,7 +12,7 @@ class SelfApiWriter:
10
  def __init__(self):
11
  """Initialize the Self.api writer with enhanced content tracking"""
12
  ANTHROPIC_API_KEY = os.getenv('api_key')
13
-
14
  if not ANTHROPIC_API_KEY:
15
  raise ValueError("Anthropic API key not found. Please ensure ANTHROPIC_API_KEY is set.")
16
 
@@ -151,7 +153,7 @@ class SelfApiWriter:
151
  temperature=0,
152
  system=system_prompt,
153
  messages=[{
154
- "role": "user",
155
  "content": f"""Analyze this book blueprint and extract ALL information:
156
 
157
  {truncated_blueprint}
@@ -177,138 +179,7 @@ class SelfApiWriter:
177
  st.error(f"Error processing blueprint: {str(e)}")
178
  return None
179
 
180
- def set_manual_content(self, content_id: str, content: str) -> None:
181
- """Set pre-written content for a section"""
182
- if content_id not in self.content_states:
183
- self._initialize_content_state(content_id)
184
- self.content_states[content_id].set_manual_content(content)
185
-
186
- def _generate_transition(self, content_id: str, prev_content: str, next_content: str) -> str:
187
- """Generate smooth transition between content sections"""
188
- state = self.content_states[content_id]
189
-
190
- transition_prompt = f"""Create a smooth transition between these sections:
191
-
192
- Previous Section Summary: {self._summarize_text(prev_content)}
193
- Next Section Key Points: {self._summarize_text(next_content)}
194
-
195
- Create a natural bridge that:
196
- 1. References relevant previous points
197
- 2. Introduces upcoming concepts
198
- 3. Maintains narrative flow
199
- 4. Feels organic and not forced"""
200
-
201
- response = self.client.messages.create(
202
- model=self.model,
203
- max_tokens=300,
204
- temperature=0.7,
205
- messages=[{"role": "user", "content": transition_prompt}]
206
- )
207
-
208
- transition = response.content[0].text
209
- state.transition_points.append(transition)
210
- return transition
211
-
212
- def _generate_progressive_summary(self, content_id: str, content: str) -> str:
213
- """Generate a running summary of content progress"""
214
- summary_prompt = f"""Summarize the key points and narrative progression of:
215
-
216
- {content}
217
-
218
- Focus on:
219
- 1. Main concepts introduced
220
- 2. Key arguments developed
221
- 3. Narrative threads established
222
- 4. Important conclusions reached
223
-
224
- Keep the summary concise but comprehensive."""
225
-
226
- response = self.client.messages.create(
227
- model=self.model,
228
- max_tokens=500,
229
- temperature=0.3,
230
- messages=[{"role": "user", "content": summary_prompt}]
231
- )
232
-
233
- return response.content[0].text
234
-
235
- def _generate_with_continuity(self,
236
- generate_func: callable,
237
- content_id: str,
238
- title: str,
239
- total_steps: int = 10) -> str:
240
- """Enhanced generation with content continuity tracking"""
241
- progress_bar = st.progress(0, text=f"Generating {title}...")
242
- full_content = ""
243
- state = self.content_states[content_id]
244
-
245
- try:
246
- # If manual content exists, use it as a starting point
247
- if state.manual_content:
248
- full_content = state.manual_content + "\n\n"
249
- # Generate initial summary from manual content
250
- state.current_summary = self._generate_progressive_summary(
251
- content_id,
252
- full_content
253
- )
254
-
255
- # Generate initial outline
256
- outline = self._generate_section_outline(content_id, "section", title)
257
- points_per_iteration = max(1, len(outline) // total_steps)
258
-
259
- for iteration in range(1, total_steps + 1):
260
- progress = iteration / total_steps
261
- progress_bar.progress(
262
- min(int(progress * 100), 100),
263
- text=f"Generating {title}... (Iteration {iteration}/{total_steps})"
264
- )
265
-
266
- start_idx = (iteration - 1) * points_per_iteration
267
- end_idx = min(start_idx + points_per_iteration, len(outline))
268
- current_points = outline[start_idx:end_idx]
269
-
270
- new_content = generate_func(
271
- iteration=iteration,
272
- previous_summary=state.current_summary,
273
- points_to_cover=current_points,
274
- narrative_threads=state.narrative_threads
275
- )
276
-
277
- state.generated_sections.append(new_content)
278
-
279
- if iteration > 1:
280
- transition = self._generate_transition(
281
- content_id,
282
- state.generated_sections[-2],
283
- new_content
284
- )
285
- full_content += transition
286
-
287
- full_content += new_content
288
-
289
- state.current_summary = self._generate_progressive_summary(
290
- content_id,
291
- full_content
292
- )
293
- state.key_points_covered.update(current_points)
294
-
295
- if len(full_content.split()) > self.pages_per_chapter * self.words_per_page:
296
- break
297
-
298
- conclusion = self._generate_conclusion(content_id, full_content)
299
- full_content += conclusion
300
-
301
- progress_bar.progress(100, text=f"Finished generating {title}")
302
- return full_content
303
-
304
- except Exception as e:
305
- st.error(f"Error generating {title}: {e}")
306
- progress_bar.empty()
307
- return f"Error generating {title}: {e}"
308
- finally:
309
- progress_bar.empty()
310
-
311
- def write_introduction(self) -> str:
312
  """Generate the book's introduction with enhanced continuity"""
313
  if not self.initialized:
314
  raise ValueError("Writer not initialized. Process blueprint first.")
@@ -317,9 +188,9 @@ class SelfApiWriter:
317
  self._initialize_content_state(content_id)
318
 
319
  def generate_intro_iteration(iteration: int,
320
- previous_summary: str,
321
- points_to_cover: List[str],
322
- narrative_threads: List[str]) -> str:
323
  """Generate a single iteration of the introduction"""
324
  full_blueprint = self.context.get('full_original_blueprint', '')
325
 
@@ -332,7 +203,11 @@ class SelfApiWriter:
332
  Core Vision: {self.book_info.get('vision', '')}
333
  Target Audience: {self.book_info.get('target_audience', '')}
334
  Writing Style: {self.writing_guidelines.get('style', 'Academic and clear')}
335
- Tone: {self.writing_guidelines.get('tone', 'Professional')}"""
 
 
 
 
336
 
337
  response = self.client.messages.create(
338
  model=self.model,
@@ -365,15 +240,15 @@ class SelfApiWriter:
365
 
366
  content_id = f"part_{part_idx}_chapter_{chapter_idx}"
367
  self._initialize_content_state(content_id)
368
-
369
  # Add any additional prompts to the content state
370
  if additional_prompt:
371
  self.content_states[content_id].add_custom_prompt(content_id, additional_prompt)
372
-
373
  def generate_chapter_iteration(iteration: int,
374
- previous_summary: str,
375
- points_to_cover: List[str],
376
- narrative_threads: List[str]) -> str:
377
  """Generate a single chapter iteration with enhanced context"""
378
  part = self.book_structure["parts"][part_idx]
379
  chapter_title = part["chapters"][chapter_idx]
@@ -389,8 +264,8 @@ class SelfApiWriter:
389
 
390
  Blueprint Context: {self.context.get('full_original_blueprint', '')}
391
 
392
- Additional Instructions: {section_context['additional_prompt']}
393
- Custom Guidelines: {section_context['custom_instructions']}
394
 
395
  Previous Content Summary: {previous_summary}
396
  Points to Cover in This Section: {', '.join(points_to_cover)}
@@ -421,19 +296,204 @@ class SelfApiWriter:
421
 
422
  return response.content[0].text
423
 
424
- # Update generation process to include additional context
425
  full_chapter_content = self._generate_with_continuity(
426
  generate_chapter_iteration,
427
  content_id,
428
  f"Chapter: {self.book_structure['parts'][part_idx]['chapters'][chapter_idx]}"
429
  )
430
-
431
  # Store context history
432
  self.content_states[content_id].update_context_history(
433
  content_id,
434
  self.content_states[content_id].get_section_context(content_id)
435
  )
436
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  return full_chapter_content
438
 
439
- def
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # selfapi_writer.py
2
+
3
  from anthropic import Anthropic
4
  import streamlit as st
5
  import json
 
12
  def __init__(self):
13
  """Initialize the Self.api writer with enhanced content tracking"""
14
  ANTHROPIC_API_KEY = os.getenv('api_key')
15
+
16
  if not ANTHROPIC_API_KEY:
17
  raise ValueError("Anthropic API key not found. Please ensure ANTHROPIC_API_KEY is set.")
18
 
 
153
  temperature=0,
154
  system=system_prompt,
155
  messages=[{
156
+ "role": "user",
157
  "content": f"""Analyze this book blueprint and extract ALL information:
158
 
159
  {truncated_blueprint}
 
179
  st.error(f"Error processing blueprint: {str(e)}")
180
  return None
181
 
182
+ def write_introduction(self, additional_prompt: str = "") -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  """Generate the book's introduction with enhanced continuity"""
184
  if not self.initialized:
185
  raise ValueError("Writer not initialized. Process blueprint first.")
 
188
  self._initialize_content_state(content_id)
189
 
190
  def generate_intro_iteration(iteration: int,
191
+ previous_summary: str,
192
+ points_to_cover: List[str],
193
+ narrative_threads: List[str]) -> str:
194
  """Generate a single iteration of the introduction"""
195
  full_blueprint = self.context.get('full_original_blueprint', '')
196
 
 
203
  Core Vision: {self.book_info.get('vision', '')}
204
  Target Audience: {self.book_info.get('target_audience', '')}
205
  Writing Style: {self.writing_guidelines.get('style', 'Academic and clear')}
206
+ Tone: {self.writing_guidelines.get('tone', 'Professional')}
207
+
208
+ Additional Instructions: {additional_prompt}
209
+
210
+ Write the introduction following these guidelines."""
211
 
212
  response = self.client.messages.create(
213
  model=self.model,
 
240
 
241
  content_id = f"part_{part_idx}_chapter_{chapter_idx}"
242
  self._initialize_content_state(content_id)
243
+
244
  # Add any additional prompts to the content state
245
  if additional_prompt:
246
  self.content_states[content_id].add_custom_prompt(content_id, additional_prompt)
247
+
248
  def generate_chapter_iteration(iteration: int,
249
+ previous_summary: str,
250
+ points_to_cover: List[str],
251
+ narrative_threads: List[str]) -> str:
252
  """Generate a single chapter iteration with enhanced context"""
253
  part = self.book_structure["parts"][part_idx]
254
  chapter_title = part["chapters"][chapter_idx]
 
264
 
265
  Blueprint Context: {self.context.get('full_original_blueprint', '')}
266
 
267
+ Additional Instructions: {additional_prompt}
268
+ Custom Guidelines: {section_context.get('custom_instructions', '')}
269
 
270
  Previous Content Summary: {previous_summary}
271
  Points to Cover in This Section: {', '.join(points_to_cover)}
 
296
 
297
  return response.content[0].text
298
 
 
299
  full_chapter_content = self._generate_with_continuity(
300
  generate_chapter_iteration,
301
  content_id,
302
  f"Chapter: {self.book_structure['parts'][part_idx]['chapters'][chapter_idx]}"
303
  )
304
+
305
  # Store context history
306
  self.content_states[content_id].update_context_history(
307
  content_id,
308
  self.content_states[content_id].get_section_context(content_id)
309
  )
310
+
311
+ if 'parts' not in self.context:
312
+ self.context['parts'] = []
313
+
314
+ while len(self.context['parts']) <= part_idx:
315
+ self.context['parts'].append({'chapters': []})
316
+
317
+ while len(self.context['parts'][part_idx]['chapters']) <= chapter_idx:
318
+ self.context['parts'][part_idx]['chapters'].append({})
319
+
320
+ self.context['parts'][part_idx]['chapters'][chapter_idx] = {
321
+ 'title': self.book_structure['parts'][part_idx]['chapters'][chapter_idx],
322
+ 'content': full_chapter_content
323
+ }
324
+
325
  return full_chapter_content
326
 
327
+ def _generate_with_continuity(self,
328
+ generate_func: callable,
329
+ content_id: str,
330
+ title: str,
331
+ total_steps: int = 10) -> str:
332
+ """Enhanced generation with content continuity tracking"""
333
+ progress_bar = st.progress(0, text=f"Generating {title}...")
334
+ full_content = ""
335
+ state = self.content_states[content_id]
336
+
337
+ try:
338
+ # If manual content exists, use it as a starting point
339
+ if state.manual_content:
340
+ full_content = state.manual_content + "\n\n"
341
+ # Generate initial summary from manual content
342
+ state.current_summary = self._generate_progressive_summary(
343
+ content_id,
344
+ full_content
345
+ )
346
+
347
+ # Generate initial outline
348
+ outline = self._generate_section_outline(content_id, "section", title)
349
+ points_per_iteration = max(1, len(outline) // total_steps)
350
+
351
+ for iteration in range(1, total_steps + 1):
352
+ progress = iteration / total_steps
353
+ progress_bar.progress(
354
+ min(int(progress * 100), 100),
355
+ text=f"Generating {title}... (Iteration {iteration}/{total_steps})"
356
+ )
357
+
358
+ start_idx = (iteration - 1) * points_per_iteration
359
+ end_idx = min(start_idx + points_per_iteration, len(outline))
360
+ current_points = outline[start_idx:end_idx]
361
+
362
+ new_content = generate_func(
363
+ iteration=iteration,
364
+ previous_summary=state.current_summary,
365
+ points_to_cover=current_points,
366
+ narrative_threads=state.narrative_threads
367
+ )
368
+
369
+ state.generated_sections.append(new_content)
370
+
371
+ if iteration > 1:
372
+ transition = self._generate_transition(
373
+ content_id,
374
+ state.generated_sections[-2],
375
+ new_content
376
+ )
377
+ full_content += transition
378
+
379
+ full_content += new_content
380
+
381
+ state.current_summary = self._generate_progressive_summary(
382
+ content_id,
383
+ full_content
384
+ )
385
+ state.key_points_covered.update(current_points)
386
+
387
+ if len(full_content.split()) > self.pages_per_chapter * self.words_per_page:
388
+ break
389
+
390
+ conclusion = self._generate_conclusion(content_id, full_content)
391
+ full_content += conclusion
392
+
393
+ progress_bar.progress(100, text=f"Finished generating {title}")
394
+ return full_content
395
+
396
+ except Exception as e:
397
+ st.error(f"Error generating {title}: {e}")
398
+ progress_bar.empty()
399
+ return f"Error generating {title}: {e}"
400
+ finally:
401
+ progress_bar.empty()
402
+
403
+ def _generate_transition(self, content_id: str, prev_content: str, next_content: str) -> str:
404
+ """Generate smooth transition between sections"""
405
+ state = self.content_states[content_id]
406
+
407
+ transition_prompt = f"""Create a smooth transition between these sections:
408
+
409
+ Previous Section Summary: {self._summarize_text(prev_content)}
410
+ Next Section Key Points: {self._summarize_text(next_content)}
411
+
412
+ Create a natural bridge that:
413
+ 1. References relevant previous points
414
+ 2. Introduces upcoming concepts
415
+ 3. Maintains narrative flow
416
+ 4. Feels organic and not forced"""
417
+
418
+ response = self.client.messages.create(
419
+ model=self.model,
420
+ max_tokens=300,
421
+ temperature=0.7,
422
+ messages=[{"role": "user", "content": transition_prompt}]
423
+ )
424
+
425
+ transition = response.content[0].text
426
+ state.transition_points.append(transition)
427
+ return transition
428
+
429
+ def _generate_progressive_summary(self, content_id: str, content: str) -> str:
430
+ """Generate a running summary of content progress"""
431
+ summary_prompt = f"""Summarize the key points and narrative progression of:
432
+
433
+ {content}
434
+
435
+ Focus on:
436
+ 1. Main concepts introduced
437
+ 2. Key arguments developed
438
+ 3. Narrative threads established
439
+ 4. Important conclusions reached
440
+
441
+ Keep the summary concise but comprehensive."""
442
+
443
+ response = self.client.messages.create(
444
+ model=self.model,
445
+ max_tokens=500,
446
+ temperature=0.3,
447
+ messages=[{"role": "user", "content": summary_prompt}]
448
+ )
449
+
450
+ return response.content[0].text
451
+
452
+ def _summarize_text(self, text: str) -> str:
453
+ """Generate a concise summary of text"""
454
+ response = self.client.messages.create(
455
+ model=self.model,
456
+ max_tokens=300,
457
+ temperature=0.3,
458
+ messages=[{
459
+ "role": "user",
460
+ "content": f"Summarize the key points from this text:\n\n{text}"
461
+ }]
462
+ )
463
+ return response.content[0].text
464
+
465
+ def _generate_conclusion(self, content_id: str, full_content: str) -> str:
466
+ """Generate a conclusion that ties everything together"""
467
+ state = self.content_states[content_id]
468
+
469
+ conclusion_prompt = f"""Create a conclusion that ties together:
470
+
471
+ Content Summary: {state.current_summary}
472
+ Key Points Covered: {', '.join(state.key_points_covered)}
473
+ Narrative Threads: {', '.join(state.narrative_threads)}
474
+
475
+ The conclusion should:
476
+ 1. Summarize main arguments
477
+ 2. Connect key themes
478
+ 3. Reinforce core messages
479
+ 4. Provide closure while maintaining interest"""
480
+
481
+ response = self.client.messages.create(
482
+ model=self.model,
483
+ max_tokens=500,
484
+ temperature=0.7,
485
+ messages=[{"role": "user", "content": conclusion_prompt}]
486
+ )
487
+
488
+ return response.content[0].text
489
+
490
+ def get_current_structure(self) -> Optional[Dict[str, Any]]:
491
+ """Get current book structure and guidelines"""
492
+ if not self.initialized:
493
+ return None
494
+
495
+ return {
496
+ "book_info": self.book_info,
497
+ "structure": self.book_structure,
498
+ "guidelines": self.writing_guidelines
499
+ }