openfree commited on
Commit
2636781
ยท
verified ยท
1 Parent(s): 2a4f761

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -26
app.py CHANGED
@@ -418,6 +418,52 @@ class NovelDatabase:
418
  conn.commit()
419
  logger.info(f"Updated final novel for session {session_id}, length: {len(final_novel)}")
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  @staticmethod
422
  def get_active_sessions() -> List[Dict]:
423
  """Get all active sessions"""
@@ -1076,7 +1122,7 @@ Write a high-quality complete novel."""
1076
 
1077
  # ์ž‘์„ฑ์ž๋“ค์—๊ฒŒ๋Š” ์ ์ ˆํ•œ ํ† ํฐ ํ• ๋‹น
1078
  if role == "writer10" and stage_info and stage_info.get('test_mode'):
1079
- max_tokens = 20000 # ํ…Œ์ŠคํŠธ ๋ชจ๋“œ: ์ „์ฒด ์†Œ์„ค ์ž‘์„ฑ
1080
  temperature = 0.8
1081
  top_p = 0.95
1082
  elif role.startswith("writer"):
@@ -1211,11 +1257,12 @@ Write a high-quality complete novel."""
1211
  yield f"โŒ Error occurred: {str(e)}"
1212
 
1213
  def get_system_prompts(self, language: str) -> Dict[str, str]:
1214
- """Get system prompts for all 10 writers"""
1215
  if language == "Korean":
1216
  prompts = {
1217
  "director": "๋‹น์‹ ์€ 30ํŽ˜์ด์ง€ ์ค‘ํŽธ ์†Œ์„ค์„ ๊ธฐํšํ•˜๊ณ  ๊ฐ๋…ํ•˜๋Š” ๋ฌธํ•™ ๊ฐ๋…์ž์ž…๋‹ˆ๋‹ค. ์ฒด๊ณ„์ ์ด๊ณ  ์ฐฝ์˜์ ์ธ ์Šคํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด๋ƒ…๋‹ˆ๋‹ค.",
1218
- "critic": "๋‹น์‹ ์€ ๋‚ ์นด๋กœ์šด ํ†ต์ฐฐ๋ ฅ์„ ๊ฐ€์ง„ ๋ฌธํ•™ ๋น„ํ‰๊ฐ€์ž…๋‹ˆ๋‹ค. ๊ฑด์„ค์ ์ด๊ณ  ๊ตฌ์ฒด์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค."
 
1219
  }
1220
 
1221
  # 10๋ช…์˜ ์ž‘๊ฐ€ ํ”„๋กฌํ”„ํŠธ
@@ -1239,7 +1286,8 @@ Write a high-quality complete novel."""
1239
  else:
1240
  prompts = {
1241
  "director": "You are a literary director planning and supervising a 30-page novella. You create systematic and creative story structures.",
1242
- "critic": "You are a literary critic with sharp insights. You provide constructive and specific feedback."
 
1243
  }
1244
 
1245
  # 10 writer prompts
@@ -1550,8 +1598,31 @@ Seoyeon leaned back in her chair and closed her eyes for a moment. Fatigue penet
1550
  # ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์—์„œ writer10 ์ €์žฅ ์‹œ ํŠน๋ณ„ ์ฒ˜๋ฆฌ
1551
  if test_quick_mode and role == "writer10":
1552
  # ์ „์ฒด ๋‚ด์šฉ์„ 10๊ฐœ ์ฑ•ํ„ฐ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ์ €์žฅ
1553
- chapters = re.split(r'\[Chapter \d+\]', stage_content)
1554
- chapters = [ch.strip() for ch in chapters if ch.strip()]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1555
 
1556
  # ๊ฐ ์ฑ•ํ„ฐ๋ฅผ ๊ฐœ๋ณ„ writer๋กœ ์ €์žฅ
1557
  for i, chapter_content in enumerate(chapters[:10], 1):
@@ -1564,7 +1635,8 @@ Seoyeon leaned back in her chair and closed her eyes for a moment. Fatigue penet
1564
  chapter_content,
1565
  "complete"
1566
  )
1567
- logger.info(f"โœ… Test mode: Saved chapter {i} as writer {i}")
 
1568
  else:
1569
  NovelDatabase.save_stage(
1570
  self.current_session_id,
@@ -1585,9 +1657,12 @@ Seoyeon leaned back in her chair and closed her eyes for a moment. Fatigue penet
1585
  # Verify content after completion
1586
  if self.current_session_id:
1587
  verification = NovelDatabase.verify_novel_content(self.current_session_id)
1588
- logger.info(f"Content verification: {verification}")
 
 
 
1589
 
1590
- if verification['total_words'] < 12000:
1591
  logger.error(f"Final novel too short! Only {verification['total_words']} words")
1592
 
1593
  # Get complete novel from DB
@@ -1737,30 +1812,30 @@ Write a high-quality complete novel."""
1737
  return ""
1738
 
1739
  # Gradio Interface Functions
1740
- def process_query(query: str, language: str, session_id: str = None, test_mode: bool = False) -> Generator[Tuple[str, str, str, str], None, None]:
1741
- """Process query and yield updates with recovery status"""
1742
  if not query.strip() and not session_id:
1743
  if language == "Korean":
1744
- yield "", "", "โŒ ์†Œ์„ค ์ฃผ์ œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.", ""
1745
  else:
1746
- yield "", "", "โŒ Please enter a novel theme.", ""
1747
  return
1748
 
1749
  system = NovelWritingSystem()
1750
 
1751
  try:
1752
- # Recovery status message
1753
- recovery_status = ""
1754
  if session_id:
1755
  if language == "Korean":
1756
- recovery_status = "โ™ป๏ธ ์ด์ „ ์„ธ์…˜์„ ๋ณต๊ตฌํ•˜์—ฌ ๊ณ„์† ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค..."
1757
  else:
1758
- recovery_status = "โ™ป๏ธ Recovering previous session and continuing..."
1759
  elif test_mode:
1760
  if language == "Korean":
1761
- recovery_status = "๐Ÿงช ํ…Œ์ŠคํŠธ ๋ชจ๋“œ: ๋น ๋ฅธ ์ƒ์„ฑ (1,2๋‹จ๊ณ„ + Writer 10๋งŒ)"
1762
  else:
1763
- recovery_status = "๐Ÿงช Test Mode: Quick generation (Stages 1,2 + Writer 10 only)"
1764
 
1765
  for final_novel, stages in system.process_novel_stream(query, language, session_id, test_quick_mode=test_mode):
1766
  # Format stages for display
@@ -1771,22 +1846,22 @@ def process_query(query: str, language: str, session_id: str = None, test_mode:
1771
  total = len(stages)
1772
  progress_percent = (completed / total * 100) if total > 0 else 0
1773
 
1774
- if "โœ… Novel complete!" in str(final_novel):
1775
- status = "โœ… Complete! Ready to download."
1776
  else:
1777
  if language == "Korean":
1778
- status = f"๐Ÿ”„ ์ง„ํ–‰์ค‘... ({completed}/{total} - {progress_percent:.1f}%)"
1779
  else:
1780
- status = f"๐Ÿ”„ Processing... ({completed}/{total} - {progress_percent:.1f}%)"
1781
 
1782
- yield stages_display, final_novel, status, recovery_status
1783
 
1784
  except Exception as e:
1785
  logger.error(f"Error in process_query: {str(e)}", exc_info=True)
1786
  if language == "Korean":
1787
- yield "", "", f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", ""
1788
  else:
1789
- yield "", "", f"โŒ Error occurred: {str(e)}", ""
1790
 
1791
  def format_stages_display(stages: List[Dict[str, str]], language: str) -> str:
1792
  """Format stages into simple display with writer save status"""
 
418
  conn.commit()
419
  logger.info(f"Updated final novel for session {session_id}, length: {len(final_novel)}")
420
 
421
+ @staticmethod
422
+ def verify_novel_content(session_id: str) -> Dict[str, Any]:
423
+ """์„ธ์…˜์˜ ์ „์ฒด ์†Œ์„ค ๋‚ด์šฉ ๊ฒ€์ฆ"""
424
+ with NovelDatabase.get_db() as conn:
425
+ cursor = conn.cursor()
426
+
427
+ # ๋ชจ๋“  ์ž‘๊ฐ€ ์ˆ˜์ •๋ณธ ํ™•์ธ
428
+ cursor.execute(f'''
429
+ SELECT stage_number, stage_name, LENGTH(content) as content_length, word_count
430
+ FROM stages
431
+ WHERE session_id = ? AND stage_number IN ({','.join(map(str, WRITER_REVISION_STAGES))})
432
+ ORDER BY stage_number
433
+ ''', (session_id,))
434
+
435
+ results = []
436
+ total_length = 0
437
+ total_words = 0
438
+
439
+ for row in cursor.fetchall():
440
+ results.append({
441
+ 'stage': row['stage_number'],
442
+ 'name': row['stage_name'],
443
+ 'length': row['content_length'] or 0,
444
+ 'words': row['word_count'] or 0
445
+ })
446
+ total_length += row['content_length'] or 0
447
+ total_words += row['word_count'] or 0
448
+
449
+ # ์ตœ์ข… ์†Œ์„ค ํ™•์ธ
450
+ cursor.execute('''
451
+ SELECT LENGTH(final_novel) as final_length
452
+ FROM sessions
453
+ WHERE session_id = ?
454
+ ''', (session_id,))
455
+
456
+ final_row = cursor.fetchone()
457
+ final_length = final_row['final_length'] if final_row else 0
458
+
459
+ return {
460
+ 'writer_stages': results,
461
+ 'total_writer_content': total_length,
462
+ 'total_words': total_words,
463
+ 'final_novel_length': final_length,
464
+ 'expected_words': 14500 # 10 ์ž‘๊ฐ€ * 1450 ํ‰๊ท 
465
+ }
466
+
467
  @staticmethod
468
  def get_active_sessions() -> List[Dict]:
469
  """Get all active sessions"""
 
1122
 
1123
  # ์ž‘์„ฑ์ž๋“ค์—๊ฒŒ๋Š” ์ ์ ˆํ•œ ํ† ํฐ ํ• ๋‹น
1124
  if role == "writer10" and stage_info and stage_info.get('test_mode'):
1125
+ max_tokens = 30000 # ํ…Œ์ŠคํŠธ ๋ชจ๋“œ: ์ „์ฒด ์†Œ์„ค ์ž‘์„ฑ (์ถฉ๋ถ„ํ•œ ํ† ํฐ)
1126
  temperature = 0.8
1127
  top_p = 0.95
1128
  elif role.startswith("writer"):
 
1257
  yield f"โŒ Error occurred: {str(e)}"
1258
 
1259
  def get_system_prompts(self, language: str) -> Dict[str, str]:
1260
+ """Get system prompts for all writers including test mode"""
1261
  if language == "Korean":
1262
  prompts = {
1263
  "director": "๋‹น์‹ ์€ 30ํŽ˜์ด์ง€ ์ค‘ํŽธ ์†Œ์„ค์„ ๊ธฐํšํ•˜๊ณ  ๊ฐ๋…ํ•˜๋Š” ๋ฌธํ•™ ๊ฐ๋…์ž์ž…๋‹ˆ๋‹ค. ์ฒด๊ณ„์ ์ด๊ณ  ์ฐฝ์˜์ ์ธ ์Šคํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด๋ƒ…๋‹ˆ๋‹ค.",
1264
+ "critic": "๋‹น์‹ ์€ ๋‚ ์นด๋กœ์šด ํ†ต์ฐฐ๋ ฅ์„ ๊ฐ€์ง„ ๋ฌธํ•™ ๋น„ํ‰๊ฐ€์ž…๋‹ˆ๋‹ค. ๊ฑด์„ค์ ์ด๊ณ  ๊ตฌ์ฒด์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.",
1265
+ "writer10": "[ํ…Œ์ŠคํŠธ ๋ชจ๋“œ] ๋‹น์‹ ์€ ์ „์ฒด 30ํŽ˜์ด์ง€ ์†Œ์„ค์„ ํ•œ ๋ฒˆ์— ์ž‘์„ฑํ•˜๋Š” ํŠน๋ณ„ ์ž‘๊ฐ€์ž…๋‹ˆ๋‹ค. 10๊ฐœ ์ฑ•ํ„ฐ๋กœ ๊ตฌ์„ฑ๋œ ์™„์ „ํ•œ ์†Œ์„ค์„ ์ž‘์„ฑํ•˜์„ธ์š”."
1266
  }
1267
 
1268
  # 10๋ช…์˜ ์ž‘๊ฐ€ ํ”„๋กฌํ”„ํŠธ
 
1286
  else:
1287
  prompts = {
1288
  "director": "You are a literary director planning and supervising a 30-page novella. You create systematic and creative story structures.",
1289
+ "critic": "You are a literary critic with sharp insights. You provide constructive and specific feedback.",
1290
+ "writer10": "[TEST MODE] You are a special writer creating the complete 30-page novel at once. Write a complete novel organized into 10 chapters."
1291
  }
1292
 
1293
  # 10 writer prompts
 
1598
  # ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์—์„œ writer10 ์ €์žฅ ์‹œ ํŠน๋ณ„ ์ฒ˜๋ฆฌ
1599
  if test_quick_mode and role == "writer10":
1600
  # ์ „์ฒด ๋‚ด์šฉ์„ 10๊ฐœ ์ฑ•ํ„ฐ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ์ €์žฅ
1601
+ # [Chapter ์ˆซ์ž] ํŒจํ„ด์œผ๋กœ ๋ถ„ํ• 
1602
+ chapter_pattern = r'\[Chapter\s+\d+\]'
1603
+ chapters_with_headers = re.split(f'({chapter_pattern})', stage_content)
1604
+
1605
+ # ์ฑ•ํ„ฐ ๋‚ด์šฉ๋งŒ ์ถ”์ถœ (ํ—ค๋”์™€ ๋‚ด์šฉ์„ ์Œ์œผ๋กœ)
1606
+ chapters = []
1607
+ for i in range(1, len(chapters_with_headers), 2):
1608
+ if i+1 < len(chapters_with_headers):
1609
+ chapter_content = chapters_with_headers[i+1].strip()
1610
+ if chapter_content:
1611
+ chapters.append(chapter_content)
1612
+
1613
+ # ์ฑ•ํ„ฐ๊ฐ€ 10๊ฐœ๊ฐ€ ์•ˆ ๋˜๋ฉด ๊ท ๋“ฑ ๋ถ„ํ• 
1614
+ if len(chapters) < 10:
1615
+ logger.warning(f"Only {len(chapters)} chapters found, splitting evenly")
1616
+ # ์ „์ฒด ํ…์ŠคํŠธ๋ฅผ 10๊ฐœ๋กœ ๊ท ๋“ฑ ๋ถ„ํ• 
1617
+ total_text = stage_content.replace('[Chapter', '\n[Chapter')
1618
+ words = total_text.split()
1619
+ words_per_chapter = len(words) // 10
1620
+ chapters = []
1621
+ for i in range(10):
1622
+ start_idx = i * words_per_chapter
1623
+ end_idx = (i + 1) * words_per_chapter if i < 9 else len(words)
1624
+ chapter_words = words[start_idx:end_idx]
1625
+ chapters.append(' '.join(chapter_words))
1626
 
1627
  # ๊ฐ ์ฑ•ํ„ฐ๋ฅผ ๊ฐœ๋ณ„ writer๋กœ ์ €์žฅ
1628
  for i, chapter_content in enumerate(chapters[:10], 1):
 
1635
  chapter_content,
1636
  "complete"
1637
  )
1638
+ word_count = len(chapter_content.split())
1639
+ logger.info(f"โœ… Test mode: Saved chapter {i} as writer {i} ({word_count} words)")
1640
  else:
1641
  NovelDatabase.save_stage(
1642
  self.current_session_id,
 
1657
  # Verify content after completion
1658
  if self.current_session_id:
1659
  verification = NovelDatabase.verify_novel_content(self.current_session_id)
1660
+ if test_quick_mode:
1661
+ logger.info(f"[TEST MODE] Content verification: {verification}")
1662
+ else:
1663
+ logger.info(f"Content verification: {verification}")
1664
 
1665
+ if verification['total_words'] < 12000 and not test_quick_mode:
1666
  logger.error(f"Final novel too short! Only {verification['total_words']} words")
1667
 
1668
  # Get complete novel from DB
 
1812
  return ""
1813
 
1814
  # Gradio Interface Functions
1815
+ def process_query(query: str, language: str, session_id: str = None, test_mode: bool = False) -> Generator[Tuple[str, str, str], None, None]:
1816
+ """Process query and yield updates"""
1817
  if not query.strip() and not session_id:
1818
  if language == "Korean":
1819
+ yield "", "", "โŒ ์†Œ์„ค ์ฃผ์ œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
1820
  else:
1821
+ yield "", "", "โŒ Please enter a novel theme."
1822
  return
1823
 
1824
  system = NovelWritingSystem()
1825
 
1826
  try:
1827
+ # Status message with mode indicator
1828
+ mode_status = ""
1829
  if session_id:
1830
  if language == "Korean":
1831
+ mode_status = " [โ™ป๏ธ ๋ณต๊ตฌ ๋ชจ๋“œ]"
1832
  else:
1833
+ mode_status = " [โ™ป๏ธ Recovery Mode]"
1834
  elif test_mode:
1835
  if language == "Korean":
1836
+ mode_status = " [๐Ÿงช ํ…Œ์ŠคํŠธ ๋ชจ๋“œ]"
1837
  else:
1838
+ mode_status = " [๐Ÿงช Test Mode]"
1839
 
1840
  for final_novel, stages in system.process_novel_stream(query, language, session_id, test_quick_mode=test_mode):
1841
  # Format stages for display
 
1846
  total = len(stages)
1847
  progress_percent = (completed / total * 100) if total > 0 else 0
1848
 
1849
+ if "โœ… Novel complete!" in str(final_novel) or "โœ… [TEST MODE] Novel complete!" in str(final_novel):
1850
+ status = f"โœ… Complete! Ready to download.{mode_status}"
1851
  else:
1852
  if language == "Korean":
1853
+ status = f"๐Ÿ”„ ์ง„ํ–‰์ค‘... ({completed}/{total} - {progress_percent:.1f}%){mode_status}"
1854
  else:
1855
+ status = f"๐Ÿ”„ Processing... ({completed}/{total} - {progress_percent:.1f}%){mode_status}"
1856
 
1857
+ yield stages_display, final_novel, status
1858
 
1859
  except Exception as e:
1860
  logger.error(f"Error in process_query: {str(e)}", exc_info=True)
1861
  if language == "Korean":
1862
+ yield "", "", f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
1863
  else:
1864
+ yield "", "", f"โŒ Error occurred: {str(e)}"
1865
 
1866
  def format_stages_display(stages: List[Dict[str, str]], language: str) -> str:
1867
  """Format stages into simple display with writer save status"""