diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,337 +1,54 @@ +# === 1. IMPORTS & SETUP === import streamlit as st import json import datetime +import logging from openai import OpenAI -from typing import Dict, List, Set +from typing import Dict, List, Set, Tuple import io from reportlab.lib import colors from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle -from reportlab.lib.units import inch -from reportlab.pdfgen import canvas -from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image -from reportlab.pdfbase import pdfmetrics -from reportlab.pdfbase.ttfonts import TTFont +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer from datetime import datetime -from typing import Dict, List, Optional, Tuple import random -# Reset counter when page reloads -if 'theme_button_counter' in st.session_state: - st.session_state.theme_button_counter = 0 - -# Theme Configuration -story_themes = { - 'fantasy': { - 'id': 'fantasy', - 'icon': '🏰', - 'name_en': 'Fantasy & Magic', - 'name_th': 'แฟนตาซีและเวทมนตร์', - 'description_th': 'ผจญภัยในโลกแห่งเวทมนตร์และจินตนาการ', - 'description_en': 'Adventure in a world of magic and imagination', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['dragon', 'magic', 'wand', 'spell', 'wizard', 'fairy', 'castle', 'king', 'queen'], - 'Intermediate': ['potion', 'enchanted', 'castle', 'creature', 'power', 'scroll', 'portal', 'magical'], - 'Advanced': ['sorcery', 'mystical', 'enchantment', 'prophecy', 'ancient', 'legendary', 'mythical'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'วันหนึ่งฉันเจอไม้วิเศษในสวน...', 'en': 'One day, I found a magic wand in the garden...'}, - {'th': 'มังกรน้อยกำลังมองหาเพื่อน...', 'en': 'The little dragon was looking for a friend...'}, - {'th': 'เจ้าหญิงน้อยมีความลับวิเศษ...', 'en': 'The little princess had a magical secret...'} - ], - 'Intermediate': [ - {'th': 'ในปราสาทเก่าแก่มีประตูลึกลับ...', 'en': 'In the ancient castle, there was a mysterious door...'}, - {'th': 'เมื่อน้ำยาวิเศษเริ่มส่องแสง...', 'en': 'When the magic potion started to glow...'}, - {'th': 'หนังสือเวทมนตร์เล่มนั้นเปิดออกเอง...', 'en': 'The spellbook opened by itself...'} - ], - 'Advanced': [ - {'th': 'คำทำนายโบราณกล่าวถึงผู้วิเศษที่จะมา...', 'en': 'The ancient prophecy spoke of a wizard who would come...'}, - {'th': 'ในโลกที่เวทมนตร์กำลังจะสูญหาย...', 'en': 'In a world where magic was fading away...'}, - {'th': 'ณ จุดบรรจบของดวงดาวทั้งห้า...', 'en': 'At the convergence of the five stars...'} - ] - }, - 'background_color': '#E8F3FF', - 'accent_color': '#1E88E5' - }, - 'nature': { - 'id': 'nature', - 'icon': '🌳', - 'name_en': 'Nature & Animals', - 'name_th': 'ธรรมชาติและสัตว์โลก', - 'description_th': 'เรื่องราวของสัตว์น้อยใหญ่และธรรมชาติอันงดงาม', - 'description_en': 'Stories of animals and beautiful nature', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['tree', 'bird', 'flower', 'cat', 'dog', 'garden', 'rabbit', 'butterfly', 'sun'], - 'Intermediate': ['forest', 'river', 'mountain', 'wildlife', 'season', 'weather', 'rainbow', 'stream'], - 'Advanced': ['ecosystem', 'habitat', 'wilderness', 'environment', 'conservation', 'migration', 'climate'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'แมวน้อยเจอนกในสวน...', 'en': 'The little cat found a bird in the garden...'}, - {'th': 'ดอกไม้สวยกำลังเบ่งบาน...', 'en': 'The beautiful flower was blooming...'}, - {'th': 'กระต่ายน้อยหลงทางในสวน...', 'en': 'The little rabbit got lost in the garden...'} - ], - 'Intermediate': [ - {'th': 'ในป่าใหญ่มีเสียงลึกลับ...', 'en': 'In the big forest, there was a mysterious sound...'}, - {'th': 'แม่น้ำสายนี้มีความลับ...', 'en': 'This river had a secret...'}, - {'th': 'สายรุ้งพาดผ่านภูเขา...', 'en': 'A rainbow stretched across the mountain...'} - ], - 'Advanced': [ - {'th': 'ฝูงนกกำลังอพยพย้ายถิ่น...', 'en': 'The birds were migrating...'}, - {'th': 'ป่าฝนกำลังเปลี่ยนแปลง...', 'en': 'The rainforest was changing...'}, - {'th': 'ความลับของระบบนิเวศ...', 'en': 'The secret of the ecosystem...'} - ] - }, - 'background_color': '#F1F8E9', - 'accent_color': '#4CAF50' - }, - 'space': { - 'id': 'space', - 'icon': '🚀', - 'name_en': 'Space Adventure', - 'name_th': 'ผจญภัยในอวกาศ', - 'description_th': 'เรื่องราวการสำรวจอวกาศและดวงดาวอันน่าตื่นเต้น', - 'description_en': 'Exciting stories of space exploration and celestial discoveries', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['star', 'moon', 'planet', 'sun', 'rocket', 'alien', 'space', 'light'], - 'Intermediate': ['astronaut', 'spacecraft', 'galaxy', 'meteor', 'satellite', 'orbit', 'comet'], - 'Advanced': ['constellation', 'nebula', 'astronomy', 'telescope', 'exploration', 'discovery'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'จรวดลำน้อยพร้อมบินแล้ว...', 'en': 'The little rocket was ready to fly...'}, - {'th': 'ดาวดวงน้อยเปล่งแสงวิบวับ...', 'en': 'The little star twinkled brightly...'}, - {'th': 'มนุษย์ต่างดาวที่เป็นมิตร...', 'en': 'The friendly alien...'} - ], - 'Intermediate': [ - {'th': 'นักบินอวกาศพบสิ่งประหลาด...', 'en': 'The astronaut found something strange...'}, - {'th': 'ดาวเคราะห์ดวงใหม่ถูกค้นพบ...', 'en': 'A new planet was discovered...'}, - {'th': 'สถานีอวกาศส่งสัญญาณลึกลับ...', 'en': 'The space station sent a mysterious signal...'} - ], - 'Advanced': [ - {'th': 'การสำรวจดาวหางนำไปสู่การค้นพบ...', 'en': 'The comet exploration led to a discovery...'}, - {'th': 'กาแล็กซี่ที่ไม่มีใครเคยเห็น...', 'en': 'An unknown galaxy appeared...'}, - {'th': 'ความลับของหลุมดำ...', 'en': 'The secret of the black hole...'} - ] - }, - 'background_color': '#E1F5FE', - 'accent_color': '#0288D1' - }, - 'adventure': { - 'id': 'adventure', - 'icon': '🗺️', - 'name_en': 'Adventure & Quest', - 'name_th': 'การผจญภัยและการค้นหา', - 'description_th': 'ออกผจญภัยค้นหาสมบัติและความลับต่างๆ', - 'description_en': 'Embark on quests to find treasures and secrets', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['map', 'treasure', 'cave', 'island', 'path', 'boat', 'key', 'chest'], - 'Intermediate': ['compass', 'adventure', 'journey', 'mystery', 'explore', 'discover', 'quest'], - 'Advanced': ['expedition', 'archaeology', 'artifact', 'ancient', 'mysterious', 'discovery'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'แผนที่เก่าแก่ชิ้นหนึ่ง...', 'en': 'An old map showed...'}, - {'th': 'บนเกาะเล็กๆ มีสมบัติ...', 'en': 'On a small island, there was a treasure...'}, - {'th': 'ถ้ำลึกลับถูกค้นพบ...', 'en': 'A mysterious cave was found...'} - ], - 'Intermediate': [ - {'th': 'เข็มทิศวิเศษชี้ไปที่...', 'en': 'The magical compass pointed to...'}, - {'th': 'การเดินทางเริ่มต้นที่...', 'en': 'The journey began at...'}, - {'th': 'ความลับของวัตถุโบราณ...', 'en': 'The secret of the ancient artifact...'} - ], - 'Advanced': [ - {'th': 'การสำรวจซากปรักห���กพังนำไปสู่...', 'en': 'The ruins exploration led to...'}, - {'th': 'นักโบราณคดีค้นพบ...', 'en': 'The archaeologist discovered...'}, - {'th': 'ความลับของอารยธรรมโบราณ...', 'en': 'The secret of the ancient civilization...'} - ] - }, - 'background_color': '#FFF3E0', - 'accent_color': '#FF9800' - }, - 'school': { - 'id': 'school', - 'icon': '🏫', - 'name_en': 'School & Friends', - 'name_th': 'โรงเรียนและเพื่อน', - 'description_th': 'เรื่องราวสนุกๆ ในโรงเรียนกับเพื่อนๆ', - 'description_en': 'Fun stories about school life and friendship', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['friend', 'teacher', 'book', 'classroom', 'pencil', 'desk', 'lunch', 'play'], - 'Intermediate': ['homework', 'project', 'library', 'playground', 'student', 'lesson', 'study'], - 'Advanced': ['presentation', 'experiment', 'knowledge', 'research', 'collaboration', 'achievement'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'วันแรกในห้องเรียนใหม่...', 'en': 'First day in the new classroom...'}, - {'th': 'เพื่อนใหม่ในโรงเรียน...', 'en': 'A new friend at school...'}, - {'th': 'ที่โต๊ะอาหารกลางวัน...', 'en': 'At the lunch table...'} - ], - 'Intermediate': [ - {'th': 'โครงงานพิเศษของห้องเรา...', 'en': 'Our class special project...'}, - {'th': 'ในห้องสมุดมีความลับ...', 'en': 'The library had a secret...'}, - {'th': 'การทดลองวิทยาศาสตร์ครั้งนี้...', 'en': 'This science experiment...'} - ], - 'Advanced': [ - {'th': 'การนำเสนอครั้งสำคัญ...', 'en': 'The important presentation...'}, - {'th': 'การค้นคว้าพิเศษนำไปสู่...', 'en': 'The special research led to...'}, - {'th': 'โครงการความร่วมมือระหว่างห้อง...', 'en': 'The inter-class collaboration project...'} - ] - }, - 'background_color': '#F3E5F5', - 'accent_color': '#9C27B0' - }, - 'superhero': { - 'id': 'superhero', - 'icon': '🦸', - 'name_en': 'Superheroes', - 'name_th': 'ซูเปอร์ฮีโร่', - 'description_th': 'เรื่องราวของฮีโร่ตัวน้อยผู้ช่วยเหลือผู้อื่น', - 'description_en': 'Stories of young heroes helping others', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['hero', 'help', 'save', 'power', 'mask', 'cape', 'fly', 'strong'], - 'Intermediate': ['rescue', 'protect', 'brave', 'courage', 'mission', 'team', 'secret', 'mighty'], - 'Advanced': ['superhero', 'extraordinary', 'responsibility', 'leadership', 'determination', 'justice'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'ฮีโร่น้อยคนใหม่ของเมือง...', 'en': 'The city\'s new young hero...'}, - {'th': 'พลังพิเศษของฉันทำให้...', 'en': 'My special power made me...'}, - {'th': 'เมื่อต้องช่วยเหลือแมวตัวน้อย...', 'en': 'When I had to save a little cat...'} - ], - 'Intermediate': [ - {'th': 'ภารกิจลับของทีมฮีโร่...', 'en': 'The hero team\'s secret mission...'}, - {'th': 'พลังใหม่ที่น่าประหลาดใจ...', 'en': 'A surprising new power...'}, - {'th': 'การช่วยเหลือครั้งสำคัญ...', 'en': 'An important rescue mission...'} - ], - 'Advanced': [ - {'th': 'ความรับผิดชอบของการเป็นฮีโร่...', 'en': 'The responsibility of being a hero...'}, - {'th': 'เมื่อเมืองต้องการฮีโร่...', 'en': 'When the city needed a hero...'}, - {'th': 'การต่อสู้เพื่อความยุติธรรม...', 'en': 'Fighting for justice...'} - ] - }, - 'background_color': '#FFE0B2', - 'accent_color': '#F57C00' - }, - 'mystery': { - 'id': 'mystery', - 'icon': '🔍', - 'name_en': 'Mystery & Detective', - 'name_th': 'ไขปริศนาและนักสืบ', - 'description_th': 'สืบสวนปริศนาและไขความลับต่างๆ', - 'description_en': 'Solve mysteries and uncover secrets', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['clue', 'find', 'look', 'search', 'mystery', 'hidden', 'secret', 'detective'], - 'Intermediate': ['investigate', 'evidence', 'puzzle', 'solve', 'discover', 'suspicious', 'case'], - 'Advanced': ['investigation', 'deduction', 'enigma', 'cryptic', 'mysterious', 'revelation'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'มีรอยปริศนาในสวน...', 'en': 'There were mysterious footprints in the garden...'}, - {'th': 'จดหมายลึกลับถูกส่งมา...', 'en': 'A mysterious letter arrived...'}, - {'th': 'ของเล่นหายไปอย่างลึกลับ...', 'en': 'The toy mysteriously disappeared...'} - ], - 'Intermediate': [ - {'th': 'เบาะแสชิ้นแรกนำไปสู่...', 'en': 'The first clue led to...'}, - {'th': 'ความลับในห้องเก่า...', 'en': 'The secret in the old room...'}, - {'th': 'รหัสลับถูกค้นพบ...', 'en': 'A secret code was found...'} - ], - 'Advanced': [ - {'th': 'คดีปริศนาที่ยากที่สุด...', 'en': 'The most challenging mystery case...'}, - {'th': 'ความลับที่ซ่อนอยู่มานาน...', 'en': 'A long-hidden secret...'}, - {'th': 'การสืบสวนนำไปสู่การค้นพบ...', 'en': 'The investigation led to a discovery...'} - ] - }, - 'background_color': '#E0E0E0', - 'accent_color': '#616161' - }, - 'science': { - 'id': 'science', - 'icon': '🔬', - 'name_en': 'Science & Discovery', - 'name_th': 'วิทยาศาสตร์และการค้นพบ', - 'description_th': 'การทดลองและค้นพบทางวิทยาศาสตร์ที่น่าตื่นเต้น', - 'description_en': 'Exciting scientific experiments and discoveries', - 'level_range': ['Beginner', 'Intermediate', 'Advanced'], - 'vocabulary': { - 'Beginner': ['experiment', 'science', 'lab', 'test', 'mix', 'observe', 'change', 'result'], - 'Intermediate': ['hypothesis', 'research', 'discovery', 'invention', 'laboratory', 'scientist'], - 'Advanced': ['innovation', 'technological', 'breakthrough', 'analysis', 'investigation'] - }, - 'story_starters': { - 'Beginner': [ - {'th': 'การทดลองง่ายๆ เริ่มต้นด้วย...', 'en': 'The simple experiment started with...'}, - {'th': 'ในห้องทดลองมีสิ่งมหัศจรรย์...', 'en': 'In the lab, there was something amazing...'}, - {'th': 'เมื่อผสมสองสิ่งเข้าด้วยกัน...', 'en': 'When mixing the two things together...'} - ], - 'Intermediate': [ - {'th': 'การค้นพบที่น่าประหลาดใจ...', 'en': 'A surprising discovery...'}, - {'th': 'สิ่งประดิษฐ์ใหม่ทำให้...', 'en': 'The new invention made...'}, - {'th': 'การทดลองที่ไม่คาดคิด...', 'en': 'An unexpected experiment...'} - ], - 'Advanced': [ - {'th': 'นวัตกรรมที่จะเปลี่ยนโลก...', 'en': 'Innovation that would change the world...'}, - {'th': 'การค้นพบทางวิทยาศาสตร์ครั้งสำคัญ...', 'en': 'An important scientific discovery...'}, - {'th': 'เทคโนโลยีใหม่ที่น่าทึ่ง...', 'en': 'Amazing new technology...'} - ] - }, - 'background_color': '#E8EAF6', - 'accent_color': '#3F51B5' - } -} - -# ระบบ Achievements -achievements_list = { - 'perfect_writer': { - 'name': '🌟 นักเขียนไร้ที่ติ', - 'description': 'เขียนถูกต้อง 5 ประโยคติดต่อกัน', - 'condition': lambda: st.session_state.points['streak'] >= 5 - }, - 'vocabulary_master': { - 'name': '📚 ราชาคำศัพท์', - 'description': 'ใช้คำศัพท์ไม่ซ้ำกัน 50 คำ', - 'condition': lambda: len(st.session_state.stats['vocabulary_used']) >= 50 - }, - 'quick_learner': { - 'name': '🚀 นักเรียนจอมขยัน', - 'description': 'แก้ไขประโยคให้ถูกต้องภายใน 3 วินาที', - 'condition': lambda: True # ต้องเพิ่มการจับเวลา - }, - 'story_master': { - 'name': '📖 นักแต่งนิทาน', - 'description': 'เขียนเรื่องยาว 10 ประโยค', - 'condition': lambda: len(st.session_state.story) >= 10 - }, - 'accuracy_king': { - 'name': '👑 ราชาความแม่นยำ', - 'description': 'มีอัตราความถูกต้อง 80% ขึ้นไป (อย่างน้อย 10 ประโยค)', - 'condition': lambda: ( - st.session_state.stats['total_sentences'] >= 10 and - st.session_state.stats['accuracy_rate'] >= 80 - ) - } -} +# Set up logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) -# Set up Streamlit page configuration +# === 2. CONFIGURATIONS === +# Page Config st.set_page_config( page_title="JoyStory - Interactive Story Adventure", page_icon="📖", layout="wide", - initial_sidebar_state="collapsed", + initial_sidebar_state="collapsed" ) # Initialize OpenAI client -client = OpenAI() +try: + client = OpenAI() +except Exception as e: + logging.error(f"Failed to initialize OpenAI client: {str(e)}") + st.error("Failed to initialize AI services. Please try again later.") + +# Define Constants +MAX_RETRIES = 3 +DEFAULT_LEVEL = 'Beginner' +SUPPORTED_LANGUAGES = ['th', 'en'] + +# Achievement Requirements +ACHIEVEMENT_THRESHOLDS = { + 'perfect_writer': 5, # 5 correct sentences in a row + 'vocabulary_master': 50, # 50 unique words used + 'story_master': 10, # 10 sentences in story + 'accuracy_king': 80 # 80% accuracy rate +} -# Define level configurations +# Level Configuration level_options = { 'Beginner': { 'thai_name': 'ระดับเริ่มต้น (ป.1-3)', @@ -342,7 +59,10 @@ level_options = { 'คำศัพท์พื้นฐานที่ใช้ในชีวิตประจำวัน', 'มีคำแนะนำภาษาไทยละเอียด', 'เน้นการใช้ Present Simple Tense' - ] + ], + 'max_sentence_length': 10, + 'allowed_tenses': ['present_simple'], + 'feedback_level': 'detailed' }, 'Intermediate': { 'thai_name': 'ระดับกลาง (ป.4-6)', @@ -353,7 +73,10 @@ level_options = { 'เริ่มใช้ Past Tense ได้', 'คำศัพท์หลากหลายขึ้น', 'สามารถเขียนเรื่องราวต่อเนื่องได้' - ] + ], + 'max_sentence_length': 15, + 'allowed_tenses': ['present_simple', 'past_simple'], + 'feedback_level': 'moderate' }, 'Advanced': { 'thai_name': 'ระดับก้าวหน้า (ม.1-3)', @@ -364,67 +87,51 @@ level_options = { 'ใช้ Tense ต่างๆ ได้', 'คำศัพท์ระดับสูงขึ้น', 'สามารถแต่งเรื่องที่ซับซ้อนได้' - ] + ], + 'max_sentence_length': 20, + 'allowed_tenses': ['present_simple', 'past_simple', 'present_perfect', 'past_perfect'], + 'feedback_level': 'concise' } } -# Add custom CSS including new styles for level selection -st.markdown(""" - +""", unsafe_allow_html=True) + +# Reset counter when page reloads +if 'theme_button_counter' in st.session_state: + st.session_state.theme_button_counter = 0 + +# === 3. STATE MANAGEMENT === +def init_session_state(): + """Initialize all session state variables with default values""" + + # Basic states + default_states = { + 'theme_selection_id': datetime.now().strftime('%Y%m%d%H%M%S'), + 'current_theme': None, + 'theme_button_counter': 0, + 'theme_story_starter': None, + 'story': [], + 'feedback': None, + 'level': DEFAULT_LEVEL, + 'should_reset': False, + 'last_interaction': datetime.now().isoformat(), + } + + # Points system + points_states = { + 'points': { + 'total': 0, + 'perfect_sentences': 0, + 'corrections_made': 0, + 'streak': 0, + 'max_streak': 0 + } } - .theme-card:before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: linear-gradient(45deg, rgba(255,255,255,0.1), rgba(255,255,255,0.5)); - opacity: 0; - transition: opacity 0.3s ease; + # Statistics tracking + stats_states = { + 'stats': { + 'total_sentences': 0, + 'correct_first_try': 0, + 'accuracy_rate': 0.0, + 'vocabulary_used': set(), + 'corrections_made': 0, + 'average_sentence_length': 0, + 'total_words': 0, + 'session_duration': 0 + } } - .theme-card:hover:before { - opacity: 1; + # Game progress + progress_states = { + 'achievements': [], + 'unlocked_features': set(), + 'current_milestone': 0, + 'next_milestone': 5 } - .theme-card.selected { - transform: scale(0.98); - box-shadow: 0 2px 5px rgba(0,0,0,0.2); - } - - /* CSS สำหรับปุ่ม Change Theme */ - .stButton button { - padding: 0.5rem 1rem; - border-radius: 0.5rem; - border: 1px solid rgba(49, 51, 63, 0.2); - background-color: #ffffff; - color: #31333f; - transition: all 0.2s ease; + # User preferences + preferences_states = { + 'language': 'th', + 'feedback_level': 'detailed', + 'theme_color': 'light', + 'sound_enabled': True } - .stButton button:hover { - border-color: #1e88e5; - color: #1e88e5; - transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0,0,0,0.1); - } - - /* ปรับแต่ง tooltip */ - .stTooltipIcon { - color: #1e88e5; - } - - /* Responsive Design */ - @media (max-width: 768px) { - .theme-card { - min-height: 120px; - } - - .theme-card h4 { - font-size: 0.9em; - } - - .theme-card p { - font-size: 0.8em; - } - } - - /* Story Display Styling */ - .story-message { - padding: 10px; - margin: 5px 0; - border-radius: 5px; - } - .story-message.ai { - background-color: #f0f7ff; - } - .story-message.user { - background-color: #fff; - } - .story-message.corrected { - background-color: #f0f9ff; - } - -""", unsafe_allow_html=True) + # Initialize all states if they don't exist + for state_dict in [default_states, points_states, stats_states, progress_states, preferences_states]: + for key, value in state_dict.items(): + if key not in st.session_state: + st.session_state[key] = value -# Initialize session state variables -def init_session_state(): - if 'theme_selection_id' not in st.session_state: - st.session_state.theme_selection_id = datetime.now().strftime('%Y%m%d%H%M%S') +def init_theme_state(): + """Initialize theme-specific state variables""" if 'current_theme' not in st.session_state: st.session_state.current_theme = None - if 'theme_button_counter' not in st.session_state: - st.session_state.theme_button_counter = 0 if 'theme_story_starter' not in st.session_state: st.session_state.theme_story_starter = None - if 'story' not in st.session_state: + +def reset_story(): + """Reset story and related state variables""" + try: + # Reset story-related states st.session_state.story = [] - if 'feedback' not in st.session_state: st.session_state.feedback = None - if 'level' not in st.session_state: - st.session_state.level = 'Beginner' - if 'unique_words' not in st.session_state: - st.session_state.unique_words = set() - if 'total_words' not in st.session_state: - st.session_state.total_words = 0 - if 'should_reset' not in st.session_state: - st.session_state.should_reset = False - if 'user_input' not in st.session_state: - st.session_state.user_input = "" - if 'points' not in st.session_state: + st.session_state.theme_story_starter = None + + # Reset points st.session_state.points = { 'total': 0, 'perfect_sentences': 0, @@ -583,1814 +259,674 @@ def init_session_state(): 'streak': 0, 'max_streak': 0 } - if 'corrections' not in st.session_state: - st.session_state.corrections = {} - if 'stats' not in st.session_state: + + # Reset stats st.session_state.stats = { 'total_sentences': 0, 'correct_first_try': 0, 'accuracy_rate': 0.0, 'vocabulary_used': set(), - 'corrections_made': 0 + 'corrections_made': 0, + 'average_sentence_length': 0, + 'total_words': 0, + 'session_duration': 0 } - if 'achievements' not in st.session_state: - st.session_state.achievements = [] - -init_session_state() + + # Reset progress + st.session_state.current_milestone = 0 + st.session_state.next_milestone = 5 + + # Reset flag + st.session_state.should_reset = False + + # Log reset + logging.info("Story state reset successfully") + + return True + + except Exception as e: + logging.error(f"Error resetting story state: {str(e)}") + st.error("เกิดข้อผิดพลาดในการรีเซ็ตเรื่อง กรุณาลองใหม่อีกครั้ง") + return False -# เพิ่มฟังก์ชันสำหรับจัดการ input -def clear_input(): - st.session_state.user_input = "" +def save_progress() -> Dict: + """Save current progress to JSON format""" + try: + progress_data = { + 'timestamp': datetime.now().isoformat(), + 'level': st.session_state.level, + 'story': st.session_state.story, + 'stats': { + key: list(value) if isinstance(value, set) else value + for key, value in st.session_state.stats.items() + }, + 'points': st.session_state.points, + 'achievements': st.session_state.achievements, + 'current_theme': st.session_state.current_theme + } + + logging.info("Progress saved successfully") + return progress_data + + except Exception as e: + logging.error(f"Error saving progress: {str(e)}") + raise -# Callback function for submit button -def submit_story(): - """Handle story submission and processing.""" - if st.session_state.text_input.strip(): - user_text = st.session_state.text_input.strip() +def load_progress(data: Dict): + """Load progress from saved data""" + try: + # Validate data structure + required_keys = ['level', 'story', 'stats', 'points', 'achievements'] + if not all(key in data for key in required_keys): + raise ValueError("Invalid save data format") + + # Load basic data + st.session_state.level = data['level'] + st.session_state.story = data['story'] + st.session_state.achievements = data['achievements'] + st.session_state.points = data['points'] + + # Load stats (converting lists back to sets where needed) + st.session_state.stats = { + 'total_sentences': data['stats']['total_sentences'], + 'correct_first_try': data['stats']['correct_first_try'], + 'accuracy_rate': data['stats']['accuracy_rate'], + 'vocabulary_used': set(data['stats']['vocabulary_used']), + 'corrections_made': data['stats']['corrections_made'], + 'average_sentence_length': data['stats'].get('average_sentence_length', 0), + 'total_words': data['stats'].get('total_words', 0), + 'session_duration': data['stats'].get('session_duration', 0) + } + + # Load theme if present + if 'current_theme' in data: + st.session_state.current_theme = data['current_theme'] + + logging.info("Progress loaded successfully") + st.success("โหลดความก้าวหน้าเรียบร้อย!") - # ตรวจสอบว่ามีเรื่องเริ่มต้นหรือยัง - if not st.session_state.story: - st.error("กรุณาเลือกธีมเรื่องราวก่อนเริ่มเขียน") - return + return True + + except Exception as e: + logging.error(f"Error loading progress: {str(e)}") + st.error("เกิดข้อผิดพลาดในการโหลดข้อมูล กรุณาตรวจสอบไฟล์และลองใหม่อีกครั้ง") + return False - try: - # รับ feedback และตรวจสอบความถูกต้อง - feedback_data = provide_feedback(user_text, st.session_state.level) - st.session_state.feedback = feedback_data - is_correct = not feedback_data.get('has_errors', False) - - # เพิ่มประโยคของผู้ใช้ (เพิ่มครั้งเดียว) - st.session_state.story.append({ - "role": "You", - "content": user_text, - "is_corrected": False, - "is_correct": is_correct - }) - - # เพิ่มคำศัพท์ที่ใช้ - words = set(user_text.lower().split()) - st.session_state.stats['vocabulary_used'].update(words) - - # อัพเดตคะแนนและ achievements - update_points(is_correct) - update_achievements() +def update_session_stats(): + """Update session statistics""" + try: + if st.session_state.story: + # Update word counts + all_text = ' '.join([entry['content'] for entry in st.session_state.story]) + words = all_text.split() + st.session_state.stats['total_words'] = len(words) - # Generate AI continuation - text_for_continuation = feedback_data['corrected'] if feedback_data['has_errors'] else user_text - ai_response = generate_story_continuation(text_for_continuation, st.session_state.level) + # Update average sentence length + if st.session_state.stats['total_sentences'] > 0: + st.session_state.stats['average_sentence_length'] = ( + st.session_state.stats['total_words'] / + st.session_state.stats['total_sentences'] + ) - # เพิ่มการตอบกลับของ AI - st.session_state.story.append({ - "role": "AI", - "content": ai_response - }) + # Update session duration + start_time = datetime.fromisoformat(st.session_state.last_interaction) + current_time = datetime.now() + duration = (current_time - start_time).total_seconds() + st.session_state.stats['session_duration'] = duration - # Clear input - st.session_state.text_input = "" + # Update last interaction time + st.session_state.last_interaction = current_time.isoformat() - except Exception as e: - st.error("เกิดข้อผิดพลาดในการวิเคราะห์ประโยค กรุณาลองใหม่อีกครั้ง") - st.error(f"Debug - Error in submit_story: {str(e)}") - - -# Theme Helper Functions -def get_available_themes(level: str) -> List[Dict]: - """Get list of themes available for the current level.""" - return [ - theme for theme in story_themes.values() - if level in theme['level_range'] - ] - -def generate_dynamic_story_starter(theme_id: str, level: str) -> Dict[str, str]: - """ - Dynamically generate a story starter based on theme and level. - Returns both Thai and English versions. - """ - theme = story_themes.get(theme_id, {}) + return True - # Theme-specific elements for dynamic generation - theme_elements = { - 'fantasy': { - 'characters': { - 'Beginner': [ - ('young wizard', 'พ่อมดน้อย'), - ('fairy', 'นางฟ้า'), - ('friendly dragon', 'มังกรใจดี'), - ('magical cat', 'แมวเวทมนตร์'), - ], - 'Intermediate': [ - ('mysterious wizard', 'พ่อมดลึกลับ'), - ('ancient dragon', 'มังกรโบราณ'), - ('enchanted princess', 'เจ้าหญิงต้องมนตร์'), - ], - 'Advanced': [ - ('legendary sorcerer', 'จอมเวทในตำนาน'), - ('mythical creature', 'สัตว์ในตำนาน'), - ('wise elder wizard', 'พ่อมดผู้เฒ่าผู้เป็นปราชญ์'), - ] - }, - 'locations': { - 'Beginner': [ - ('magical garden', 'สวนเวทมนตร์'), - ('enchanted forest', 'ป่าวิเศษ'), - ], - 'Intermediate': [ - ('ancient castle', 'ปราสาทโบราณ'), - ('wizard school', 'โรงเรียนเวทมนตร์'), - ], - 'Advanced': [ - ('mystical realm', 'อาณาจักรเวทมนตร์'), - ('floating islands', 'เกาะลอยฟ้า'), - ] - }, - 'objects': { - 'Beginner': [ - ('magic wand', 'ไม้กายสิทธิ์'), - ('glowing crystal', 'คริสตัลเรืองแสง'), - ], - 'Intermediate': [ - ('ancient spellbook', 'ตำราเวทโบราณ'), - ('magical artifact', 'วัตถุวิเศษ'), - ], - 'Advanced': [ - ('legendary sword', 'ดาบในตำนาน'), - ('mystical orb', 'ลูกแก้ววิเศษ'), - ] - } - }, - 'nature': { - 'characters': { - 'Beginner': [ - ('little bird', 'นกน้อย'), - ('friendly squirrel', 'กระรอกน้อยใจดี'), - ('playful rabbit', 'กระต่ายซน'), - ], - 'Intermediate': [ - ('wise owl', 'นกฮูกผู้รอบรู้'), - ('busy beaver', 'บีเวอร์ขยัน'), - ('clever fox', 'จิ้งจอกเจ้าปัญญา'), - ], - 'Advanced': [ - ('majestic eagle', 'อินทรีผู้สง่างาม'), - ('mysterious panther', 'เสือดำลึกลับ'), - ] - }, - 'locations': { - 'Beginner': [ - ('flower garden', 'สวนดอกไม้'), - ('small pond', 'สระน้ำเล็กๆ'), - ], - 'Intermediate': [ - ('deep forest', 'ป่าลึก'), - ('mountain peak', 'ยอดเขาสูง'), - ], - 'Advanced': [ - ('ancient rainforest', 'ป่าดึกดำบรรพ์'), - ('hidden valley', 'หุบเขาซ่อนเร้น'), - ] - }, - 'objects': { - 'Beginner': [ - ('colorful flower', 'ดอกไม้สีสวย'), - ('fallen leaf', 'ใบไม้ร่วง'), - ], - 'Intermediate': [ - ('old tree', 'ต้นไม้เก่าแก่'), - ('clear stream', 'ลำธารใส'), - ], - 'Advanced': [ - ('rare plant', 'พืชหายาก'), - ('ancient tree', 'ต้นไม้โบราณ'), - ] - } - }, - 'space': { - 'characters': { - 'Beginner': [ - ('friendly alien', 'มนุษย์ต่างดาวใจดี'), - ('little astronaut', 'นักบินอวกาศตัวน้อย'), - ('space robot', 'หุ่นยนต์อวกาศ'), - ], - 'Intermediate': [ - ('space explorer', 'นักสำรวจอวกาศ'), - ('alien scientist', 'นักวิทยาศาสตร์ต่างดาว'), - ('space pilot', 'นักบินยานอวกาศ'), - ], - 'Advanced': [ - ('galactic commander', 'ผู้บัญชาการกาแล็กซี่'), - ('space archaeologist', 'นักโบราณคดีอวกาศ'), - ] - }, - 'locations': { - 'Beginner': [ - ('small planet', 'ดาวเคราะห์เล็กๆ'), - ('space station', 'สถานีอวกาศ'), - ], - 'Intermediate': [ - ('mysterious galaxy', 'กาแล็กซี่ลึกลับ'), - ('alien world', 'โลกต่างดาว'), - ], - 'Advanced': [ - ('black hole', 'หลุมดำ'), - ('distant nebula', 'เนบิวลาไกลโพ้น'), - ] - }, - 'objects': { - 'Beginner': [ - ('shiny meteor', 'ดาวตกเปล่งประกาย'), - ('space telescope', 'กล้องดูดาว'), - ], - 'Intermediate': [ - ('advanced spaceship', 'ยานอวกาศลำใหม่'), - ('mysterious signal', 'สัญญาณลึกลับ'), - ], - 'Advanced': [ - ('alien artifact', 'วัตถุโบราณจากต่างดาว'), - ('space anomaly', 'ความผิดปกติในอวกาศ'), - ] - } - }, - 'adventure': { - 'characters': { - 'Beginner': [ - ('young explorer', 'นักผจญภัยตัวน้อย'), - ('treasure hunter', 'นักล่าสมบัติ'), - ('brave sailor', 'กะลาสีผู้กล้า'), - ], - 'Intermediate': [ - ('experienced guide', 'ไกด์ผู้ชำนาญ'), - ('mysterious traveler', 'นักเดินทางลึกลับ'), - ], - 'Advanced': [ - ('legendary explorer', 'นักสำรวจในตำนาน'), - ('ancient guardian', 'ผู้พิทักษ์โบราณ'), - ] - }, - 'locations': { - 'Beginner': [ - ('hidden cave', 'ถ้ำซ่อนเร้น'), - ('treasure island', 'เกาะสมบัติ'), - ], - 'Intermediate': [ - ('ancient ruins', 'ซากปรักหักพัง'), - ('mysterious temple', 'วัดลึกลับ'), - ], - 'Advanced': [ - ('lost city', 'เมืองที่สาบสูญ'), - ('forbidden valley', 'หุบเขาต้องห้าม'), - ] - }, - 'objects': { - 'Beginner': [ - ('old map', 'แผนที่เก่า'), - ('golden compass', 'เข็มทิศทองคำ'), - ], - 'Intermediate': [ - ('ancient scroll', 'ม้วนกระดาษโบราณ'), - ('magical key', 'กุญแจวิเศษ'), - ], - 'Advanced': [ - ('legendary artifact', 'วัตถุโบราณในตำนาน'), - ('sacred relic', 'วัตถุศักดิ์สิทธิ์'), - ] - } - }, - 'school': { - 'characters': { - 'Beginner': [ - ('new student', 'นักเรียนใหม่'), - ('kind teacher', 'คุณครูใจดี'), - ('best friend', 'เพื่อนรัก'), - ], - 'Intermediate': [ - ('class president', 'หัวหน้าห้อง'), - ('school librarian', 'บรรณารักษ์'), - ], - 'Advanced': [ - ('exchange student', 'นักเรียนแลกเปลี่ยน'), - ('science genius', 'อัจฉริยะวิทยาศาสตร์'), - ] - }, - 'locations': { - 'Beginner': [ - ('classroom', 'ห้องเรียน'), - ('school playground', 'สนามเด็กเล่น'), - ], - 'Intermediate': [ - ('science lab', 'ห้องทดลองวิทยาศาสตร์'), - ('school library', 'ห้องสมุด'), - ], - 'Advanced': [ - ('school theater', 'โรงละครโรงเรียน'), - ('computer room', 'ห้องคอมพิวเตอร์'), - ] - }, - 'objects': { - 'Beginner': [ - ('new book', 'หนังสือเล่มใหม่'), - ('special pencil', 'ดินสอวิเศษ'), - ], - 'Intermediate': [ - ('science project', 'โครงงานวิทยาศาสตร์'), - ('old diary', 'ไดอารี่เก่า'), - ], - 'Advanced': [ - ('robotics kit', 'ชุดประดิษฐ์หุ่นยนต์'), - ('ancient textbook', 'ตำราเรียนโบราณ'), - ] - } - }, - 'superhero': { - 'characters': { - 'Beginner': [ - ('young hero', 'ฮีโร่ตัวน้อย'), - ('super pet', 'สัตว์เลี้ยงพลังพิเศษ'), - ('friendly sidekick', 'ผู้ช่วยฮีโร่'), - ], - 'Intermediate': [ - ('masked vigilante', 'ฮีโร่ปริศนา'), - ('super teacher', 'คุณครูพลังพิเศษ'), - ], - 'Advanced': [ - ('legendary hero', 'ฮีโร่ในตำนาน'), - ('protector of justice', 'ผู้พิทักษ์ความยุติธรรม'), - ] - }, - 'locations': { - 'Beginner': [ - ('hero school', 'โรงเรียนฮีโร่'), - ('secret hideout', 'ที่ซ่อนลับ'), - ], - 'Intermediate': [ - ('hero headquarters', 'ศูนย์บัญชาการฮีโร่'), - ('training ground', 'สนามฝึกซ้อม'), - ], - 'Advanced': [ - ('hero academy', 'สถาบันฝึกฮีโร่'), - ('crisis center', 'ศูนย์รับมือวิกฤต'), - ] - }, - 'objects': { - 'Beginner': [ - ('hero mask', 'หน้ากากฮีโร่'), - ('power crystal', 'คริสตัลพลัง'), - ], - 'Intermediate': [ - ('super gadget', 'อุปกรณ์พิเศษ'), - ('power suit', 'ชุดพลังพิเศษ'), - ], - 'Advanced': [ - ('ultimate weapon', 'อาวุธสุดยอด'), - ('ancient power source', 'แหล่งพลังโบราณ'), - ] - } - }, - 'mystery': { - 'characters': { - 'Beginner': [ - ('young detective', 'นักสืบตัวน้อย'), - ('mysterious neighbor', 'เพื่อนบ้านปริศนา'), - ('helpful friend', 'เพื่อนผู้ช่วย'), - ], - 'Intermediate': [ - ('famous detective', 'นักสืบชื่อดัง'), - ('mystery writer', 'นักเขียนนิยายปริศนา'), - ], - 'Advanced': [ - ('master detective', 'ยอดนักสืบ'), - ('crime expert', 'ผู้เชี่ยวชาญคดี'), - ] - }, - 'locations': { - 'Beginner': [ - ('old house', 'บ้านเก่า'), - ('mystery shop', 'ร้านค้าปริศนา'), - ], - 'Intermediate': [ - ('abandoned building', 'ตึกร้าง'), - ('detective office', 'สำนักงานนักสืบ'), - ], - 'Advanced': [ - ('secret laboratory', 'ห้องทดลองลับ'), - ('mystery mansion', 'คฤหาสน์ปริศนา'), - ] - }, - 'objects': { - 'Beginner': [ - ('mysterious letter', 'จดหมายปริศนา'), - ('strange footprint', 'รอยเท้าประหลาด'), - ], - 'Intermediate': [ - ('ancient cipher', 'รหัสลับโบราณ'), - ('hidden clue', 'เบาะแสซ่อนเร้น'), - ], - 'Advanced': [ - ('secret document', 'เอกสารลับ'), - ('mysterious artifact', 'วัตถุปริศนา'), - ] - } - }, - 'science': { - 'characters': { - 'Beginner': [ - ('young scientist', 'นักวิทยาศาสตร์ตัวน้อย'), - ('robot friend', 'หุ่นยนต์เพื่อนรัก'), - ('curious student', 'นักเรียนช่างสงสัย'), - ], - 'Intermediate': [ - ('brilliant inventor', 'นักประดิษฐ์อัจฉริยะ'), - ('science teacher', 'คุณครูวิทยาศาสตร์'), - ], - 'Advanced': [ - ('famous researcher', 'นักวิจัยชื่อดัง'), - ('genius professor', 'ศาสตราจารย์อัจฉริยะ'), - ] - }, - 'locations': { - 'Beginner': [ - ('science lab', 'ห้องทดลองวิทยาศาสตร์'), - ('invention workshop', 'ห้องประดิษฐ์'), - ], - 'Intermediate': [ - ('research center', 'ศูนย์วิจัย'), - ('robotics lab', 'ห้องปฏิบัติการหุ่นยนต์'), - ], - 'Advanced': [ - ('quantum laboratory', 'ห้องปฏิบัติการควอนตัม'), - ('innovation center', 'ศูนย์นวัตกรรม'), - ] - }, - 'objects': { - 'Beginner': [ - ('colorful chemical', 'สารเคมีสีสันสดใส'), - ('strange invention', 'สิ่งประดิษฐ์แปลกใหม่'), - ], - 'Intermediate': [ - ('advanced machine', 'เครื่องจักรทันสมัย'), - ('experimental device', 'อุปกรณ์ทดลอง'), - ], - 'Advanced': [ - ('groundbreaking discovery', 'การค้นพบที่ยิ่งใ��ญ่'), - ('revolutionary invention', 'สิ่งประดิษฐ์ปฏิวัติโลก'), - ] - } - } - } - - def get_random_element(category: str) -> Tuple[str, str]: - """Get random element from the specified category for current theme and level.""" - elements = theme_elements.get(theme_id, {}).get(category, {}).get(level, []) - if not elements: - elements = theme_elements.get(theme_id, {}).get(category, {}).get('Beginner', []) - return random.choice(elements) if elements else ('', '') - - # Get random elements - character_en, character_th = get_random_element('characters') - location_en, location_th = get_random_element('locations') - object_en, object_th = get_random_element('objects') + except Exception as e: + logging.error(f"Error updating session stats: {str(e)}") + return False - # Templates for different levels - templates = { +# === 4. UTILITY FUNCTIONS === +def generate_story_continuation(user_input: str, level: str) -> str: + """Generate AI story continuation using ChatGPT""" + + level_context = { 'Beginner': { - 'en': [ - f"One day, {character_en} found {object_en} in {location_en}...", - f"In {location_en}, {character_en} saw something special...", - f"{character_en} was walking in {location_en} when suddenly...", - f"The story begins when {character_en} discovered {object_en}...", - ], - 'th': [ - f"วันหนึ่ง {character_th}เจอ{object_th}ใน{location_th}...", - f"ที่{location_th} {character_th}เห็นบางสิ่งที่พิเศษ...", - f"{character_th}กำลังเดินอยู่ใน{location_th} เมื่อจู่ๆ...", - f"เรื่องราวเริ่มต้นเมื่อ{character_th}ค้นพบ{object_th}...", - ] + 'instructions': """ + Role: Teaching assistant for Thai students (grades 1-3) + Rules: + - Use only 1-2 VERY simple sentences + - Use Present Simple Tense only + - Basic vocabulary (family, school, daily activities) + - 5-7 words per sentence maximum + - Focus on clear, basic responses + """, + 'max_tokens': 30, + 'temperature': 0.6 }, 'Intermediate': { - 'en': [ - f"While exploring {location_en}, {character_en} discovered {object_en} that seemed magical...", - f"The story begins when {character_en} encountered a mysterious {object_en} in {location_en}...", - f"Something strange was happening in {location_en}, and {character_en} knew it had to do with {object_en}...", - f"Nobody knew why {character_en} found {object_en} in {location_en}, but...", - ], - 'th': [ - f"ขณะที่สำรวจ{location_th} {character_th}ได้ค้นพบ{object_th}ที่ดูมีเวทมนตร์...", - f"เรื่องราวเริ่มต้นเมื่อ{character_th}พบกับ{object_th}ที่ลึกลับใน{location_th}...", - f"มีบางสิ่งประหลาดเกิดขึ้นใน{location_th} และ{character_th}รู้ว่ามันเกี่ยวข้องกับ{object_th}...", - f"ไม่มีใครรู้ว่าทำไม{character_th}ถึงพบ{object_th}ใน{location_th} แต่...", - ] + 'instructions': """ + Role: Teaching assistant for Thai students (grades 4-6) + Rules: + - Use exactly 2 sentences maximum + - Can use Present or Past Tense + - Keep each sentence under 12 words + - Grade-appropriate vocabulary + - Add simple descriptions but stay concise + """, + 'max_tokens': 40, + 'temperature': 0.7 }, 'Advanced': { - 'en': [ - f"Legend speaks of {object_en} hidden within {location_en}, and {character_en} was destined to find it...", - f"In the depths of {location_en}, {character_en} uncovered an ancient mystery surrounding {object_en}...", - f"As {character_en} ventured through {location_en}, the secrets of {object_en} began to unfold...", - f"The discovery of {object_en} by {character_en} in {location_en} would change everything...", - ], - 'th': [ - f"ตำนานเล่าขานถึง{object_th}ที่ซ่อนอยู่ใน{location_th} และ{character_th}ถูกลิขิตให้เป็นผู้ค้นพบ...", - f"ในส่วนลึกของ{location_th} {character_th}ได้พบกับปริศนาโบราณเกี่ยวกับ{object_th}...", - f"ขณะที่{character_th}ผจญภัยใน{location_th} ความลับของ{object_th}ก็เริ่มเผยออกมา...", - f"การค้นพบ{object_th}โดย{character_th}ใน{location_th}จะเปลี่ยนแปลงทุกสิ่ง...", - ] - } - } - - # Select random template for the current level - level_templates = templates.get(level, templates['Beginner']) - starter_en = random.choice(level_templates['en']) - starter_th = random.choice(level_templates['th']) - - return { - 'en': starter_en, - 'th': starter_th - } - -def convert_sets_to_lists(obj): - """แปลง set เป็น list สำหรับการ serialize เป็น JSON""" - if isinstance(obj, set): - return list(obj) - elif isinstance(obj, dict): - return {key: convert_sets_to_lists(value) for key, value in obj.items()} - elif isinstance(obj, list): - return [convert_sets_to_lists(item) for item in obj] - return obj - -def get_theme_story_starter(theme_id: str, level: str) -> Dict[str, str]: - """Get a dynamically generated story starter for the selected theme and level.""" - return generate_dynamic_story_starter(theme_id, level) - -def get_theme_vocabulary(theme_id: str, level: str) -> List[Dict[str, str]]: - """ - Get theme-specific vocabulary with Thai translations and example sentences. - Returns list of dictionaries containing word, type, thai meaning, and example. - """ - vocab_data = { - 'fantasy': { - 'Beginner': [ - { - 'word': 'magic', - 'type': 'noun', - 'thai': 'เวทมนตร์', - 'example_en': 'The magic made flowers appear.', - 'example_th': 'เวทมนตร์ทำให้ดอกไม้ปรากฏขึ้น' - }, - { - 'word': 'wizard', - 'type': 'noun', - 'thai': 'พ่อมด', - 'example_en': 'The wizard waved his wand.', - 'example_th': 'พ่อมดโบกไม้กายสิทธิ์' - } - ], - 'Intermediate': [ - { - 'word': 'enchanted', - 'type': 'adjective', - 'thai': 'ที่ถูกสะกดด้วยเวทมนตร์', - 'example_en': 'They found an enchanted forest.', - 'example_th': 'พวกเขาพบป่าที่ถูกสะกดด้วยเวทมนตร์' - } - ] - }, - 'mystery': { - 'Beginner': [ - { - 'word': 'clue', - 'type': 'noun', - 'thai': 'เบาะแส', - 'example_en': 'The detective found an important clue.', - 'example_th': 'นักสืบพบเบาะแสสำคัญ' - } - ] + 'instructions': """ + Role: Teaching assistant for Thai students (grades 7-9) + Rules: + - Use 2-3 sentences maximum + - Various tenses allowed + - Natural sentence length but keep overall response concise + - More sophisticated vocabulary and structures + - Create engaging responses that encourage creative continuation + """, + 'max_tokens': 50, + 'temperature': 0.8 } } - # แสดงคำศัพท์พร้อมตัวอย่างประโยคในหน้า UI - def show_vocabulary(word_list: List[Dict[str, str]]): - st.markdown("### 📚 คำศัพท์น่ารู้ประจำธีม") - for word_data in word_list: - st.markdown(f""" -
เลือกโลกแห่งจินตนาการที่คุณต้องการผจญภัย และเริ่มต้นเขียนเรื่องราวของคุณ
-
- 🎯 ตัวอย่างคำศัพท์:
- {', '.join(theme['vocabulary'][st.session_state.level][:3])}...
-
💡 เคล็ดลับ: เลือกธีมที่คุณสนใจและอยากเขียนถึงที่สุด
-- แต่ละธีมมีคำศัพท์และแนวเรื่องที่แตกต่างกัน เหมาะสำหรับการฝึกเขียนในบริบทต่างๆ -
-💡 เคล็ดลับ: ให้น้องๆ พูดเรื่องราวที่อยากเขียนเป็นภาษาไทยก่อน - แล้วค่อยๆ ช่วยกันแปลงเป็นภาษาอังกฤษ
-🎬 เริ่มเรื่อง:
-{entry.get('thai_content', '')}
-{entry['content']}
-🤖 AI: {entry['content']}
-👤 You: {status_icon}{entry['content']}
-Streak ปัจจุบัน: {st.session_state.points['streak']} ประโยค
-Streak สูงสุด: {st.session_state.points['max_streak']} ประโยค
+# === 5. UI COMPONENTS === +def show_welcome_section(): + """Display welcome message and introduction""" + st.markdown(""" ++ 💡 เคล็ดลับ: ให้น้องๆ พูดเรื่องราวที่อยากเขียนเป็นภาษาไทยก่อน + แล้วค่อยๆ ช่วยกันแปลงเป็นภาษาอังกฤษ +
{st.session_state.theme_story_starter['th']}
-{st.session_state.theme_story_starter['en']}
+ 🎯 {level_options[level]['description']} +
++ 👥 เหมาะสำหรับอายุ: {level_options[level]['age_range']} +
++ เลือกโลกแห่งจินตนาการที่คุณต้องการผจญภัย และเริ่มต้นเขียนเรื่องราวของคุณ +
++ 💡 เคล็ดลับ: เลือกธีมที่คุณสนใจและอยากเขียนถึงที่สุด +
++ แต่ละธีมมีคำศัพท์และแนวเรื่องที่แตกต่างกัน เหมาะสำหรับการฝึกเขียนในบริบทต่างๆ +
+- {feedback_data['feedback']} -
-
- ประโยคที่ถูกต้อง:
-
- {feedback_data['corrected']}
-
-
- {feedback_data.get('feedback', '✨ เขียนได้ถูกต้องแล้วค่ะ!')} -
-