Update app.py
Browse files
app.py
CHANGED
@@ -1445,7 +1445,7 @@ def show_story():
|
|
1445 |
for idx, entry in enumerate(st.session_state.story):
|
1446 |
if entry['role'] == 'AI':
|
1447 |
if entry.get('is_starter'):
|
1448 |
-
# Story Starter
|
1449 |
st.markdown(f"""
|
1450 |
<div style="
|
1451 |
background-color: #f0f7ff;
|
@@ -1466,8 +1466,50 @@ def show_story():
|
|
1466 |
</div>
|
1467 |
</div>
|
1468 |
""", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1469 |
else:
|
1470 |
-
# AI Response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1471 |
st.markdown(f"""
|
1472 |
<div style="
|
1473 |
background-color: #f8f9fa;
|
@@ -1476,18 +1518,36 @@ def show_story():
|
|
1476 |
margin: 8px 0;
|
1477 |
border-left: 4px solid #4caf50;
|
1478 |
">
|
1479 |
-
<div style="color: #2e7d32;">
|
1480 |
-
|
|
|
1481 |
</div>
|
1482 |
</div>
|
1483 |
""", unsafe_allow_html=True)
|
1484 |
|
1485 |
elif entry['role'] == 'You':
|
1486 |
-
# User Entry
|
1487 |
status_icon = "✅" if entry.get('is_correct') else "✍️"
|
1488 |
bg_color = "#e8f5e9" if entry.get('is_correct') else "#fff"
|
1489 |
border_color = "#4caf50" if entry.get('is_correct') else "#1e88e5"
|
1490 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1491 |
st.markdown(f"""
|
1492 |
<div style="
|
1493 |
background-color: {bg_color};
|
@@ -1496,12 +1556,33 @@ def show_story():
|
|
1496 |
margin: 8px 0;
|
1497 |
border-left: 4px solid {border_color};
|
1498 |
">
|
1499 |
-
<div style="color: #333;">
|
1500 |
-
|
|
|
1501 |
</div>
|
1502 |
{f'<div style="font-size: 0.9em; color: #666; margin-top: 5px;">{entry.get("feedback", "")}</div>' if entry.get('feedback') else ''}
|
1503 |
</div>
|
1504 |
""", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1505 |
|
1506 |
def show_story_progress():
|
1507 |
"""Display story progress metrics"""
|
@@ -1552,32 +1633,146 @@ def show_story_ending_options():
|
|
1552 |
|
1553 |
def handle_ending_mode(text: str):
|
1554 |
"""Handle story submission during ending mode"""
|
1555 |
-
|
1556 |
-
|
1557 |
-
|
1558 |
-
|
1559 |
-
|
1560 |
-
|
1561 |
-
|
1562 |
-
|
1563 |
-
|
1564 |
-
|
1565 |
-
"
|
1566 |
-
|
1567 |
-
|
1568 |
-
|
1569 |
-
|
1570 |
-
|
1571 |
-
|
1572 |
-
|
1573 |
-
|
1574 |
-
|
1575 |
-
|
1576 |
-
|
1577 |
-
|
1578 |
-
|
1579 |
-
|
1580 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1581 |
|
1582 |
def generate_ending_continuation(text: str, ending_type: str, remaining_sentences: int) -> str:
|
1583 |
"""Generate AI continuation focusing on story conclusion"""
|
@@ -2162,9 +2357,14 @@ def show_main_interface():
|
|
2162 |
""", unsafe_allow_html=True)
|
2163 |
|
2164 |
show_story()
|
2165 |
-
|
2166 |
-
if
|
|
|
2167 |
show_story_input()
|
|
|
|
|
|
|
|
|
2168 |
|
2169 |
with col2:
|
2170 |
# Feedback section
|
|
|
1445 |
for idx, entry in enumerate(st.session_state.story):
|
1446 |
if entry['role'] == 'AI':
|
1447 |
if entry.get('is_starter'):
|
1448 |
+
# Story Starter (คงเดิม)
|
1449 |
st.markdown(f"""
|
1450 |
<div style="
|
1451 |
background-color: #f0f7ff;
|
|
|
1466 |
</div>
|
1467 |
</div>
|
1468 |
""", unsafe_allow_html=True)
|
1469 |
+
elif entry.get('is_final'): # เพิ่มเงื่อนไขสำหรับประโยคจบ
|
1470 |
+
# Final Ending Display
|
1471 |
+
st.markdown(f"""
|
1472 |
+
<div style="
|
1473 |
+
background-color: #e8f5e9;
|
1474 |
+
padding: 25px;
|
1475 |
+
border-radius: 10px;
|
1476 |
+
margin: 15px 0;
|
1477 |
+
border: 2px solid #4caf50;
|
1478 |
+
text-align: center;
|
1479 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
1480 |
+
">
|
1481 |
+
<div style="font-size: 1.3em; color: #2e7d32; margin-bottom: 15px;">
|
1482 |
+
🎭 จบเรื่อง | The End
|
1483 |
+
</div>
|
1484 |
+
<div style="color: #333; font-size: 1.1em; font-style: italic;">
|
1485 |
+
{entry['content']}
|
1486 |
+
</div>
|
1487 |
+
<div style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #a5d6a7;">
|
1488 |
+
<span style="color: #666;">
|
1489 |
+
✨ รูปแบบการจบ: {st.session_state.ending_type}
|
1490 |
+
</span>
|
1491 |
+
</div>
|
1492 |
+
</div>
|
1493 |
+
""", unsafe_allow_html=True)
|
1494 |
else:
|
1495 |
+
# Regular AI Response with ending mode indicator
|
1496 |
+
ending_badge = ""
|
1497 |
+
if st.session_state.get('ending_mode'):
|
1498 |
+
remaining = st.session_state.sentences_to_end
|
1499 |
+
ending_badge = f"""
|
1500 |
+
<div style="
|
1501 |
+
display: inline-block;
|
1502 |
+
background-color: #fff3e0;
|
1503 |
+
padding: 3px 8px;
|
1504 |
+
border-radius: 12px;
|
1505 |
+
font-size: 0.8em;
|
1506 |
+
color: #f57c00;
|
1507 |
+
margin-left: 10px;
|
1508 |
+
">
|
1509 |
+
🎭 Ending: {remaining} sentences left
|
1510 |
+
</div>
|
1511 |
+
"""
|
1512 |
+
|
1513 |
st.markdown(f"""
|
1514 |
<div style="
|
1515 |
background-color: #f8f9fa;
|
|
|
1518 |
margin: 8px 0;
|
1519 |
border-left: 4px solid #4caf50;
|
1520 |
">
|
1521 |
+
<div style="color: #2e7d32; display: flex; align-items: center;">
|
1522 |
+
<span>🤖 AI: {entry['content']}</span>
|
1523 |
+
{ending_badge}
|
1524 |
</div>
|
1525 |
</div>
|
1526 |
""", unsafe_allow_html=True)
|
1527 |
|
1528 |
elif entry['role'] == 'You':
|
1529 |
+
# User Entry with ending mode indicator
|
1530 |
status_icon = "✅" if entry.get('is_correct') else "✍️"
|
1531 |
bg_color = "#e8f5e9" if entry.get('is_correct') else "#fff"
|
1532 |
border_color = "#4caf50" if entry.get('is_correct') else "#1e88e5"
|
1533 |
|
1534 |
+
ending_badge = ""
|
1535 |
+
if st.session_state.get('ending_mode'):
|
1536 |
+
remaining = st.session_state.sentences_to_end
|
1537 |
+
ending_badge = f"""
|
1538 |
+
<div style="
|
1539 |
+
display: inline-block;
|
1540 |
+
background-color: #fff3e0;
|
1541 |
+
padding: 3px 8px;
|
1542 |
+
border-radius: 12px;
|
1543 |
+
font-size: 0.8em;
|
1544 |
+
color: #f57c00;
|
1545 |
+
margin-left: 10px;
|
1546 |
+
">
|
1547 |
+
🎭 Ending: {remaining} sentences left
|
1548 |
+
</div>
|
1549 |
+
"""
|
1550 |
+
|
1551 |
st.markdown(f"""
|
1552 |
<div style="
|
1553 |
background-color: {bg_color};
|
|
|
1556 |
margin: 8px 0;
|
1557 |
border-left: 4px solid {border_color};
|
1558 |
">
|
1559 |
+
<div style="color: #333; display: flex; align-items: center;">
|
1560 |
+
<span>👤 You: {status_icon} {entry['content']}</span>
|
1561 |
+
{ending_badge}
|
1562 |
</div>
|
1563 |
{f'<div style="font-size: 0.9em; color: #666; margin-top: 5px;">{entry.get("feedback", "")}</div>' if entry.get('feedback') else ''}
|
1564 |
</div>
|
1565 |
""", unsafe_allow_html=True)
|
1566 |
+
|
1567 |
+
# Show completion message if story is done
|
1568 |
+
if st.session_state.get('story_completed'):
|
1569 |
+
st.markdown("""
|
1570 |
+
<div style="
|
1571 |
+
background-color: #f3e5f5;
|
1572 |
+
padding: 20px;
|
1573 |
+
border-radius: 10px;
|
1574 |
+
margin: 20px 0;
|
1575 |
+
text-align: center;
|
1576 |
+
border: 2px dashed #9c27b0;
|
1577 |
+
">
|
1578 |
+
<h2 style="color: #9c27b0; margin-bottom: 10px;">
|
1579 |
+
🎉 ยินดีด้วย! คุณเขียนเรื่องราวจบสมบูรณ์แล้ว
|
1580 |
+
</h2>
|
1581 |
+
<p style="color: #666;">
|
1582 |
+
คุณสามารถบันทึกเรื่องราวหรือเริ่มเรื่องใหม่ได้
|
1583 |
+
</p>
|
1584 |
+
</div>
|
1585 |
+
""", unsafe_allow_html=True)
|
1586 |
|
1587 |
def show_story_progress():
|
1588 |
"""Display story progress metrics"""
|
|
|
1633 |
|
1634 |
def handle_ending_mode(text: str):
|
1635 |
"""Handle story submission during ending mode"""
|
1636 |
+
try:
|
1637 |
+
remaining = st.session_state.sentences_to_end
|
1638 |
+
|
1639 |
+
# Show remaining sentences warning
|
1640 |
+
st.warning(f"""
|
1641 |
+
🎭 Ending Mode Active:
|
1642 |
+
- Remaining sentences: {remaining}
|
1643 |
+
- Ending Type: {st.session_state.ending_type}
|
1644 |
+
|
1645 |
+
Try to work towards completing your story!
|
1646 |
+
""")
|
1647 |
+
|
1648 |
+
# Get specialized ending feedback
|
1649 |
+
feedback_data = provide_feedback(text, st.session_state.level)
|
1650 |
+
st.session_state.feedback = feedback_data
|
1651 |
+
is_correct = not feedback_data.get('has_errors', False)
|
1652 |
+
|
1653 |
+
# Add user's sentence
|
1654 |
+
st.session_state.story.append({
|
1655 |
+
"role": "You",
|
1656 |
+
"content": text,
|
1657 |
+
"is_corrected": False,
|
1658 |
+
"is_correct": is_correct,
|
1659 |
+
"timestamp": datetime.now().isoformat()
|
1660 |
+
})
|
1661 |
+
|
1662 |
+
# Update stats and achievements
|
1663 |
+
words = set(text.lower().split())
|
1664 |
+
st.session_state.stats['vocabulary_used'].update(words)
|
1665 |
+
update_points(is_correct)
|
1666 |
+
update_achievements()
|
1667 |
+
|
1668 |
+
# Generate AI's ending continuation
|
1669 |
+
if remaining > 1: # Still have sentences remaining
|
1670 |
+
ai_response = generate_ending_continuation(
|
1671 |
+
text,
|
1672 |
+
ending_type=st.session_state.ending_type,
|
1673 |
+
remaining_sentences=remaining - 1
|
1674 |
+
)
|
1675 |
+
|
1676 |
+
st.session_state.story.append({
|
1677 |
+
"role": "AI",
|
1678 |
+
"content": ai_response,
|
1679 |
+
"timestamp": datetime.now().isoformat()
|
1680 |
+
})
|
1681 |
+
|
1682 |
+
# Decrease remaining sentences count
|
1683 |
+
st.session_state.sentences_to_end = remaining - 2 # -2 because both user and AI added sentences
|
1684 |
+
|
1685 |
+
else: # Last sentence - complete the story
|
1686 |
+
final_response = generate_final_ending(
|
1687 |
+
st.session_state.story,
|
1688 |
+
st.session_state.ending_type
|
1689 |
+
)
|
1690 |
+
|
1691 |
+
st.session_state.story.append({
|
1692 |
+
"role": "AI",
|
1693 |
+
"content": final_response,
|
1694 |
+
"timestamp": datetime.now().isoformat(),
|
1695 |
+
"is_final": True
|
1696 |
+
})
|
1697 |
+
|
1698 |
+
# Mark story as complete
|
1699 |
+
st.session_state.story_completed = True
|
1700 |
+
complete_story()
|
1701 |
+
|
1702 |
+
# Update session stats
|
1703 |
+
update_session_stats()
|
1704 |
+
|
1705 |
+
# Clear input and rerun
|
1706 |
+
st.session_state.story_input_area = ""
|
1707 |
+
st.rerun()
|
1708 |
+
|
1709 |
+
except Exception as e:
|
1710 |
+
logging.error(f"Error in ending mode: {str(e)}")
|
1711 |
+
st.error("เกิดข้อผิดพลาดในโหมดจบเรื่อง กรุณาลองใหม่อีกครั้ง")
|
1712 |
+
|
1713 |
+
def generate_final_ending(story: List[dict], ending_type: str) -> str:
|
1714 |
+
"""Generate the final ending sentence based on the story and chosen ending type"""
|
1715 |
+
try:
|
1716 |
+
# Create a comprehensive prompt for the final ending
|
1717 |
+
story_summary = " ".join([entry['content'] for entry in story[-5:]]) # Last 5 sentences
|
1718 |
+
|
1719 |
+
ending_prompts = {
|
1720 |
+
"Happy Ending": """
|
1721 |
+
Create a final happy ending sentence that:
|
1722 |
+
- Brings joy and satisfaction
|
1723 |
+
- Resolves the main story elements
|
1724 |
+
- Ends on a positive note
|
1725 |
+
Maximum 2 sentences.
|
1726 |
+
""",
|
1727 |
+
"Mysterious Ending": """
|
1728 |
+
Create a final mysterious ending sentence that:
|
1729 |
+
- Leaves an intriguing question
|
1730 |
+
- Creates a sense of wonder
|
1731 |
+
- Maintains some mystery
|
1732 |
+
Maximum 2 sentences.
|
1733 |
+
""",
|
1734 |
+
"Lesson Learned": """
|
1735 |
+
Create a final sentence that:
|
1736 |
+
- Shows what was learned
|
1737 |
+
- Provides a moral lesson
|
1738 |
+
- Connects to the story's events
|
1739 |
+
Maximum 2 sentences.
|
1740 |
+
""",
|
1741 |
+
"Surprise Ending": """
|
1742 |
+
Create a final twist ending that:
|
1743 |
+
- Provides an unexpected but logical conclusion
|
1744 |
+
- Connects to previous story elements
|
1745 |
+
- Creates a satisfying surprise
|
1746 |
+
Maximum 2 sentences.
|
1747 |
+
"""
|
1748 |
+
}
|
1749 |
+
|
1750 |
+
response = client.chat.completions.create(
|
1751 |
+
model="gpt-4",
|
1752 |
+
messages=[
|
1753 |
+
{
|
1754 |
+
"role": "system",
|
1755 |
+
"content": f"""
|
1756 |
+
You are a master storyteller creating the final ending.
|
1757 |
+
{ending_prompts[ending_type]}
|
1758 |
+
This must be the absolute final sentence(s) of the story.
|
1759 |
+
Make it conclusive and satisfying.
|
1760 |
+
"""
|
1761 |
+
},
|
1762 |
+
{
|
1763 |
+
"role": "user",
|
1764 |
+
"content": f"Story context:\n{story_summary}\n\nCreate the final ending:"
|
1765 |
+
}
|
1766 |
+
],
|
1767 |
+
max_tokens=100,
|
1768 |
+
temperature=0.7
|
1769 |
+
)
|
1770 |
+
|
1771 |
+
return response.choices[0].message.content.strip()
|
1772 |
+
|
1773 |
+
except Exception as e:
|
1774 |
+
logging.error(f"Error generating final ending: {str(e)}")
|
1775 |
+
return "And so, the story came to an end."
|
1776 |
|
1777 |
def generate_ending_continuation(text: str, ending_type: str, remaining_sentences: int) -> str:
|
1778 |
"""Generate AI continuation focusing on story conclusion"""
|
|
|
2357 |
""", unsafe_allow_html=True)
|
2358 |
|
2359 |
show_story()
|
2360 |
+
|
2361 |
+
# Only show input if story is not completed
|
2362 |
+
if st.session_state.story and not st.session_state.get('story_completed'):
|
2363 |
show_story_input()
|
2364 |
+
|
2365 |
+
# Show completion options if story is done
|
2366 |
+
if st.session_state.get('story_completed'):
|
2367 |
+
show_completion_options()
|
2368 |
|
2369 |
with col2:
|
2370 |
# Feedback section
|