Update appback.py3
Browse files- appback.py3 +194 -67
appback.py3
CHANGED
@@ -12,6 +12,7 @@ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
12 |
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
|
13 |
from datetime import datetime
|
14 |
import random
|
|
|
15 |
|
16 |
# === 2. CONFIGURATIONS ===
|
17 |
# Theme Configuration
|
@@ -393,6 +394,11 @@ achievements_list = {
|
|
393 |
# Initial CSS Setup
|
394 |
st.markdown("""
|
395 |
<style>
|
|
|
|
|
|
|
|
|
|
|
396 |
/* Base Styles */
|
397 |
@import url('https://fonts.googleapis.com/css2?family=Sarabun:wght@400;600&display=swap');
|
398 |
|
@@ -566,15 +572,26 @@ def init_theme_state():
|
|
566 |
st.session_state.theme_story_starter = None
|
567 |
|
568 |
def reset_story():
|
569 |
-
"""Reset story and related state variables"""
|
570 |
try:
|
571 |
-
# Reset story-related states
|
572 |
-
|
573 |
-
|
574 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
575 |
|
576 |
# Reset points
|
577 |
-
|
578 |
'total': 0,
|
579 |
'perfect_sentences': 0,
|
580 |
'corrections_made': 0,
|
@@ -583,7 +600,7 @@ def reset_story():
|
|
583 |
}
|
584 |
|
585 |
# Reset stats
|
586 |
-
|
587 |
'total_sentences': 0,
|
588 |
'correct_first_try': 0,
|
589 |
'accuracy_rate': 0.0,
|
@@ -594,12 +611,27 @@ def reset_story():
|
|
594 |
'session_duration': 0
|
595 |
}
|
596 |
|
597 |
-
# Reset
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
598 |
st.session_state.current_milestone = 0
|
599 |
st.session_state.next_milestone = 5
|
600 |
|
601 |
-
# Reset
|
602 |
-
st.session_state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
603 |
|
604 |
# Log reset
|
605 |
logging.info("Story state reset successfully")
|
@@ -706,6 +738,46 @@ def update_session_stats():
|
|
706 |
return False
|
707 |
|
708 |
# === 4. UTILITY FUNCTIONS ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
709 |
def generate_story_continuation(user_input: str, level: str) -> str:
|
710 |
"""Generate AI story continuation using ChatGPT"""
|
711 |
|
@@ -940,22 +1012,26 @@ def update_achievements():
|
|
940 |
"🌟 นักเขียนไร้ที่ติ" not in current_achievements):
|
941 |
current_achievements.append("🌟 นักเขียนไร้ที่ติ")
|
942 |
st.success("🎉 ได้รับความสำเร็จใหม่: นักเขียนไร้ที่ติ!")
|
|
|
943 |
|
944 |
if (len(st.session_state.stats['vocabulary_used']) >= 50 and
|
945 |
"📚 ราชาคำศัพท์" not in current_achievements):
|
946 |
current_achievements.append("📚 ราชาคำศัพท์")
|
947 |
st.success("🎉 ได้รับความสำเร็จใหม่: ราชาคำศัพท์!")
|
|
|
948 |
|
949 |
if (len(st.session_state.story) >= 10 and
|
950 |
"📖 นักแต่งนิทาน" not in current_achievements):
|
951 |
current_achievements.append("📖 นักแต่งนิทาน")
|
952 |
st.success("🎉 ได้รับความสำเร็จใหม่: นักแต่งนิทาน!")
|
|
|
953 |
|
954 |
if (st.session_state.stats['total_sentences'] >= 10 and
|
955 |
st.session_state.stats['accuracy_rate'] >= 80 and
|
956 |
"👑 ราชาความแม่นยำ" not in current_achievements):
|
957 |
current_achievements.append("👑 ราชาความแม่นยำ")
|
958 |
st.success("🎉 ได้รับความสำเร็จใหม่: ราชาความแม่นยำ!")
|
|
|
959 |
|
960 |
# บันทึกความสำเร็จ
|
961 |
st.session_state.achievements = current_achievements
|
@@ -1369,6 +1445,10 @@ def handle_theme_selection(theme: dict):
|
|
1369 |
"""Handle theme selection and initialization"""
|
1370 |
try:
|
1371 |
with st.spinner("กำลังเตรียมเรื่องราว..."):
|
|
|
|
|
|
|
|
|
1372 |
st.session_state.current_theme = theme['id']
|
1373 |
starter = generate_dynamic_story_starter(
|
1374 |
theme['id'],
|
@@ -1450,6 +1530,12 @@ def show_story():
|
|
1450 |
story_display = st.container()
|
1451 |
|
1452 |
with story_display:
|
|
|
|
|
|
|
|
|
|
|
|
|
1453 |
if not st.session_state.story:
|
1454 |
st.info("เลือกธีมเรื่องราวที่ต้องการเพื่อเริ่มต้นการผจญภัย!")
|
1455 |
return
|
@@ -2312,45 +2398,52 @@ def generate_ending_continuation(text: str, ending_type: str, remaining_sentence
|
|
2312 |
|
2313 |
def complete_story():
|
2314 |
"""Handle story completion and celebration"""
|
2315 |
-
|
2316 |
-
|
2317 |
-
|
2318 |
-
|
2319 |
-
|
2320 |
-
|
2321 |
-
|
2322 |
-
|
2323 |
-
|
2324 |
-
|
2325 |
-
|
2326 |
-
|
2327 |
-
|
2328 |
-
|
2329 |
-
|
2330 |
-
|
2331 |
-
|
2332 |
-
<
|
2333 |
-
|
2334 |
-
|
2335 |
-
|
2336 |
-
|
2337 |
-
|
2338 |
-
|
2339 |
-
<
|
2340 |
-
|
|
|
|
|
|
|
|
|
2341 |
</div>
|
2342 |
-
|
2343 |
-
|
2344 |
-
|
2345 |
-
|
2346 |
-
|
2347 |
-
|
2348 |
-
|
2349 |
-
|
2350 |
-
|
2351 |
-
|
2352 |
-
|
2353 |
-
|
|
|
|
|
|
|
2354 |
|
2355 |
def show_feedback_section():
|
2356 |
"""Display writing feedback section"""
|
@@ -2700,26 +2793,20 @@ def show_story_input():
|
|
2700 |
|
2701 |
# Submit and Clear buttons
|
2702 |
col1, col2, col3 = st.columns([3, 1, 1])
|
2703 |
-
|
2704 |
with col1:
|
2705 |
-
|
2706 |
-
|
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
|
@@ -3437,12 +3524,51 @@ def create_story_pdf():
|
|
3437 |
logging.error(f"Error creating PDF: {str(e)}")
|
3438 |
raise
|
3439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3440 |
# === 6. MAIN APPLICATION LOGIC ===
|
3441 |
def main():
|
3442 |
try:
|
3443 |
# Initialize states
|
3444 |
init_session_state()
|
3445 |
init_theme_state()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3446 |
|
3447 |
# Initialize ending system state if not exists
|
3448 |
if 'ending_mode' not in st.session_state:
|
@@ -3470,7 +3596,8 @@ def main():
|
|
3470 |
# Sidebar
|
3471 |
with st.sidebar:
|
3472 |
show_sidebar()
|
3473 |
-
|
|
|
3474 |
# Session Status Check
|
3475 |
check_session_status()
|
3476 |
|
|
|
12 |
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
|
13 |
from datetime import datetime
|
14 |
import random
|
15 |
+
from sounds import AudioManager, get_sound_commands
|
16 |
|
17 |
# === 2. CONFIGURATIONS ===
|
18 |
# Theme Configuration
|
|
|
394 |
# Initial CSS Setup
|
395 |
st.markdown("""
|
396 |
<style>
|
397 |
+
/* Hide audio elements */
|
398 |
+
.hide-tag {
|
399 |
+
display: none !important;
|
400 |
+
}
|
401 |
+
|
402 |
/* Base Styles */
|
403 |
@import url('https://fonts.googleapis.com/css2?family=Sarabun:wght@400;600&display=swap');
|
404 |
|
|
|
572 |
st.session_state.theme_story_starter = None
|
573 |
|
574 |
def reset_story():
|
575 |
+
"""Reset story and related state variables completely"""
|
576 |
try:
|
577 |
+
# Reset all story-related states
|
578 |
+
new_states = {
|
579 |
+
'story': [],
|
580 |
+
'feedback': None,
|
581 |
+
'theme_story_starter': None,
|
582 |
+
'text_input': "",
|
583 |
+
'current_theme': None,
|
584 |
+
'ending_mode': False,
|
585 |
+
'sentences_to_end': 0,
|
586 |
+
'ending_type': None,
|
587 |
+
'story_completed': False,
|
588 |
+
'stitched_story': None,
|
589 |
+
'clear_input': True,
|
590 |
+
'last_submission': None
|
591 |
+
}
|
592 |
|
593 |
# Reset points
|
594 |
+
new_points = {
|
595 |
'total': 0,
|
596 |
'perfect_sentences': 0,
|
597 |
'corrections_made': 0,
|
|
|
600 |
}
|
601 |
|
602 |
# Reset stats
|
603 |
+
new_stats = {
|
604 |
'total_sentences': 0,
|
605 |
'correct_first_try': 0,
|
606 |
'accuracy_rate': 0.0,
|
|
|
611 |
'session_duration': 0
|
612 |
}
|
613 |
|
614 |
+
# Reset all session states
|
615 |
+
for key, value in new_states.items():
|
616 |
+
st.session_state[key] = value
|
617 |
+
st.session_state.points = new_points
|
618 |
+
st.session_state.stats = new_stats
|
619 |
+
|
620 |
+
# Reset achievements and progress
|
621 |
+
st.session_state.achievements = []
|
622 |
st.session_state.current_milestone = 0
|
623 |
st.session_state.next_milestone = 5
|
624 |
|
625 |
+
# Reset UI elements
|
626 |
+
if 'story_input_area' in st.session_state:
|
627 |
+
del st.session_state.story_input_area
|
628 |
+
|
629 |
+
# Force new input field creation
|
630 |
+
st.session_state.clear_count = st.session_state.get('clear_count', 0) + 1
|
631 |
+
|
632 |
+
# Reset theme selection
|
633 |
+
st.session_state.theme_button_counter = 0
|
634 |
+
st.session_state.theme_selection_id = datetime.now().strftime('%Y%m%d%H%M%S')
|
635 |
|
636 |
# Log reset
|
637 |
logging.info("Story state reset successfully")
|
|
|
738 |
return False
|
739 |
|
740 |
# === 4. UTILITY FUNCTIONS ===
|
741 |
+
|
742 |
+
def initialize_audio():
|
743 |
+
"""Initialize audio system"""
|
744 |
+
if 'audio_manager' not in st.session_state:
|
745 |
+
audio_manager = AudioManager()
|
746 |
+
st.session_state.audio_manager = audio_manager
|
747 |
+
st.session_state.sound_commands = get_sound_commands()
|
748 |
+
|
749 |
+
# Add audio elements to the page using st.markdown with hide-tag class
|
750 |
+
st.markdown("""
|
751 |
+
<style>
|
752 |
+
.hide-tag {
|
753 |
+
display: none;
|
754 |
+
}
|
755 |
+
</style>
|
756 |
+
""", unsafe_allow_html=True)
|
757 |
+
|
758 |
+
st.markdown(
|
759 |
+
f"""
|
760 |
+
<div class="hide-tag">
|
761 |
+
{audio_manager.get_audio_html()}
|
762 |
+
</div>
|
763 |
+
""",
|
764 |
+
unsafe_allow_html=True
|
765 |
+
)
|
766 |
+
|
767 |
+
def show_audio_controls():
|
768 |
+
"""Show audio control in sidebar"""
|
769 |
+
st.sidebar.markdown("### 🔊 ตั้งค่าเสียง")
|
770 |
+
|
771 |
+
# Background music toggle
|
772 |
+
if st.sidebar.checkbox("เปิดเพลงประกอบ", value=True, key='bgm_enabled'):
|
773 |
+
st.markdown(f"<script>{st.session_state.sound_commands['bgm_play']}</script>", unsafe_allow_html=True)
|
774 |
+
else:
|
775 |
+
st.markdown(f"<script>{st.session_state.sound_commands['bgm_pause']}</script>", unsafe_allow_html=True)
|
776 |
+
|
777 |
+
# Volume control
|
778 |
+
volume = st.sidebar.slider("ระดับเสียง", 0, 100, 50, key='volume') / 100
|
779 |
+
st.markdown(f"<script>setVolume({volume});</script>", unsafe_allow_html=True)
|
780 |
+
|
781 |
def generate_story_continuation(user_input: str, level: str) -> str:
|
782 |
"""Generate AI story continuation using ChatGPT"""
|
783 |
|
|
|
1012 |
"🌟 นักเขียนไร้ที่ติ" not in current_achievements):
|
1013 |
current_achievements.append("🌟 นักเขียนไร้ที่ติ")
|
1014 |
st.success("🎉 ได้รับความสำเร็จใหม่: นักเขียนไร้ที่ติ!")
|
1015 |
+
st.markdown(f"<script>{st.session_state.sound_commands['achievement']}</script>", unsafe_allow_html=True)
|
1016 |
|
1017 |
if (len(st.session_state.stats['vocabulary_used']) >= 50 and
|
1018 |
"📚 ราชาคำศัพท์" not in current_achievements):
|
1019 |
current_achievements.append("📚 ราชาคำศัพท์")
|
1020 |
st.success("🎉 ได้รับความสำเร็จใหม่: ราชาคำศัพท์!")
|
1021 |
+
st.markdown(f"<script>{st.session_state.sound_commands['achievement']}</script>", unsafe_allow_html=True)
|
1022 |
|
1023 |
if (len(st.session_state.story) >= 10 and
|
1024 |
"📖 นักแต่งนิทาน" not in current_achievements):
|
1025 |
current_achievements.append("📖 นักแต่งนิทาน")
|
1026 |
st.success("🎉 ได้รับความสำเร็จใหม่: นักแต่งนิทาน!")
|
1027 |
+
st.markdown(f"<script>{st.session_state.sound_commands['achievement']}</script>", unsafe_allow_html=True)
|
1028 |
|
1029 |
if (st.session_state.stats['total_sentences'] >= 10 and
|
1030 |
st.session_state.stats['accuracy_rate'] >= 80 and
|
1031 |
"👑 ราชาความแม่นยำ" not in current_achievements):
|
1032 |
current_achievements.append("👑 ราชาความแม่นยำ")
|
1033 |
st.success("🎉 ได้รับความสำเร็จใหม่: ราชาความแม่นยำ!")
|
1034 |
+
st.markdown(f"<script>{st.session_state.sound_commands['achievement']}</script>", unsafe_allow_html=True)
|
1035 |
|
1036 |
# บันทึกความสำเร็จ
|
1037 |
st.session_state.achievements = current_achievements
|
|
|
1445 |
"""Handle theme selection and initialization"""
|
1446 |
try:
|
1447 |
with st.spinner("กำลังเตรียมเรื่องราว..."):
|
1448 |
+
# Reset story completely first
|
1449 |
+
reset_story()
|
1450 |
+
|
1451 |
+
# Then set new theme
|
1452 |
st.session_state.current_theme = theme['id']
|
1453 |
starter = generate_dynamic_story_starter(
|
1454 |
theme['id'],
|
|
|
1530 |
story_display = st.container()
|
1531 |
|
1532 |
with story_display:
|
1533 |
+
# Clear previous story if resetting
|
1534 |
+
if st.session_state.get('should_reset'):
|
1535 |
+
reset_story()
|
1536 |
+
st.rerun()
|
1537 |
+
return
|
1538 |
+
|
1539 |
if not st.session_state.story:
|
1540 |
st.info("เลือกธีมเรื่องราวที่ต้องการเพื่อเริ่มต้นการผจญภัย!")
|
1541 |
return
|
|
|
2398 |
|
2399 |
def complete_story():
|
2400 |
"""Handle story completion and celebration"""
|
2401 |
+
try:
|
2402 |
+
# เล่นเสียงจบเรื่อง
|
2403 |
+
st.markdown(f"<script>{st.session_state.sound_commands['complete']}</script>", unsafe_allow_html=True)
|
2404 |
+
st.balloons()
|
2405 |
+
|
2406 |
+
# Generate Story Summary
|
2407 |
+
story_summary = generate_story_summary(st.session_state.story)
|
2408 |
+
|
2409 |
+
# แสดงหน้าจบเรื่อง
|
2410 |
+
st.markdown(f"""
|
2411 |
+
<div style="
|
2412 |
+
background-color: #e8f5e9;
|
2413 |
+
padding: 20px;
|
2414 |
+
border-radius: 10px;
|
2415 |
+
text-align: center;
|
2416 |
+
margin: 20px 0;
|
2417 |
+
">
|
2418 |
+
<h2>🎉 ยินดีด้วย! คุณเขียนเรื่องราวจบสมบูรณ์แล้ว</h2>
|
2419 |
+
|
2420 |
+
<div style="margin: 20px 0;">
|
2421 |
+
<h3>📝 สรุปเรื่องราว</h3>
|
2422 |
+
<p>{story_summary}</p>
|
2423 |
+
</div>
|
2424 |
+
|
2425 |
+
<div style="margin: 20px 0;">
|
2426 |
+
<h3>🏆 ความสำเร็จ</h3>
|
2427 |
+
<p>จำนวนประโยค: {len(st.session_state.story)}</p>
|
2428 |
+
<p>คำศัพท์ที่ใช้: {len(st.session_state.stats['vocabulary_used'])}</p>
|
2429 |
+
<p>ความแม่นยำ: {st.session_state.stats['accuracy_rate']:.1f}%</p>
|
2430 |
+
</div>
|
2431 |
</div>
|
2432 |
+
""", unsafe_allow_html=True)
|
2433 |
+
|
2434 |
+
# แสดงตัวเลือกหลังจบเรื่อง
|
2435 |
+
col1, col2 = st.columns(2)
|
2436 |
+
with col1:
|
2437 |
+
if st.button("💾 บันทึกเรื่องราว", use_container_width=True):
|
2438 |
+
save_completed_story()
|
2439 |
+
with col2:
|
2440 |
+
if st.button("🔄 เริ่มเรื่องใหม่", use_container_width=True):
|
2441 |
+
reset_story()
|
2442 |
+
st.rerun()
|
2443 |
+
|
2444 |
+
except Exception as e:
|
2445 |
+
logging.error(f"Error in complete_story: {str(e)}")
|
2446 |
+
st.error("เกิดข้อผิดพลาดในการแสดงผลการจบเรื่อง")
|
2447 |
|
2448 |
def show_feedback_section():
|
2449 |
"""Display writing feedback section"""
|
|
|
2793 |
|
2794 |
# Submit and Clear buttons
|
2795 |
col1, col2, col3 = st.columns([3, 1, 1])
|
2796 |
+
|
2797 |
with col1:
|
2798 |
+
if st.button("📝 ส่งคำตอบ | Submit", use_container_width=True):
|
2799 |
+
if not text_input.strip():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2800 |
st.warning("กรุณาเขียนข้อความก่อนส่ง")
|
2801 |
+
return
|
2802 |
+
try:
|
2803 |
+
# เล่นเสียงตอนกดปุ่ม Submit
|
2804 |
+
st.markdown(f"<script>{st.session_state.sound_commands['submit']}</script>", unsafe_allow_html=True)
|
2805 |
+
with st.spinner("กำลังวิเคราะห์ประโยค..."):
|
2806 |
+
handle_story_submission(text_input.strip())
|
2807 |
+
except Exception as e:
|
2808 |
+
logging.error(f"Error submitting story: {str(e)}")
|
2809 |
+
st.error("เกิดข้อผิดพลาดในการส่งคำตอบ กรุณาลองใหม่อีกครั้ง")
|
2810 |
|
2811 |
with col2:
|
2812 |
# Clear button with unique key
|
|
|
3524 |
logging.error(f"Error creating PDF: {str(e)}")
|
3525 |
raise
|
3526 |
|
3527 |
+
def check_audio_system():
|
3528 |
+
"""Check if audio system is working properly"""
|
3529 |
+
try:
|
3530 |
+
if 'audio_manager' in st.session_state:
|
3531 |
+
# ตรวจสอบว่า audio elements ถูกโหลดสำเร็จ
|
3532 |
+
js_check = """
|
3533 |
+
<script>
|
3534 |
+
function checkAudioElements() {
|
3535 |
+
const elements = ['bgm', 'sound_submit', 'sound_achievement', 'sound_complete'];
|
3536 |
+
for (let id of elements) {
|
3537 |
+
if (!document.getElementById(id)) {
|
3538 |
+
console.error(`Audio element ${id} not found`);
|
3539 |
+
return false;
|
3540 |
+
}
|
3541 |
+
}
|
3542 |
+
return true;
|
3543 |
+
}
|
3544 |
+
window.audioSystemWorking = checkAudioElements();
|
3545 |
+
</script>
|
3546 |
+
"""
|
3547 |
+
st.markdown(js_check, unsafe_allow_html=True)
|
3548 |
+
return True
|
3549 |
+
except Exception as e:
|
3550 |
+
logging.error(f"Error checking audio system: {str(e)}")
|
3551 |
+
return False
|
3552 |
+
|
3553 |
# === 6. MAIN APPLICATION LOGIC ===
|
3554 |
def main():
|
3555 |
try:
|
3556 |
# Initialize states
|
3557 |
init_session_state()
|
3558 |
init_theme_state()
|
3559 |
+
|
3560 |
+
# Check if reset is needed
|
3561 |
+
if st.session_state.get('should_reset'):
|
3562 |
+
reset_story()
|
3563 |
+
st.rerun()
|
3564 |
+
return
|
3565 |
+
|
3566 |
+
# Initialize audio system
|
3567 |
+
initialize_audio()
|
3568 |
+
|
3569 |
+
# Check audio system
|
3570 |
+
if not check_audio_system():
|
3571 |
+
st.warning("ระบบเสียงอาจทำงานไม่สมบูรณ์ แต่คุณยังสามารถใช้งานแอพได้")
|
3572 |
|
3573 |
# Initialize ending system state if not exists
|
3574 |
if 'ending_mode' not in st.session_state:
|
|
|
3596 |
# Sidebar
|
3597 |
with st.sidebar:
|
3598 |
show_sidebar()
|
3599 |
+
show_audio_controls()
|
3600 |
+
|
3601 |
# Session Status Check
|
3602 |
check_session_status()
|
3603 |
|