Spaces:
Running
Running
Update app.py
Browse files
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 =
|
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
|
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 |
-
|
1554 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
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 |
-
|
|
|
|
|
|
|
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
|
1741 |
-
"""Process query and yield updates
|
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 |
-
#
|
1753 |
-
|
1754 |
if session_id:
|
1755 |
if language == "Korean":
|
1756 |
-
|
1757 |
else:
|
1758 |
-
|
1759 |
elif test_mode:
|
1760 |
if language == "Korean":
|
1761 |
-
|
1762 |
else:
|
1763 |
-
|
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
|
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"""
|