Rathapoom commited on
Commit
174dccb
·
verified ·
1 Parent(s): cbbf32f

Update appback.py3

Browse files
Files changed (1) hide show
  1. 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 clear_input flag if not exists
2288
  if 'clear_input' not in st.session_state:
2289
  st.session_state.clear_input = False
2290
-
2291
- # Default value for text input
2292
- default_value = "" if st.session_state.clear_input else st.session_state.get('text_input', "")
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.get('text_input', ""),
2307
  height=100,
2308
- key="story_input_area",
2309
  help="พิมพ์ประโยคภาษาอังกฤษเพื่อต่อเรื่อง",
2310
  label_visibility="collapsed"
2311
  )
2312
 
2313
- # Save current input to session state
2314
  st.session_state.text_input = text_input
2315
 
2316
- # Submit button with character count
2317
- col1, col2 = st.columns([3, 1])
 
2318
  with col1:
2319
- if st.button("📝 ส่งคำตอบ | Submit", use_container_width=True):
2320
- if not text_input.strip():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 and processing"""
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
- # Set flag to clear input on next rerun
2414
- st.session_state.clear_input = True
 
 
 
 
 
 
 
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
- st.markdown("""
 
 
 
 
 
 
 
 
 
 
 
 
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
- เรื่องราวของคุณจบลงด้วย: {st.session_state.ending_type}
2564
  </p>
2565
  </div>
2566
  """, unsafe_allow_html=True)
2567
 
2568
  # Show statistics
2569
- metrics_col1, metrics_col2 = st.columns(2)
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
- with metrics_col2:
2583
- st.metric(
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
- # Save options
2595
- st.markdown("### 🎯 ต้องการทำอะไรต่อ?")
2596
- save_completed_story()
2597
-
2598
- # New story option
2599
- if st.button("🔄 เริ่มเรื่องใหม่",
2600
- key="new_story_button",
2601
  use_container_width=True):
2602
- if st.checkbox("✅ ยืนยันการเริ่มใหม่", key="confirm_reset"):
2603
- st.warning("การเริ่มใหม่จะลบเรื่องราวปัจจุบันทั้งหมด")
2604
- if st.button("🔄 ยืนยันการเริ่มใหม่",
2605
- key="final_confirm_reset",
2606
- use_container_width=True):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: