Update appback.py3
Browse files- appback.py3 +714 -66
appback.py3
CHANGED
@@ -1602,6 +1602,382 @@ def show_story_progress():
|
|
1602 |
</div>
|
1603 |
""", unsafe_allow_html=True)
|
1604 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1605 |
def show_story_ending_options():
|
1606 |
"""Display story ending options and guidance"""
|
1607 |
if len(st.session_state.story) >= 10: # Show options when story is long enough
|
@@ -2275,8 +2651,20 @@ def show_sidebar():
|
|
2275 |
else:
|
2276 |
st.sidebar.info("ยังไม่มีเรื่องราวที่จะรีเซ็ต")
|
2277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2278 |
def show_story_input():
|
2279 |
-
"""Display story input section"""
|
2280 |
st.markdown("""
|
2281 |
<div class="thai-eng">
|
2282 |
<div class="thai">✏️ ถึงตาคุณแล้ว</div>
|
@@ -2284,59 +2672,83 @@ def show_story_input():
|
|
2284 |
</div>
|
2285 |
""", unsafe_allow_html=True)
|
2286 |
|
2287 |
-
# Initialize
|
2288 |
if 'clear_input' not in st.session_state:
|
2289 |
st.session_state.clear_input = False
|
2290 |
-
|
2291 |
-
|
2292 |
-
|
2293 |
-
|
2294 |
-
# If clear_input flag is True, reset it
|
2295 |
-
if st.session_state.clear_input:
|
2296 |
-
st.session_state.clear_input = False
|
2297 |
|
2298 |
# Show remaining sentences if in ending mode
|
2299 |
if st.session_state.get('ending_mode'):
|
2300 |
remaining = st.session_state.sentences_to_end
|
2301 |
st.info(f"🎭 โหมดจบเรื่อง - เหลืออีก {remaining} ประโยค")
|
2302 |
|
2303 |
-
# Input area
|
2304 |
text_input = st.text_area(
|
2305 |
"เขียนต่อจากเรื่องราว | Continue the story:",
|
2306 |
-
value=st.session_state.
|
2307 |
height=100,
|
2308 |
-
key="
|
2309 |
help="พิมพ์ประโยคภาษาอังกฤษเพื่อต่อเรื่อง",
|
2310 |
label_visibility="collapsed"
|
2311 |
)
|
2312 |
|
2313 |
-
#
|
2314 |
st.session_state.text_input = text_input
|
2315 |
|
2316 |
-
# Submit
|
2317 |
-
col1, col2 = st.columns([3, 1])
|
|
|
2318 |
with col1:
|
2319 |
-
|
2320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2321 |
st.warning("กรุณาเขียนข้อความก่อนส่ง")
|
2322 |
-
return
|
2323 |
-
try:
|
2324 |
-
with st.spinner("กำลังวิเคราะห์ประโยค..."):
|
2325 |
-
handle_story_submission(text_input.strip())
|
2326 |
-
except Exception as e:
|
2327 |
-
logging.error(f"Error submitting story: {str(e)}")
|
2328 |
-
st.error("เกิดข้อผิดพลาดในการส่งคำตอบ กรุณาลองใหม่อีกครั้���")
|
2329 |
|
2330 |
with col2:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2331 |
char_count = len(text_input)
|
2332 |
st.markdown(f"""
|
2333 |
-
<div style="text-align: right; color: {'red' if char_count > 200 else '#666'};">
|
2334 |
{char_count}/200 ตัวอักษร
|
2335 |
</div>
|
2336 |
""", unsafe_allow_html=True)
|
2337 |
|
|
|
|
|
|
|
|
|
2338 |
def handle_story_submission(text: str):
|
2339 |
-
"""Handle story submission
|
2340 |
if not st.session_state.story:
|
2341 |
st.error("กรุณาเลือกธีมเรื่องราวก่อนเริ่มเขียน")
|
2342 |
return
|
@@ -2344,6 +2756,8 @@ def handle_story_submission(text: str):
|
|
2344 |
# Check if in ending mode
|
2345 |
if st.session_state.get('ending_mode'):
|
2346 |
handle_ending_mode(text)
|
|
|
|
|
2347 |
return
|
2348 |
|
2349 |
# Regular processing
|
@@ -2410,14 +2824,23 @@ def handle_story_submission(text: str):
|
|
2410 |
# Update session stats
|
2411 |
update_session_stats()
|
2412 |
|
2413 |
-
#
|
2414 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2415 |
|
2416 |
# Rerun to update UI
|
2417 |
st.rerun()
|
2418 |
|
2419 |
except Exception as e:
|
2420 |
logging.error(f"Error in story submission: {str(e)}")
|
|
|
|
|
2421 |
raise
|
2422 |
|
2423 |
|
@@ -2546,8 +2969,20 @@ def show_completion_options():
|
|
2546 |
try:
|
2547 |
st.balloons()
|
2548 |
|
2549 |
-
# Show completion message
|
2550 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2551 |
<div style="
|
2552 |
background-color: #e8f5e9;
|
2553 |
padding: 20px;
|
@@ -2560,50 +2995,58 @@ def show_completion_options():
|
|
2560 |
🎉 ยินดีด้วย! คุณเขียนเรื่องราวจบสมบูรณ์แล้ว
|
2561 |
</h2>
|
2562 |
<p style="color: #1b5e20;">
|
2563 |
-
เรื่องราวของคุณจบลงด้วย: {
|
2564 |
</p>
|
2565 |
</div>
|
2566 |
""", unsafe_allow_html=True)
|
2567 |
|
2568 |
# Show statistics
|
2569 |
-
|
2570 |
-
with metrics_col1:
|
2571 |
-
st.metric(
|
2572 |
-
"จำนวนประโยคทั้งหมด",
|
2573 |
-
len(st.session_state.story),
|
2574 |
-
help="จำนวนประโยคในเรื่องทั้งหมด"
|
2575 |
-
)
|
2576 |
-
st.metric(
|
2577 |
-
"คำศัพท์ที่ใช้",
|
2578 |
-
len(st.session_state.stats['vocabulary_used']),
|
2579 |
-
help="จำนวนคำศัพท์ที่ไม่ซ้ำกัน"
|
2580 |
-
)
|
2581 |
|
2582 |
-
|
2583 |
-
|
2584 |
-
"คะแนนรวม",
|
2585 |
-
st.session_state.points['total'],
|
2586 |
-
help="คะแนนรวมที่ได้รับ"
|
2587 |
-
)
|
2588 |
-
st.metric(
|
2589 |
-
"ความแม่นยำ",
|
2590 |
-
f"{st.session_state.stats['accuracy_rate']:.1f}%",
|
2591 |
-
help="อัตราการเขียนถูกต้อง"
|
2592 |
-
)
|
2593 |
|
2594 |
-
|
2595 |
-
|
2596 |
-
save_completed_story()
|
2597 |
-
|
2598 |
-
# New story option
|
2599 |
-
if st.button("🔄 เริ่มเรื่องใหม่",
|
2600 |
-
key="new_story_button",
|
2601 |
use_container_width=True):
|
2602 |
-
|
2603 |
-
|
2604 |
-
|
2605 |
-
|
2606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2607 |
reset_story()
|
2608 |
st.rerun()
|
2609 |
|
@@ -2611,6 +3054,211 @@ def show_completion_options():
|
|
2611 |
logging.error(f"Error showing completion options: {str(e)}")
|
2612 |
st.error("เกิดข้อผิดพลาดในการแสดงตัวเลือกหลังจบเรื่อง")
|
2613 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2614 |
def show_save_dialog():
|
2615 |
"""Display save options dialog"""
|
2616 |
try:
|
|
|
1602 |
</div>
|
1603 |
""", unsafe_allow_html=True)
|
1604 |
|
1605 |
+
def generate_story_summary(story_entries: List[dict]) -> str:
|
1606 |
+
"""Generate a concise summary of the story for the stitching process"""
|
1607 |
+
try:
|
1608 |
+
# Extract main story content
|
1609 |
+
story_text = []
|
1610 |
+
for entry in story_entries:
|
1611 |
+
if entry.get('content'):
|
1612 |
+
text = entry['content'].strip()
|
1613 |
+
if text.endswith('.'):
|
1614 |
+
text = text[:-1] # Remove trailing period for better concatenation
|
1615 |
+
story_text.append(text)
|
1616 |
+
|
1617 |
+
story_summary = '. '.join(story_text) + '.'
|
1618 |
+
return story_summary
|
1619 |
+
|
1620 |
+
except Exception as e:
|
1621 |
+
logging.error(f"Error generating story summary: {str(e)}")
|
1622 |
+
return "Error creating story summary."
|
1623 |
+
|
1624 |
+
def stitch_story(raw_story: List[dict], theme_id: str, level: str) -> Dict[str, str]:
|
1625 |
+
"""Create a polished, coherent version of the story with Thai translation"""
|
1626 |
+
try:
|
1627 |
+
# Get theme details for context
|
1628 |
+
theme = story_themes.get(theme_id, {})
|
1629 |
+
theme_context = f"Theme: {theme.get('name_en', 'General')} - {theme.get('description_en', '')}"
|
1630 |
+
|
1631 |
+
# Get story summary
|
1632 |
+
story_summary = generate_story_summary(raw_story)
|
1633 |
+
|
1634 |
+
# Create level-appropriate instructions
|
1635 |
+
level_context = {
|
1636 |
+
'Beginner': {
|
1637 |
+
'instructions': """
|
1638 |
+
Create a simple, clear narrative using:
|
1639 |
+
- Basic vocabulary
|
1640 |
+
- Short, straightforward sentences
|
1641 |
+
- Present tense
|
1642 |
+
- Clear transitions
|
1643 |
+
Maintain the original story's key points but make it flow smoothly.
|
1644 |
+
""",
|
1645 |
+
'max_tokens': 500,
|
1646 |
+
'temperature': 0.7
|
1647 |
+
},
|
1648 |
+
'Intermediate': {
|
1649 |
+
'instructions': """
|
1650 |
+
Create an engaging narrative using:
|
1651 |
+
- Grade-appropriate vocabulary
|
1652 |
+
- Mix of simple and compound sentences
|
1653 |
+
- Present and past tense
|
1654 |
+
- Natural transitions
|
1655 |
+
Preserve the original story's elements while enhancing the flow.
|
1656 |
+
""",
|
1657 |
+
'max_tokens': 700,
|
1658 |
+
'temperature': 0.7
|
1659 |
+
},
|
1660 |
+
'Advanced': {
|
1661 |
+
'instructions': """
|
1662 |
+
Create a sophisticated narrative using:
|
1663 |
+
- Rich vocabulary
|
1664 |
+
- Varied sentence structures
|
1665 |
+
- Multiple tenses
|
1666 |
+
- Elegant transitions
|
1667 |
+
Maintain the story's essence while adding literary flourish.
|
1668 |
+
""",
|
1669 |
+
'max_tokens': 1000,
|
1670 |
+
'temperature': 0.8
|
1671 |
+
}
|
1672 |
+
}
|
1673 |
+
|
1674 |
+
level_settings = level_context[level]
|
1675 |
+
|
1676 |
+
# Generate polished English version
|
1677 |
+
response = client.chat.completions.create(
|
1678 |
+
model="gpt-4o-mini",
|
1679 |
+
messages=[
|
1680 |
+
{
|
1681 |
+
"role": "system",
|
1682 |
+
"content": f"""
|
1683 |
+
You are a professional children's story editor.
|
1684 |
+
{level_settings['instructions']}
|
1685 |
+
Context: {theme_context}
|
1686 |
+
|
1687 |
+
Task: Create a polished, coherent version of this story while:
|
1688 |
+
1. Maintaining the original plot points
|
1689 |
+
2. Improving flow and transitions
|
1690 |
+
3. Adding appropriate descriptive elements
|
1691 |
+
4. Making the narrative more engaging
|
1692 |
+
5. Keeping the language level appropriate for {level} students
|
1693 |
+
"""
|
1694 |
+
},
|
1695 |
+
{
|
1696 |
+
"role": "user",
|
1697 |
+
"content": f"Original story:\n{story_summary}\n\nCreate a polished version:"
|
1698 |
+
}
|
1699 |
+
],
|
1700 |
+
max_tokens=level_settings['max_tokens'],
|
1701 |
+
temperature=level_settings['temperature']
|
1702 |
+
)
|
1703 |
+
|
1704 |
+
polished_english = response.choices[0].message.content.strip()
|
1705 |
+
|
1706 |
+
# Generate Thai translation
|
1707 |
+
translation_response = client.chat.completions.create(
|
1708 |
+
model="gpt-4o-mini",
|
1709 |
+
messages=[
|
1710 |
+
{
|
1711 |
+
"role": "system",
|
1712 |
+
"content": """
|
1713 |
+
You are a professional Thai-English translator specializing in children's literature.
|
1714 |
+
Create a natural, flowing Thai translation that:
|
1715 |
+
1. Captures the story's meaning and emotion
|
1716 |
+
2. Uses appropriate Thai language for the target age group
|
1717 |
+
3. Maintains cultural relevance
|
1718 |
+
4. Reads naturally in Thai
|
1719 |
+
"""
|
1720 |
+
},
|
1721 |
+
{
|
1722 |
+
"role": "user",
|
1723 |
+
"content": f"Translate this story to Thai:\n{polished_english}"
|
1724 |
+
}
|
1725 |
+
],
|
1726 |
+
max_tokens=1000,
|
1727 |
+
temperature=0.7
|
1728 |
+
)
|
1729 |
+
|
1730 |
+
thai_translation = translation_response.choices[0].message.content.strip()
|
1731 |
+
|
1732 |
+
return {
|
1733 |
+
'original': story_summary,
|
1734 |
+
'polished_english': polished_english,
|
1735 |
+
'thai_translation': thai_translation
|
1736 |
+
}
|
1737 |
+
|
1738 |
+
except Exception as e:
|
1739 |
+
logging.error(f"Error in story stitching: {str(e)}")
|
1740 |
+
raise
|
1741 |
+
|
1742 |
+
def show_stitched_story(story_data: Dict[str, str]):
|
1743 |
+
"""Display the stitched story with translation"""
|
1744 |
+
try:
|
1745 |
+
st.markdown("# 📖 Your Polished Story | เรื่องราวฉบับสมบูรณ์")
|
1746 |
+
|
1747 |
+
# English Version
|
1748 |
+
st.markdown("### 🇬🇧 English Version")
|
1749 |
+
st.markdown(
|
1750 |
+
f"""
|
1751 |
+
<div style="background-color: #f8f9fa; padding: 20px; border-radius: 10px;
|
1752 |
+
border-left: 4px solid #1565c0; margin-bottom: 20px;">
|
1753 |
+
{story_data['polished_english']}
|
1754 |
+
</div>
|
1755 |
+
""",
|
1756 |
+
unsafe_allow_html=True
|
1757 |
+
)
|
1758 |
+
|
1759 |
+
# Thai Version
|
1760 |
+
st.markdown("### 🇹🇭 ฉบับภาษาไทย")
|
1761 |
+
st.markdown(
|
1762 |
+
f"""
|
1763 |
+
<div style="background-color: #f8f9fa; padding: 20px; border-radius: 10px;
|
1764 |
+
border-left: 4px solid #28a745; margin-bottom: 20px;">
|
1765 |
+
{story_data['thai_translation']}
|
1766 |
+
</div>
|
1767 |
+
""",
|
1768 |
+
unsafe_allow_html=True
|
1769 |
+
)
|
1770 |
+
|
1771 |
+
# Save Options
|
1772 |
+
st.markdown("### 💾 บันทึกเรื่องราวฉบับสมบูรณ์")
|
1773 |
+
save_col1, save_col2 = st.columns(2)
|
1774 |
+
|
1775 |
+
with save_col1:
|
1776 |
+
if st.button("📥 บันทึกเป็น PDF", key="save_stitched_pdf", use_container_width=True):
|
1777 |
+
pdf_data = create_bilingual_story_pdf(story_data)
|
1778 |
+
st.download_button(
|
1779 |
+
"ดาวน์โหลด PDF",
|
1780 |
+
data=pdf_data,
|
1781 |
+
file_name=f"my_story_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf",
|
1782 |
+
mime="application/pdf",
|
1783 |
+
key="download_stitched_pdf"
|
1784 |
+
)
|
1785 |
+
|
1786 |
+
with save_col2:
|
1787 |
+
if st.button("💾 บันทึกข้อความ", key="save_stitched_text", use_container_width=True):
|
1788 |
+
text_data = json.dumps(story_data, ensure_ascii=False, indent=2)
|
1789 |
+
st.download_button(
|
1790 |
+
"ดาวน์โหลดข้อความ",
|
1791 |
+
data=text_data,
|
1792 |
+
file_name=f"my_story_{datetime.now().strftime('%Y%m%d_%H%M')}.json",
|
1793 |
+
mime="application/json",
|
1794 |
+
key="download_stitched_text"
|
1795 |
+
)
|
1796 |
+
|
1797 |
+
except Exception as e:
|
1798 |
+
logging.error(f"Error showing stitched story: {str(e)}")
|
1799 |
+
st.error("เกิดข้อผิดพลาดในการแสดงเรื่องราว กรุณาลองใหม่อีกครั้ง")
|
1800 |
+
|
1801 |
+
def create_bilingual_story_pdf(story_data: Dict[str, str]) -> bytes:
|
1802 |
+
"""Create a PDF with both English and Thai versions of the story"""
|
1803 |
+
try:
|
1804 |
+
buffer = io.BytesIO()
|
1805 |
+
doc = SimpleDocTemplate(
|
1806 |
+
buffer,
|
1807 |
+
pagesize=A4,
|
1808 |
+
rightMargin=72,
|
1809 |
+
leftMargin=72,
|
1810 |
+
topMargin=72,
|
1811 |
+
bottomMargin=72
|
1812 |
+
)
|
1813 |
+
|
1814 |
+
# Create styles
|
1815 |
+
styles = getSampleStyleSheet()
|
1816 |
+
title_style = ParagraphStyle(
|
1817 |
+
'CustomTitle',
|
1818 |
+
parent=styles['Title'],
|
1819 |
+
fontSize=24,
|
1820 |
+
spaceAfter=30,
|
1821 |
+
alignment=1 # Center alignment
|
1822 |
+
)
|
1823 |
+
heading_style = ParagraphStyle(
|
1824 |
+
'CustomHeading',
|
1825 |
+
parent=styles['Heading1'],
|
1826 |
+
fontSize=18,
|
1827 |
+
spaceAfter=12,
|
1828 |
+
textColor=colors.blue
|
1829 |
+
)
|
1830 |
+
body_style = ParagraphStyle(
|
1831 |
+
'CustomBody',
|
1832 |
+
parent=styles['Normal'],
|
1833 |
+
fontSize=12,
|
1834 |
+
spaceBefore=6,
|
1835 |
+
spaceAfter=6,
|
1836 |
+
leading=16
|
1837 |
+
)
|
1838 |
+
|
1839 |
+
# Create story elements
|
1840 |
+
elements = []
|
1841 |
+
|
1842 |
+
# Add title
|
1843 |
+
elements.append(Paragraph("My Story - JoyStory", title_style))
|
1844 |
+
elements.append(Spacer(1, 20))
|
1845 |
+
|
1846 |
+
# Add English version
|
1847 |
+
elements.append(Paragraph("English Version", heading_style))
|
1848 |
+
elements.append(Paragraph(story_data['polished_english'], body_style))
|
1849 |
+
elements.append(Spacer(1, 20))
|
1850 |
+
|
1851 |
+
# Add Thai version
|
1852 |
+
elements.append(Paragraph("ฉบับภาษาไทย", heading_style))
|
1853 |
+
elements.append(Paragraph(story_data['thai_translation'], body_style))
|
1854 |
+
|
1855 |
+
# Build PDF
|
1856 |
+
doc.build(elements)
|
1857 |
+
pdf = buffer.getvalue()
|
1858 |
+
buffer.close()
|
1859 |
+
|
1860 |
+
return pdf
|
1861 |
+
|
1862 |
+
except Exception as e:
|
1863 |
+
logging.error(f"Error creating bilingual PDF: {str(e)}")
|
1864 |
+
raise
|
1865 |
+
|
1866 |
+
def show_story_stats():
|
1867 |
+
"""Display comprehensive story statistics"""
|
1868 |
+
try:
|
1869 |
+
st.markdown("""
|
1870 |
+
<div style="
|
1871 |
+
background-color: #f3e5f5;
|
1872 |
+
padding: 20px;
|
1873 |
+
border-radius: 10px;
|
1874 |
+
margin: 20px 0;
|
1875 |
+
">
|
1876 |
+
<h3 style="color: #6a1b9a; margin-bottom: 15px; text-align: center;">
|
1877 |
+
📊 สถิติการเขียนเรื่องราว
|
1878 |
+
</h3>
|
1879 |
+
""", unsafe_allow_html=True)
|
1880 |
+
|
1881 |
+
# Basic statistics in 2 columns
|
1882 |
+
col1, col2 = st.columns(2)
|
1883 |
+
|
1884 |
+
with col1:
|
1885 |
+
st.metric(
|
1886 |
+
"จำนวนประโยคทั้งหมด",
|
1887 |
+
len(st.session_state.story),
|
1888 |
+
help="จำนวนประโยคในเรื่องทั้งหมด"
|
1889 |
+
)
|
1890 |
+
st.metric(
|
1891 |
+
"คำศัพท์ที่ใช้",
|
1892 |
+
len(st.session_state.stats['vocabulary_used']),
|
1893 |
+
help="จำนวนคำศัพท์ที่ไม่ซ้ำกัน"
|
1894 |
+
)
|
1895 |
+
st.metric(
|
1896 |
+
"ประโยคที่ถูกต้องแล้ว",
|
1897 |
+
st.session_state.stats['correct_first_try'],
|
1898 |
+
help="จำนวนประโยคที่เขียนถูกต้องตั้งแต่ครั้งแรก"
|
1899 |
+
)
|
1900 |
+
|
1901 |
+
with col2:
|
1902 |
+
st.metric(
|
1903 |
+
"คะแนนรวม",
|
1904 |
+
st.session_state.points['total'],
|
1905 |
+
help="คะแนนรวมที่ได้รับ"
|
1906 |
+
)
|
1907 |
+
st.metric(
|
1908 |
+
"ความแม่นยำ",
|
1909 |
+
f"{st.session_state.stats['accuracy_rate']:.1f}%",
|
1910 |
+
help="อัตราการเขียนถูกต้อง"
|
1911 |
+
)
|
1912 |
+
st.metric(
|
1913 |
+
"Streak สูงสุด",
|
1914 |
+
st.session_state.points['max_streak'],
|
1915 |
+
help="จำนวนประโยคถูกต้องติดต่อกันมากที่สุด"
|
1916 |
+
)
|
1917 |
+
|
1918 |
+
# Show achievements
|
1919 |
+
if st.session_state.achievements:
|
1920 |
+
st.markdown("""
|
1921 |
+
<h4 style="color: #6a1b9a; margin: 20px 0 10px 0;">
|
1922 |
+
🏆 ความสำเร็จที่ได้รับ
|
1923 |
+
</h4>
|
1924 |
+
""", unsafe_allow_html=True)
|
1925 |
+
|
1926 |
+
for achievement in st.session_state.achievements:
|
1927 |
+
st.success(achievement)
|
1928 |
+
|
1929 |
+
# Show writing progress details
|
1930 |
+
st.markdown("""
|
1931 |
+
<h4 style="color: #6a1b9a; margin: 20px 0 10px 0;">
|
1932 |
+
📝 รายละเอียดการเขียน
|
1933 |
+
</h4>
|
1934 |
+
""", unsafe_allow_html=True)
|
1935 |
+
|
1936 |
+
details_col1, details_col2 = st.columns(2)
|
1937 |
+
|
1938 |
+
with details_col1:
|
1939 |
+
# Story composition metrics
|
1940 |
+
st.markdown("##### 📖 องค์ประกอบเรื่อง")
|
1941 |
+
avg_sentence_length = st.session_state.stats.get('average_sentence_length', 0)
|
1942 |
+
st.markdown(f"""
|
1943 |
+
- ความยาวประโยคเฉลี่ย: {avg_sentence_length:.1f} คำ
|
1944 |
+
- จำนวนคำทั้งหมด: {st.session_state.stats.get('total_words', 0)} คำ
|
1945 |
+
- การแก้ไข: {st.session_state.stats.get('corrections_made', 0)} ครั้ง
|
1946 |
+
""")
|
1947 |
+
|
1948 |
+
with details_col2:
|
1949 |
+
# Time and progress metrics
|
1950 |
+
st.markdown("##### ⏱️ เวลาและความก้าวหน้า")
|
1951 |
+
session_duration = st.session_state.stats.get('session_duration', 0)
|
1952 |
+
duration_minutes = session_duration / 60
|
1953 |
+
st.markdown(f"""
|
1954 |
+
- เวลาที่ใช้: {duration_minutes:.1f} นาที
|
1955 |
+
- ความก้าวหน้า: {min(len(st.session_state.story) * 5, 100)}%
|
1956 |
+
- สถานะ: {"จบเรื่องแล้ว" if st.session_state.story_completed else "กำลังเขียน"}
|
1957 |
+
""")
|
1958 |
+
|
1959 |
+
# Show vocabulary usage
|
1960 |
+
if st.session_state.stats['vocabulary_used']:
|
1961 |
+
with st.expander("📚 คำศัพท์ที่ใช้"):
|
1962 |
+
vocab_list = sorted(list(st.session_state.stats['vocabulary_used']))
|
1963 |
+
st.markdown(f"""
|
1964 |
+
<div style="
|
1965 |
+
background-color: white;
|
1966 |
+
padding: 10px;
|
1967 |
+
border-radius: 5px;
|
1968 |
+
max-height: 200px;
|
1969 |
+
overflow-y: auto;
|
1970 |
+
">
|
1971 |
+
{', '.join(vocab_list)}
|
1972 |
+
</div>
|
1973 |
+
""", unsafe_allow_html=True)
|
1974 |
+
|
1975 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
1976 |
+
|
1977 |
+
except Exception as e:
|
1978 |
+
logging.error(f"Error showing story stats: {str(e)}")
|
1979 |
+
st.error("เกิดข้อผิดพลาดในการแสดงสถิติ")
|
1980 |
+
|
1981 |
def show_story_ending_options():
|
1982 |
"""Display story ending options and guidance"""
|
1983 |
if len(st.session_state.story) >= 10: # Show options when story is long enough
|
|
|
2651 |
else:
|
2652 |
st.sidebar.info("ยังไม่มีเรื่องราวที่จะรีเซ็ต")
|
2653 |
|
2654 |
+
def clear_input_state():
|
2655 |
+
"""Clear all input-related session states"""
|
2656 |
+
if 'text_input' in st.session_state:
|
2657 |
+
st.session_state.text_input = ""
|
2658 |
+
if 'story_input_area' in st.session_state:
|
2659 |
+
st.session_state.story_input_area = ""
|
2660 |
+
if 'last_submission' in st.session_state:
|
2661 |
+
del st.session_state.last_submission
|
2662 |
+
st.session_state.clear_input = True
|
2663 |
+
# Increment clear count to force new input field
|
2664 |
+
st.session_state.clear_count = st.session_state.get('clear_count', 0) + 1
|
2665 |
+
|
2666 |
def show_story_input():
|
2667 |
+
"""Display story input section with improved clear functionality"""
|
2668 |
st.markdown("""
|
2669 |
<div class="thai-eng">
|
2670 |
<div class="thai">✏️ ถึงตาคุณแล้ว</div>
|
|
|
2672 |
</div>
|
2673 |
""", unsafe_allow_html=True)
|
2674 |
|
2675 |
+
# Initialize states if not exists
|
2676 |
if 'clear_input' not in st.session_state:
|
2677 |
st.session_state.clear_input = False
|
2678 |
+
if 'text_input' not in st.session_state:
|
2679 |
+
st.session_state.text_input = ""
|
2680 |
+
if 'last_submission' not in st.session_state:
|
2681 |
+
st.session_state.last_submission = None
|
|
|
|
|
|
|
2682 |
|
2683 |
# Show remaining sentences if in ending mode
|
2684 |
if st.session_state.get('ending_mode'):
|
2685 |
remaining = st.session_state.sentences_to_end
|
2686 |
st.info(f"🎭 โหมดจบเรื่อง - เหลืออีก {remaining} ประโยค")
|
2687 |
|
2688 |
+
# Input area with key based on clear state
|
2689 |
text_input = st.text_area(
|
2690 |
"เขียนต่อจากเรื่องราว | Continue the story:",
|
2691 |
+
value=st.session_state.text_input,
|
2692 |
height=100,
|
2693 |
+
key=f"story_input_area_{st.session_state.get('clear_count', 0)}",
|
2694 |
help="พิมพ์ประโยคภาษาอังกฤษเพื่อต่อเรื่อง",
|
2695 |
label_visibility="collapsed"
|
2696 |
)
|
2697 |
|
2698 |
+
# Keep track of current input
|
2699 |
st.session_state.text_input = text_input
|
2700 |
|
2701 |
+
# Submit and Clear buttons
|
2702 |
+
col1, col2, col3 = st.columns([3, 1, 1])
|
2703 |
+
|
2704 |
with col1:
|
2705 |
+
submit_button = st.button(
|
2706 |
+
"📝 ส่งคำตอบ | Submit",
|
2707 |
+
use_container_width=True,
|
2708 |
+
disabled=not text_input.strip() # Disable if empty
|
2709 |
+
)
|
2710 |
+
|
2711 |
+
if submit_button:
|
2712 |
+
if text_input.strip():
|
2713 |
+
try:
|
2714 |
+
# Save current submission
|
2715 |
+
st.session_state.last_submission = text_input.strip()
|
2716 |
+
with st.spinner("กำลังวิเคราะห์ประโยค..."):
|
2717 |
+
handle_story_submission(text_input.strip())
|
2718 |
+
except Exception as e:
|
2719 |
+
logging.error(f"Error submitting story: {str(e)}")
|
2720 |
+
st.error("เกิดข้อผิดพลาดในการส่งคำตอบ กรุณาลองใหม่อีกครั้ง")
|
2721 |
+
else:
|
2722 |
st.warning("กรุณาเขียนข้อความก่อนส่ง")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2723 |
|
2724 |
with col2:
|
2725 |
+
# Clear button with unique key
|
2726 |
+
if st.button(
|
2727 |
+
"🗑️ ล้างข้อความ | Clear",
|
2728 |
+
key=f"clear_button_{st.session_state.get('clear_count', 0)}",
|
2729 |
+
use_container_width=True,
|
2730 |
+
disabled=not text_input.strip() # Disable if already empty
|
2731 |
+
):
|
2732 |
+
# Increment clear count to force new key generation
|
2733 |
+
st.session_state.clear_count = st.session_state.get('clear_count', 0) + 1
|
2734 |
+
clear_input_state()
|
2735 |
+
st.rerun()
|
2736 |
+
|
2737 |
+
with col3:
|
2738 |
+
# Character count
|
2739 |
char_count = len(text_input)
|
2740 |
st.markdown(f"""
|
2741 |
+
<div style="text-align: right; color: {'red' if char_count > 200 else '#666'}; padding: 8px;">
|
2742 |
{char_count}/200 ตัวอักษร
|
2743 |
</div>
|
2744 |
""", unsafe_allow_html=True)
|
2745 |
|
2746 |
+
# Warning for long text
|
2747 |
+
if char_count > 200:
|
2748 |
+
st.warning("⚠️ ข้อความยาวเกิน 200 ตัวอักษร")
|
2749 |
+
|
2750 |
def handle_story_submission(text: str):
|
2751 |
+
"""Handle story submission with improved state management"""
|
2752 |
if not st.session_state.story:
|
2753 |
st.error("กรุณาเลือกธีมเรื่องราวก่อนเริ่มเขียน")
|
2754 |
return
|
|
|
2756 |
# Check if in ending mode
|
2757 |
if st.session_state.get('ending_mode'):
|
2758 |
handle_ending_mode(text)
|
2759 |
+
# Clear input after handling ending mode
|
2760 |
+
clear_input_state()
|
2761 |
return
|
2762 |
|
2763 |
# Regular processing
|
|
|
2824 |
# Update session stats
|
2825 |
update_session_stats()
|
2826 |
|
2827 |
+
# Clear input state completely before rerun
|
2828 |
+
clear_input_state()
|
2829 |
+
|
2830 |
+
# Make sure we don't have any lingering text
|
2831 |
+
if 'story_input_area' in st.session_state:
|
2832 |
+
st.session_state.story_input_area = ""
|
2833 |
+
|
2834 |
+
# Increment clear count to force new input field
|
2835 |
+
st.session_state.clear_count = st.session_state.get('clear_count', 0) + 1
|
2836 |
|
2837 |
# Rerun to update UI
|
2838 |
st.rerun()
|
2839 |
|
2840 |
except Exception as e:
|
2841 |
logging.error(f"Error in story submission: {str(e)}")
|
2842 |
+
# Clear input even on error to prevent stuck state
|
2843 |
+
clear_input_state()
|
2844 |
raise
|
2845 |
|
2846 |
|
|
|
2969 |
try:
|
2970 |
st.balloons()
|
2971 |
|
2972 |
+
# Show completion message with proper ending type display
|
2973 |
+
ending_type_display = {
|
2974 |
+
"Happy Ending": "จบแบบมีความสุข",
|
2975 |
+
"Mysterious Ending": "จบแบบทิ้งท้ายให้คิดต่อ",
|
2976 |
+
"Lesson Learned": "จบแบบได้ข้อคิด",
|
2977 |
+
"Surprise Ending": "จบแบบพลิกความคาดหมาย"
|
2978 |
+
}
|
2979 |
+
|
2980 |
+
current_ending = ending_type_display.get(
|
2981 |
+
st.session_state.ending_type,
|
2982 |
+
st.session_state.ending_type
|
2983 |
+
)
|
2984 |
+
|
2985 |
+
st.markdown(f"""
|
2986 |
<div style="
|
2987 |
background-color: #e8f5e9;
|
2988 |
padding: 20px;
|
|
|
2995 |
🎉 ยินดีด้วย! คุณเขียนเรื่องราวจบสมบูรณ์แล้ว
|
2996 |
</h2>
|
2997 |
<p style="color: #1b5e20;">
|
2998 |
+
เรื่องราวของคุณจบลงด้วย: {current_ending}
|
2999 |
</p>
|
3000 |
</div>
|
3001 |
""", unsafe_allow_html=True)
|
3002 |
|
3003 |
# Show statistics
|
3004 |
+
show_story_stats()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3005 |
|
3006 |
+
# Offer story stitching option
|
3007 |
+
st.markdown("### ✨ ต้องการให้ AI ช่วยเรียบเรียงเรื่องราวให้สมบูรณ์ขึ้นไหม?")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3008 |
|
3009 |
+
if st.button("🎨 เรียบเรียงเรื่องราว",
|
3010 |
+
key="stitch_story_button",
|
|
|
|
|
|
|
|
|
|
|
3011 |
use_container_width=True):
|
3012 |
+
with st.spinner("กำลังเรียบเรียงเรื่องราว..."):
|
3013 |
+
try:
|
3014 |
+
stitched_story = generate_stitched_story(
|
3015 |
+
story=st.session_state.story,
|
3016 |
+
style="Classic Fairytale", # Default style
|
3017 |
+
detail_level="ปานกลาง", # Default detail level
|
3018 |
+
theme=st.session_state.current_theme,
|
3019 |
+
level=st.session_state.level
|
3020 |
+
)
|
3021 |
+
st.session_state.stitched_story = stitched_story
|
3022 |
+
show_stitched_story(stitched_story)
|
3023 |
+
except Exception as e:
|
3024 |
+
logging.error(f"Error in story stitching: {str(e)}")
|
3025 |
+
st.error("เกิดข้อผิดพลาดในการเรียบเรียงเรื่องราว กรุณาลองใหม่อีกครั้ง")
|
3026 |
+
|
3027 |
+
# Original save options
|
3028 |
+
st.markdown("### 💾 บันทึกเรื่องราวต้นฉบับ")
|
3029 |
+
save_col1, save_col2 = st.columns(2)
|
3030 |
+
|
3031 |
+
with save_col1:
|
3032 |
+
if st.button("📑 บันทึกเป็น PDF",
|
3033 |
+
key="save_original_pdf",
|
3034 |
+
use_container_width=True):
|
3035 |
+
pdf_data = create_story_pdf()
|
3036 |
+
st.download_button(
|
3037 |
+
"ดาวน์โหลด PDF",
|
3038 |
+
data=pdf_data,
|
3039 |
+
file_name=f"original_story_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf",
|
3040 |
+
mime="application/pdf",
|
3041 |
+
key="download_original_pdf"
|
3042 |
+
)
|
3043 |
+
|
3044 |
+
with save_col2:
|
3045 |
+
if st.button("🔄 เริ่มเรื่องใหม่",
|
3046 |
+
key="new_story_button",
|
3047 |
+
use_container_width=True):
|
3048 |
+
if st.checkbox("✅ ยืนยันการเริ่มใหม่",
|
3049 |
+
key="confirm_new_story"):
|
3050 |
reset_story()
|
3051 |
st.rerun()
|
3052 |
|
|
|
3054 |
logging.error(f"Error showing completion options: {str(e)}")
|
3055 |
st.error("เกิดข้อผิดพลาดในการแสดงตัวเลือกหลังจบเรื่อง")
|
3056 |
|
3057 |
+
def show_story_stitching_options():
|
3058 |
+
"""Display story stitching options and handle the flow"""
|
3059 |
+
try:
|
3060 |
+
st.markdown("""
|
3061 |
+
<div style="
|
3062 |
+
background-color: #e3f2fd;
|
3063 |
+
padding: 20px;
|
3064 |
+
border-radius: 10px;
|
3065 |
+
margin: 20px 0;
|
3066 |
+
">
|
3067 |
+
<h3 style="color: #1565c0; margin-bottom: 15px;">
|
3068 |
+
✨ เรียบเรียงเรื่องราวให้สมบูรณ์
|
3069 |
+
</h3>
|
3070 |
+
<p style="color: #333;">
|
3071 |
+
AI จะช่วย:
|
3072 |
+
- ปรับแต่งการเชื่อมประโยคให้ลื่นไหล
|
3073 |
+
- เพิ่มรายละเอียดที่น่าสนใจ
|
3074 |
+
- แปลเป็นภาษาไทย
|
3075 |
+
- รักษาเนื้อเรื่องและความคิดสร้างสรรค์ของคุณไว้
|
3076 |
+
</p>
|
3077 |
+
</div>
|
3078 |
+
""", unsafe_allow_html=True)
|
3079 |
+
|
3080 |
+
col1, col2 = st.columns(2)
|
3081 |
+
|
3082 |
+
with col1:
|
3083 |
+
style_option = st.selectbox(
|
3084 |
+
"เลือกรูปแบบการเล่าเรื่อง:",
|
3085 |
+
options=[
|
3086 |
+
"Classic Fairytale - นิทานแบบคลาสสิก",
|
3087 |
+
"Modern Adventure - การผจญภัยสมัยใหม่",
|
3088 |
+
"Poetic Style - แบบกวีนิพนธ์",
|
3089 |
+
"Simple and Clear - เรียบง่ายและชัดเจน"
|
3090 |
+
],
|
3091 |
+
key="story_style_selector"
|
3092 |
+
)
|
3093 |
+
|
3094 |
+
with col2:
|
3095 |
+
detail_level = st.select_slider(
|
3096 |
+
"ระดับรายละเอียด:",
|
3097 |
+
options=["น้อย", "ปานกลาง", "มาก"],
|
3098 |
+
value="ปานกลาง",
|
3099 |
+
key="detail_level_selector"
|
3100 |
+
)
|
3101 |
+
|
3102 |
+
if st.button("🎨 เริ่มเรียบเรียงเรื่องราว",
|
3103 |
+
key="start_stitching",
|
3104 |
+
use_container_width=True):
|
3105 |
+
with st.spinner("กำลังเรียบเรียงเรื่องราว..."):
|
3106 |
+
try:
|
3107 |
+
stitched_story = generate_stitched_story(
|
3108 |
+
story=st.session_state.story,
|
3109 |
+
style=style_option,
|
3110 |
+
detail_level=detail_level,
|
3111 |
+
theme=st.session_state.current_theme,
|
3112 |
+
level=st.session_state.level
|
3113 |
+
)
|
3114 |
+
|
3115 |
+
# Save stitched story to session state
|
3116 |
+
st.session_state.stitched_story = stitched_story
|
3117 |
+
|
3118 |
+
# Show the result
|
3119 |
+
show_stitched_result(stitched_story)
|
3120 |
+
|
3121 |
+
except Exception as e:
|
3122 |
+
logging.error(f"Error in story stitching: {str(e)}")
|
3123 |
+
st.error("เกิดข้อผิดพลาดในการเรียบเรียงเรื่องราว กรุณาลองใหม่อีกครั้ง")
|
3124 |
+
|
3125 |
+
except Exception as e:
|
3126 |
+
logging.error(f"Error showing stitching options: {str(e)}")
|
3127 |
+
st.error("เกิดข้อผิดพลาดในการแสดงตัวเลือกการเรียบเรียง")
|
3128 |
+
|
3129 |
+
def generate_stitched_story(story: List[dict], style: str, detail_level: str, theme: str, level: str) -> Dict[str, str]:
|
3130 |
+
"""Generate a polished version of the story with minimal enhancements"""
|
3131 |
+
try:
|
3132 |
+
# แยกประโยคต่างๆ ตาม role
|
3133 |
+
story_parts = {
|
3134 |
+
'starter': next((entry['content'] for entry in story if entry.get('is_starter')), ''),
|
3135 |
+
'user_sentences': [entry['content'] for entry in story if entry['role'] == 'You'],
|
3136 |
+
'ai_responses': [entry['content'] for entry in story if entry['role'] == 'AI' and not entry.get('is_starter')],
|
3137 |
+
'ending': next((entry['content'] for entry in story if entry.get('is_final')), '')
|
3138 |
+
}
|
3139 |
+
|
3140 |
+
# สร้าง prompt ที่เน้นการรักษาประโยคเดิมและเชื่อมต่อแบบกระชับ
|
3141 |
+
prompt_template = f"""
|
3142 |
+
Rewrite this story into a flowing narrative.
|
3143 |
+
|
3144 |
+
CRITICAL RULES:
|
3145 |
+
1. Keep original sentences almost exactly as they are
|
3146 |
+
2. Add only minimal connecting words or phrases
|
3147 |
+
3. Do not add new scenes or events
|
3148 |
+
4. Do not add lengthy descriptions
|
3149 |
+
5. Focus on making the story flow naturally
|
3150 |
+
6. Keep any additions very brief and simple
|
3151 |
+
|
3152 |
+
Examples of good enhancement:
|
3153 |
+
Original: "The project started. We made robots."
|
3154 |
+
Good: "The project started with great excitement. We made robots, our first real creation."
|
3155 |
+
BAD: "In the sunny classroom, with students gathered around shiny tables, the project started. We made incredible robots with flashing lights and complex circuits."
|
3156 |
+
|
3157 |
+
Original Story Parts:
|
3158 |
+
- Beginning: {story_parts['starter']}
|
3159 |
+
- Main Story: {' '.join(sum(zip(story_parts['user_sentences'], story_parts['ai_responses']), ()))}
|
3160 |
+
- Ending: {story_parts['ending']}
|
3161 |
+
|
3162 |
+
Create a coherent story that stays very close to the original while making it flow smoothly.
|
3163 |
+
Remember: Less is more - add only what's necessary for flow.
|
3164 |
+
"""
|
3165 |
+
|
3166 |
+
# Generate English version with minimal enhancements
|
3167 |
+
response = client.chat.completions.create(
|
3168 |
+
model="gpt-4o-mini",
|
3169 |
+
messages=[
|
3170 |
+
{
|
3171 |
+
"role": "system",
|
3172 |
+
"content": """You are a story editor who specializes in minimal enhancement.
|
3173 |
+
Your goal is to make the story flow while keeping it as close as possible to the original.
|
3174 |
+
Remember: Only add what's absolutely necessary for coherence."""
|
3175 |
+
},
|
3176 |
+
{
|
3177 |
+
"role": "user",
|
3178 |
+
"content": prompt_template
|
3179 |
+
}
|
3180 |
+
],
|
3181 |
+
temperature=0.5 # Lower temperature for more consistent, conservative output
|
3182 |
+
)
|
3183 |
+
|
3184 |
+
polished_english = response.choices[0].message.content.strip()
|
3185 |
+
|
3186 |
+
# Generate Thai translation with same minimal approach
|
3187 |
+
translation_prompt = f"""
|
3188 |
+
Translate this story to Thai.
|
3189 |
+
|
3190 |
+
IMPORTANT:
|
3191 |
+
1. Keep the translation concise and close to the English version
|
3192 |
+
2. Do not add extra details or explanations
|
3193 |
+
3. Maintain the same level of simplicity
|
3194 |
+
4. Focus on natural Thai flow while keeping original content
|
3195 |
+
|
3196 |
+
Story to translate:
|
3197 |
+
{polished_english}
|
3198 |
+
"""
|
3199 |
+
|
3200 |
+
translation_response = client.chat.completions.create(
|
3201 |
+
model="gpt-4o-mini",
|
3202 |
+
messages=[
|
3203 |
+
{
|
3204 |
+
"role": "system",
|
3205 |
+
"content": """You are a Thai translator who specializes in concise, accurate translations.
|
3206 |
+
Keep the same level of detail as the English version without adding extra elements."""
|
3207 |
+
},
|
3208 |
+
{
|
3209 |
+
"role": "user",
|
3210 |
+
"content": translation_prompt
|
3211 |
+
}
|
3212 |
+
],
|
3213 |
+
temperature=0.5
|
3214 |
+
)
|
3215 |
+
|
3216 |
+
thai_translation = translation_response.choices[0].message.content.strip()
|
3217 |
+
|
3218 |
+
return {
|
3219 |
+
'polished_english': polished_english,
|
3220 |
+
'thai_translation': thai_translation,
|
3221 |
+
'style': style,
|
3222 |
+
'level': level
|
3223 |
+
}
|
3224 |
+
|
3225 |
+
except Exception as e:
|
3226 |
+
logging.error(f"Error generating stitched story: {str(e)}")
|
3227 |
+
raise
|
3228 |
+
|
3229 |
+
def show_stitched_result(story_data: Dict[str, str]):
|
3230 |
+
"""Display the stitched story result with enhanced formatting"""
|
3231 |
+
try:
|
3232 |
+
# Check if story data exists
|
3233 |
+
if not story_data or not isinstance(story_data, dict):
|
3234 |
+
st.error("ไม่พบข้อมูลเรื่องราว กรุณาลองใหม่อีกครั้ง")
|
3235 |
+
return
|
3236 |
+
|
3237 |
+
# Header
|
3238 |
+
st.markdown("### 📖 Your Polished Story | เรื่องราวฉบับสมบูรณ์")
|
3239 |
+
|
3240 |
+
# English Version
|
3241 |
+
st.subheader("🇬🇧 English Version")
|
3242 |
+
st.markdown(
|
3243 |
+
f'<div style="background-color: white; padding: 15px; border-radius: 8px; margin-bottom: 15px;">'
|
3244 |
+
f'{story_data.get("polished_english", "No content available")}'
|
3245 |
+
f'</div>',
|
3246 |
+
unsafe_allow_html=True
|
3247 |
+
)
|
3248 |
+
|
3249 |
+
# Thai Version
|
3250 |
+
st.subheader("🇹🇭 ฉบับภาษาไทย")
|
3251 |
+
st.markdown(
|
3252 |
+
f'<div style="background-color: white; padding: 15px; border-radius: 8px;">'
|
3253 |
+
f'{story_data.get("thai_translation", "ไม่พบเนื้อหา")}'
|
3254 |
+
f'</div>',
|
3255 |
+
unsafe_allow_html=True
|
3256 |
+
)
|
3257 |
+
|
3258 |
+
except Exception as e:
|
3259 |
+
logging.error(f"Error showing stitched result: {str(e)}")
|
3260 |
+
st.error("เกิดข้อผิดพลาดในการแสดงผลเรื่องราว กรุณาลองใหม่อีกครั้ง")
|
3261 |
+
|
3262 |
def show_save_dialog():
|
3263 |
"""Display save options dialog"""
|
3264 |
try:
|