import math import gradio as gr from transformers import MarianTokenizer, MarianMTModel import re import functools ################################### # 1) โหลดโมเดล MarianMT (Thai->En) ครั้งเดียวเมื่อเริ่มแอป ################################### model_name = "Helsinki-NLP/opus-mt-th-en" tokenizer = MarianTokenizer.from_pretrained(model_name) model = MarianMTModel.from_pretrained(model_name) # เพิ่มการแคชผลลัพธ์การแปล @functools.lru_cache(maxsize=1024) def translate_th_to_en(text_th: str) -> str: """ แปลไทย -> อังกฤษ ด้วย MarianMT บน CPU * เรียกเฉพาะส่วนที่ผู้ใช้พิมพ์ เช่น ชื่อดาว, ชื่อสิ่งมีชีวิต """ text_th = text_th.strip() if not text_th: return "" inputs = tokenizer(text_th, return_tensors="pt", max_length=512, truncation=True) translation_tokens = model.generate(**inputs, max_length=512) en_text = tokenizer.decode(translation_tokens[0], skip_special_tokens=True) return en_text ################################### # 2) สูตรอุณหภูมิ (Black Body) + Greenhouse ################################### def approximate_temp_with_star(star_type, distance_au, albedo=0.3): """ star_type: Red Dwarf / White Dwarf / Sun-like / Blue Giant / Supergiant distance_au: ระยะห่าง (AU) albedo: สะท้อนแสง (0.3) """ lum_ratio_map = { "Red Dwarf": 0.02, "White Dwarf": 0.001, "Sun-like": 1.0, "Blue Giant": 10.0, "Supergiant": 100.0 } lum_ratio = lum_ratio_map.get(star_type, 1.0) luminosity = 3.828e26 * lum_ratio dist_m = distance_au * 1.496e11 sigma = 5.67e-8 T_k = ((1 - albedo) * luminosity / (16 * math.pi * sigma * dist_m**2))**0.25 T_c = T_k - 273.15 T_c += 15 # Greenhouse return round(T_c) ################################### # 3) สูตรแรงโน้มถ่วง (ตามนิวตัน โดยคำนึงถึงความหนาแน่นตามชนิดดาว) ################################### def approximate_gravity(diameter_factor, planet_type_th): """ คำนวณแรงโน้มถ่วงตามขนาดและชนิดดาว """ G = 6.67430e-11 # m³ kg⁻¹ s⁻² earth_radius = 6.371e6 # meters radius = diameter_factor * earth_radius # m # กำหนดความหนาแน่นตามชนิดดาว density_map = { "ดาวหิน": 5500, # kg/m³ "ดาวก๊าซ": 1300, # kg/m³ "ดาวน้ำแข็ง": 1600 # kg/m³ } density = density_map.get(planet_type_th, 5500) # ค่าเริ่มต้นเป็นดาวหิน # คำนวณมวล: M = density * volume = density * (4/3) * pi * R^3 mass = density * (4/3) * math.pi * radius**3 # คำนวณแรงโน้มถ่วง: g = G * M / R^2 g = G * mass / radius**2 # m/s² # แปลงเป็น g ของโลก g_earth = 9.81 g_relative = g / g_earth return round(g_relative, 2) ################################### # 4) Dictionary แปลล่วงหน้า (TH->EN) ################################### pretranslated_map = { # distance "โคจรใกล้ดาวฤกษ์มาก": "orbits extremely close to its star", "โคจรคล้ายโลกหรืออุ่นกว่านิดหน่อย": "orbits similarly to Earth or slightly warmer", "โคจรห่างพอประมาณ อากาศค่อนข้างเย็น": "orbits moderately far, quite cool climate", "โคจรไกลสุดขั้ว อากาศหนาวมาก": "orbits extremely far, very cold environment", # temp "อากาศหนาวแข็ง": "freezing cold", "เย็นสบาย": "mildly cool", "พอเหมาะกำลังดี": "pleasantly temperate", "ร้อนระอุ": "intensely hot", # gravity "โน้มถ่วงเบา (ลอยง่าย)": "light gravity (easy to float)", "คล้ายโลก": "similar to Earth", "หนักกว่าปกติ": "heavier than usual", "หนักมาก": "very heavy", # tilt "แทบไม่เอียง": "almost no axial tilt", "เอียงเล็กน้อย มีฤดูกาลเบาๆ": "slightly tilted, gentle seasons", "เอียงปานกลาง ฤดูกาลเปลี่ยนแปลง": "moderately tilted, noticeable seasonal changes", "เอียงมาก ฤดูกาลสุดขั้ว": "highly tilted, extreme seasonal shifts", # moons "ไม่มีดวงจันทร์": "no moons", "มีดวงจันทร์หนึ่งดวง": "one moon", "มีดวงจันทร์สองดวง": "two moons", "มีดวงจันทร์สามดวง": "three moons", "มีดวงจันทร์สี่ดวง": "four moons", "มีดวงจันทร์ห้าวง": "five moons", "มีดวงจันทร์หกดวง": "six moons", "มีดวงจันทร์เจ็ดดวง": "seven moons", "มีดวงจันทร์แปดดวง": "eight moons", "มีดวงจันทร์เก้าดวง": "nine moons", "มีดวงจันทร์สิบดวง": "ten moons", } def describe_distance_th_to_en(desc_th): return pretranslated_map.get(desc_th, "unknown distance environment") def describe_temp_th_to_en(desc_th): return pretranslated_map.get(desc_th, "unknown temperature") def describe_gravity_th_to_en(desc_th): return pretranslated_map.get(desc_th, "unknown gravity") def describe_tilt_th_to_en(desc_th): return pretranslated_map.get(desc_th, "unknown axial tilt") def describe_moons_th_to_en(desc_th): return pretranslated_map.get(desc_th, "unknown moons") def describe_oxygen_th_to_en(desc_th): if desc_th == "ไม่มีออกซิเจน": return "no oxygen" elif desc_th == "ออกซิเจนน้อย": return "low oxygen" elif desc_th == "ออกซิเจนพอเหมาะ": return "moderate oxygen" else: return "high oxygen" ################################### # ฟังก์ชันบรรยาย (ภาษาไทย) ################################### def describe_distance(distance_au): if distance_au < 0.5: return "โคจรใกล้ดาวฤกษ์มาก" elif distance_au < 1.2: return "โคจรคล้ายโลกหรืออุ่นกว่านิดหน่อย" elif distance_au < 2.5: return "โคจรห่างพอประมาณ อากาศค่อนข้างเย็น" else: return "โคจรไกลสุดขั้ว อากาศหนาวมาก" def describe_temp(temp_c): if temp_c < -30: return "อากาศหนาวแข็ง" elif temp_c < 10: return "เย็นสบาย" elif temp_c < 35: return "พอเหมาะกำลังดี" else: return "ร้อนระอุ" def describe_gravity(g): if g < 0.5: return "โน้มถ่วงเบา (ลอยง่าย)" elif g < 1.2: return "คล้ายโลก" elif g < 2.0: return "หนักกว่าปกติ" else: return "หนักมาก" def describe_tilt(tilt_deg): if tilt_deg < 5: return "แทบไม่เอียง" elif tilt_deg < 25: return "เอียงเล็กน้อย มีฤดูกาลเบาๆ" elif tilt_deg < 45: return "เอียงปานกลาง ฤดูกาลเปลี่ยนแปลง" else: return "เอียงมาก ฤดูกาลสุดขั้ว" def describe_moons(n): if n <= 0: return "ไม่มีดวงจันทร์" elif n == 1: return "มีดวงจันทร์หนึ่งดวง" elif n == 2: return "มีดวงจันทร์สองดวง" elif n == 3: return "มีดวงจันทร์สามดวง" elif n == 4: return "มีดวงจันทร์สี่ดวง" elif n == 5: return "มีดวงจันทร์ห้าวง" elif n == 6: return "มีดวงจันทร์หกดวง" elif n == 7: return "มีดวงจันทร์เจ็ดดวง" elif n == 8: return "มีดวงจันทร์แปดดวง" elif n == 9: return "มีดวงจันทร์เก้าดวง" elif n == 10: return "มีดวงจันทร์สิบดวง" else: return f"มีดวงจันทร์ {n} ดวง" def describe_oxygen(oxygen_percent): if oxygen_percent < 1: return "ไม่มีออกซิเจน" elif oxygen_percent < 10: return "ออกซิเจนน้อย" elif oxygen_percent < 25: return "ออกซิเจนพอเหมาะ" else: return "ออกซิเจนสูง" ################################### # 5) สร้าง Prompt 3 แบบ (Pre-translate dictionary) ################################### def build_prompts_en( planet_name_en, star_type_en, dist_desc_en, temp_desc_en, grav_desc_en, tilt_desc_en, moon_desc_en, oxygen_desc_en, life_en ): # Prompt 1 prompt1 = ( f"A vibrant space painting of planet '{planet_name_en}' orbiting a {star_type_en} star. " f"It is {dist_desc_en}, with {temp_desc_en} conditions and {grav_desc_en} gravity. " f"{tilt_desc_en}, {moon_desc_en}, atmosphere has {oxygen_desc_en}. Cinematic details." ) # Prompt 2 prompt2 = ( f"On planet '{planet_name_en}', we discover {life_en} thriving in {temp_desc_en} weather, " f"{grav_desc_en} pull, and {oxygen_desc_en} in the air. Surreal alien ecosystem, rich concept art." ) # Prompt 3 prompt3 = ( f"Exploring the surface of '{planet_name_en}': {temp_desc_en} climate, {grav_desc_en}, " f"{tilt_desc_en} tilt, and {moon_desc_en}. Epic environment design, atmospheric perspective." ) return prompt1, prompt2, prompt3 ################################### # 6) ฟังก์ชันหลัก generate_planet_info ################################### def generate_planet_info( planet_name_th, star_type_en, distance_str, diameter_str, tilt_value, moon_value, oxygen_percent, planet_type_th, life_th ): # parse try: distance_au = float(distance_str) except: distance_au = 1.0 try: diameter_factor = float(diameter_str) except: diameter_factor = 1.0 try: tilt_deg = float(tilt_value) except: tilt_deg = 23.5 try: moon_count = int(moon_value) except: moon_count = 1 try: oxygen_percent = float(oxygen_percent) except: oxygen_percent = 21.0 # คำนวณ temp_c = approximate_temp_with_star(star_type_en, distance_au) g_approx = approximate_gravity(diameter_factor, planet_type_th) # ----------------------------- # (A) สรุปสำหรับเด็ก (ไทย) # ----------------------------- child_summary = "" child_summary += f"สวัสดีหนูน้อยนักสำรวจ!\n\n" child_summary += f"**{planet_name_th}** ที่หนูสร้าง เป็น{planet_type_th} " child_summary += f"โคจรรอบดาวฤกษ์ **{star_type_en}**\n" child_summary += f"ระยะห่าง ~{distance_au} AU => ประเมินอุณหภูมิ ~{temp_c}°C\n" if temp_c < -20: child_summary += "หนาวจัดเลยทีเดียว!\n" elif temp_c > 35: child_summary += "ร้อนระอุทีเดียว!\n" else: child_summary += "อากาศดูพอเหมาะนะ!\n" child_summary += f"แรงโน้มถ่วง ~{g_approx}g" if g_approx < 0.5: child_summary += " (ลอยง่าย!)" elif g_approx > 1.5: child_summary += " (หนักเดินลำบาก!)" child_summary += "\n" child_summary += f"แกนเอียง {tilt_deg}° => " if tilt_deg > 45: child_summary += "ฤดูกาลแปรปรวนสุดขั้ว!\n" elif tilt_deg < 5: child_summary += "แทบไม่เปลี่ยนฤดูกาล\n" else: child_summary += "มีฤดูกาลตามองศาเอียง\n" child_summary += f"{describe_moons(moon_count)}\n" if moon_count > 2: child_summary += "น้ำขึ้นน้ำลงคงอลังการมาก\n" child_summary += f"ออกซิเจน ~{oxygen_percent}%\n" if oxygen_percent < 5: child_summary += "น้อยมาก ต้องใช้ชุดอวกาศเลย\n" elif oxygen_percent > 30: child_summary += "สูงมาก ระวังไฟติดง่ายนะ\n" child_summary += f"สิ่งมีชีวิต: **{life_th}**\n" child_summary += "ลองคิดดูสิว่าหน้าตาจะเป็นยังไง!\n\n" child_summary += "พร้อมลุยกันแล้วหรือยัง!?" # ----------------------------- # (B) รายละเอียด (ไทย) # ----------------------------- detail_th = ( f"ชื่อดาวเคราะห์(ไทย): {planet_name_th}\n" f"ประเภทดาวฤกษ์: {star_type_en}\n" f"ระยะ (AU): {distance_au}\n" f"ขนาด (เท่าโลก): {diameter_factor}\n" f"แกนเอียง: {tilt_deg}°\n" f"จำนวนดวงจันทร์: {moon_count}\n" f"เปอร์เซ็นต์ O2: {oxygen_percent}%\n" f"ชนิดดาวเคราะห์(ไทย): {planet_type_th}\n" f"สิ่งมีชีวิต(ไทย): {life_th}\n" f"อุณหภูมิ: ~{temp_c} °C\n" f"แรงโน้มถ่วง (สมมุติ): ~{g_approx} g\n" ) # ----------------------------- # (C) สร้าง Prompt อังกฤษ 3 แบบ # ----------------------------- # 1) แปลชื่อดาว, สิ่งมีชีวิต (เฉพาะ user input) ผ่านแคช planet_name_en = translate_th_to_en(planet_name_th) life_en = translate_th_to_en(life_th) # 2) อธิบาย distance/temp/gravity/tilt/moon/oxygen เป็นภาษาไทย -> แปลเป็น EN จาก Dictionary dist_desc_th = describe_distance(distance_au) temp_desc_th = describe_temp(temp_c) grav_desc_th = describe_gravity(g_approx) tilt_desc_th = describe_tilt(tilt_deg) moon_desc_th = describe_moons(moon_count) o2_desc_th = describe_oxygen(oxygen_percent) # แปลงผ่าน Dictionary dist_desc_en = describe_distance_th_to_en(dist_desc_th) temp_desc_en = describe_temp_th_to_en(temp_desc_th) grav_desc_en = describe_gravity_th_to_en(grav_desc_th) tilt_desc_en = describe_tilt_th_to_en(tilt_desc_th) moon_desc_en = describe_moons_th_to_en(moon_desc_th) oxygen_desc_en = describe_oxygen_th_to_en(o2_desc_th) # 3) สร้าง Prompt prompt1, prompt2, prompt3 = build_prompts_en( planet_name_en, star_type_en, dist_desc_en, temp_desc_en, grav_desc_en, tilt_desc_en, moon_desc_en, oxygen_desc_en, life_en ) return child_summary, detail_th, prompt1, prompt2, prompt3 ################################### # สูตรโชว์ ################################### formula_text = r""" **สูตรอุณหภูมิ (Stefan-Boltzmann) แบบง่าย** \\[ T = \left(\frac{(1 - A) \times L}{16 \pi \sigma \, d^2}\right)^{\frac{1}{4}} - 273.15 + 15^\circ\text{C (Greenhouse)} \\] - \\(A\\) = Albedo - \\(L\\) = ความสว่างของดาว (W) - \\(\sigma\\) = 5.67\\times10^{-8} - \\(d\\) = ระยะทาง (m) **สูตรแรงโน้มถ่วงนิวตัน** \\(g = \frac{G M}{R^2}\\) (เราใช้สมมุติว่า \\(M \propto R^3\\) => \\(g \propto R\\)) """ ################################### # สร้าง UI ด้วย Gradio ################################### css_code = """ body { background-color: #F9FBFF !important; font-family: "Kanit", sans-serif; } #title { color: #4A90E2 !important; text-align: center; font-size: 2rem; margin-top: 20px; margin-bottom: 10px; font-weight: bold; } .game-desc { margin: 0 auto; width: 90%; background-color: #ECF6FF !important; border: 2px dashed #B3DAFF !important; border-radius: 10px; padding: 15px; color: #333333 !important; margin-bottom: 20px; } /* เพิ่มกฎสำหรับแท็ก

ภายใน .game-desc */ .game-desc p { color: #000000 !important; /* เปลี่ยนเป็นสีดำ */ } /* กำหนดสีสำหรับข้อความภายใน , , และ ภายใน .game-desc */ .game-desc strong, .game-desc em, .game-desc span { color: #000000 !important; /* เปลี่ยนเป็นสีดำ */ } .btn-main { background-color: #FFE066 !important; border: 2px solid #FFCA28 !important; font-weight: bold; font-size: 1.1rem; padding: 10px 30px; border-radius: 10px; margin-right: 10px; color: #000000 !important; /* เพิ่มสีข้อความให้เข้ม */ } #child-summary, #detail-th, #prompt1-en, #prompt2-en, #prompt3-en, #formula-box { background-color: #FFFDF5 !important; border: 2px solid #FFE082 !important; border-radius: 10px; padding: 10px; margin-bottom: 20px; color: #333333 !important; /* เพิ่มสีข้อความให้เข้ม */ } .copy-btn { background-color: #F06292 !important; border: 2px solid #E91E63 !important; font-weight: bold; font-size: 0.8rem; padding: 5px 10px; border-radius: 5px; margin-top: 5px; color: #FFFFFF !important; /* สีข้อความของปุ่มคัดลอก */ } /* เพิ่มกฎสำหรับข้อความภายใน .game-desc ที่อาจถูกตั้งค่าโดยธีม */ .game-desc * { color: #000000 !important; /* เปลี่ยนเป็นสีดำ */ } """ def show_formula(state): new_state = not state return new_state, gr.update(visible=new_state) def welcome_text(): return "ยินดีต้อนรับสู่ **ZenityX Planetary Adventure**! ลองกรอกข้อมูลแล้วกด 'สร้างโลกแฟนตาซี' สิ!" with gr.Blocks(css=css_code) as demo: gr.Markdown("

ZenityX Planetary Adventure

") gr.Markdown("""

พัฒนาโดย สถาบัน ZenityX AI Studio

สร้างโลกแฟนตาซีของตัวเองด้วยการกรอกข้อมูลด้านล่าง! แล้วมาสนุกกับการสำรวจโลกใหม่กันเถอะ!

ใส่ข้อมูล แล้วกด "สร้างโลกแฟนตาซี" เพื่อดู สรุปสำหรับเด็ก, รายละเอียด (ไทย), และ 3 Prompts อังกฤษ

ถ้าต้องการดูสูตรคำนวณ กดปุ่ม "โชว์สูตรคำนวณ" ได้เลย!

""") formula_state = gr.State(value=False) formula_md = gr.Markdown(formula_text, visible=False, elem_id="formula-box") show_formula_btn = gr.Button("โชว์สูตรคำนวณ") show_formula_btn.click(fn=show_formula, inputs=formula_state, outputs=[formula_state, formula_md]) with gr.Row(): with gr.Column(): planet_name_th = gr.Textbox(label="ชื่อดาวเคราะห์ (ไทย)", placeholder="เช่น ดาวซานาดา, ดาวโซลาริส...") star_type_en = gr.Dropdown( label="ประเภทดาวฤกษ์", choices=["Red Dwarf", "White Dwarf", "Sun-like", "Blue Giant", "Supergiant"], value="Sun-like" ) distance_au = gr.Textbox(label="ระยะห่าง (AU)", placeholder="เช่น 1, 0.5, 2...") diameter_factor = gr.Textbox(label="ขนาด (เท่าโลก)", placeholder="เช่น 1, 2, 0.5...") planet_type_th = gr.Dropdown( label="ชนิดดาวเคราะห์ (ไทย)", choices=["ดาวหิน", "ดาวก๊าซ", "ดาวน้ำแข็ง"], value="ดาวหิน" ) with gr.Column(): tilt_slider = gr.Slider(0, 90, step=1, value=23.5, label="แกนเอียง (องศา)") moon_slider = gr.Slider(0, 10, step=1, value=1, label="จำนวนดวงจันทร์") oxygen_slider = gr.Slider(0, 100, step=1, value=21, label="% ออกซิเจน") life_th = gr.Textbox(label="สิ่งมีชีวิต (ไทย)", placeholder="เช่น แมลงยักษ์เรืองแสง...") create_btn = gr.Button("สร้างโลกแฟนตาซี", elem_classes="btn-main") child_summary_out = gr.Textbox(label="สรุปสำหรับเด็ก (ไทย)", interactive=False, elem_id="child-summary") detail_th_out = gr.Textbox(label="รายละเอียด (ไทย)", interactive=False, elem_id="detail-th") prompt1_en_out = gr.Textbox(label="Prompt #1 (English)", interactive=False, elem_id="prompt1-en") prompt2_en_out = gr.Textbox(label="Prompt #2 (English)", interactive=False, elem_id="prompt2-en") prompt3_en_out = gr.Textbox(label="Prompt #3 (English)", interactive=False, elem_id="prompt3-en") # ฟังก์ชันคัดลอก Prompt copy_button_html = """
""" gr.HTML(copy_button_html) def generate_wrapper( p_name_th, s_type_en, dist_au, dia_fac, tilt_val, moon_val, oxy_val, p_type_th, l_th ): return generate_planet_info( planet_name_th=p_name_th, star_type_en=s_type_en, distance_str=dist_au, diameter_str=dia_fac, tilt_value=str(tilt_val), moon_value=str(moon_val), oxygen_percent=oxy_val, planet_type_th=p_type_th, life_th=l_th ) create_btn.click( fn=generate_wrapper, inputs=[ planet_name_th, star_type_en, distance_au, diameter_factor, tilt_slider, moon_slider, oxygen_slider, planet_type_th, life_th ], outputs=[ child_summary_out, detail_th_out, prompt1_en_out, prompt2_en_out, prompt3_en_out ] ) demo.load(fn=welcome_text, inputs=None, outputs=child_summary_out) demo.launch()