zenityx's picture
Update app.py
e7c2a53 verified
raw
history blame
19.3 kB
import math
import gradio as gr
from transformers import MarianMTModel, MarianTokenizer
import torch
##############################################
# 1) โหลดโมเดล MarianMT สำหรับแปลไทย->อังกฤษ
##############################################
model_name = "Helsinki-NLP/opus-mt-th-en"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)
def translate_th_to_en(text_th: str) -> str:
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 (Stefan-Boltzmann) + Greenhouse เบื้องต้น
##############################################
def approximate_temp_with_star(star_type, distance_au, albedo=0.3):
"""
คำนวณอุณหภูมิพื้นผิว (°C) อย่างง่าย โดยอิง Black Body + star luminosity
- star_type:
"Red Dwarf" -> luminosity ~0.02 เท่าดวงอาทิตย์
"Sun-like" -> luminosity = 1 เท่าดวงอาทิตย์
"Blue Giant"-> luminosity ~10 เท่าดวงอาทิตย์ (สมมุติ)
- distance_au: ระยะห่างหน่วย AU
- albedo: สัดส่วนสะท้อนแสง (สมมุติ 0.3)
- สุดท้ายบวก greenhouse effect ~ +15 °C (สมมุติ)
"""
if star_type == "Red Dwarf":
lum_ratio = 0.02 # สมมุติ
elif star_type == "Blue Giant":
lum_ratio = 10.0
else: # Sun-like
lum_ratio = 1.0
# ความสว่างของดวงอาทิตย์ ~3.828e26 W
luminosity = 3.828e26 * lum_ratio
# แปลง AU -> เมตร
dist_m = distance_au * 1.496e11
sigma = 5.67e-8 # Stefan-Boltzmann constant
# T(K) = [ ( (1 - A) * L ) / (16*pi*sigma * d^2 ) ]^(1/4)
T_k = ((1 - albedo) * luminosity / (16 * math.pi * sigma * dist_m**2))**0.25
T_c = T_k - 273.15
# บวก greenhouse เล็กน้อย
T_c += 15
return round(T_c)
def approximate_gravity(diameter_factor):
"""
สมมุติว่า แรงโน้มถ่วง ~ diameter_factor เท่าของโลก
(จริงๆ เกี่ยวกับความหนาแน่นด้วย แต่เอาแบบง่าย)
"""
return round(diameter_factor, 2)
##############################################
# 3) ฟังก์ชันแปลงตัวเลข -> คำบรรยายเชิงเปรียบเทียบ
##############################################
def describe_distance(distance_au):
"""
ตีความระยะห่าง (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):
"""
ตีความอุณหภูมิ (°C) เป็นคำบรรยาย
"""
if temp_c < -30:
return "อากาศหนาวแข็ง"
elif temp_c < 10:
return "อากาศค่อนข้างเย็น"
elif temp_c < 35:
return "อากาศกำลังสบาย"
else:
return "ร้อนระอุ"
def describe_gravity(g):
"""
ตีความแรงโน้มถ่วง (g) เป็นคำบรรยาย
"""
if g < 0.5:
return "โน้มถ่วงเบามาก (ตัวลอยได้ง่าย)"
elif g < 1.2:
return "คล้ายโลก"
elif g < 2.0:
return "ค่อนข้างหนัก"
else:
return "หนักมากจนอาจกดทับทุกสิ่ง"
def describe_tilt(tilt_deg):
"""
ตีความแกนเอียง
"""
tilt = float(tilt_deg)
if tilt < 5:
return "แทบไม่เอียง ฤดูกาลเรียบง่าย"
elif tilt < 25:
return "เอียงเล็กน้อย มีฤดูกาลพอประมาณ"
elif tilt < 45:
return "เอียงปานกลาง ฤดูกาลค่อนข้างเปลี่ยนแปลง"
else:
return "เอียงมาก ฤดูกาลสุดขั้ว"
def describe_moons(n):
"""
ตีความจำนวนดวงจันทร์
"""
n = int(n)
if n == 0:
return "ไม่มีดวงจันทร์"
elif n == 1:
return "มีดวงจันทร์หนึ่งดวง"
else:
return f"มีดวงจันทร์ {n} ดวง"
##############################################
# 4) สร้าง prompt 3 แบบ (ไม่มีตัวเลขตรงๆ)
##############################################
def build_prompts_en(planet_name_en, star_type_en, distance_desc_en,
temp_desc_en, gravity_desc_en, tilt_desc_en,
moon_desc_en, oxygen_desc_en, life_en):
"""
สร้าง 3 prompts ภาษาอังกฤษ โดยไม่ใส่ตัวเลขตรงๆ
แต่ใช้คำบรรยายเชิงเปรียบเทียบ
"""
# Prompt 1: ภาพดาวจากอวกาศ
prompt1 = (
f"A stunning space illustration of planet '{planet_name_en}' orbiting a {star_type_en} star. "
f"It is {distance_desc_en}, with {temp_desc_en} climate and {gravity_desc_en} surface gravity. "
f"{tilt_desc_en}, and {moon_desc_en}. Atmosphere containing {oxygen_desc_en}, truly fascinating."
)
# Prompt 2: สิ่งมีชีวิต
prompt2 = (
f"Alien life on planet '{planet_name_en}': {life_en}, "
f"thriving under {temp_desc_en} conditions, {gravity_desc_en} gravity, and {oxygen_desc_en} in the air. "
f"Highly imaginative, concept art style, fantasy world."
)
# Prompt 3: พื้นผิวดาว
prompt3 = (
f"The planet '{planet_name_en}' has a surface with {temp_desc_en} weather, {gravity_desc_en}, "
f"{tilt_desc_en}, and {moon_desc_en}. An epic terrain, atmospheric glow, and {oxygen_desc_en} presence. "
f"Realistic space painting, cinematic lighting."
)
prompt_all = (
"--- Prompt #1 ---\n" + prompt1 + "\n\n"
"--- Prompt #2 ---\n" + prompt2 + "\n\n"
"--- Prompt #3 ---\n" + prompt3 + "\n"
)
return prompt_all
##############################################
# 5) ฟังก์ชันหลัก generate_planet_info
##############################################
def generate_planet_info(
planet_name_th,
star_type_en_select, # ("Red Dwarf", "Sun-like", "Blue Giant")
distance_str,
diameter_str,
tilt_str,
moon_str,
oxygen_percent,
planet_type_th, # ("ดาวหิน", "ดาวก๊าซ", "ดาวน้ำแข็ง")
life_th
):
# แปลง string -> float/int
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_str)
except:
tilt_deg = 23.5
try:
num_moon = int(moon_str)
except:
num_moon = 1
# 1) คำนวณอุณหภูมิ (°C)
temp_c = approximate_temp_with_star(star_type_en_select, distance_au)
# 2) คำนวณแรงโน้มถ่วง
g_approx = approximate_gravity(diameter_factor)
# 3) สร้าง “สรุปสำหรับเด็ก” (ภาษาไทย)
# โดยยังไม่ได้รวม star_type_en_select เพราะเป็นภาษาอังกฤษ
# แต่เราจะใช้ planet_type_th ด้วย
# สมมุติ child_friendly_summary:
# => โชว์ temp, g, oxygen, life
child_summary = (
f"ดาว {planet_name_th} เป็น{planet_type_th} "
f"โคจรรอบดาวฤกษ์ประเภท {star_type_en_select} (อิงวิทยาศาสตร์สมมุติ)\n"
f"อุณหภูมิประมาณ {temp_c}°C, "
f"แรงโน้มถ่วง ~{g_approx}g, ออกซิเจน ~{oxygen_percent}%, "
f"แกนเอียง {tilt_deg}°, {num_moon} ดวงจันทร์,\n"
f"มีสิ่งมีชีวิต: {life_th}\n"
f"น่าอัศจรรย์จริง ๆ!"
)
# 4) รายละเอียดเชิงเทคนิค (ไทย)
detail_th = (
f"ชื่อดาวเคราะห์ (ไทย): {planet_name_th}\n"
f"ประเภทดาวฤกษ์: {star_type_en_select}\n"
f"ระยะห่าง: ~{distance_au} AU\n"
f"ขนาดเส้นผ่านศูนย์กลาง: ~{diameter_factor} เท่าโลก\n"
f"แกนเอียง: ~{tilt_deg}°\n"
f"จำนวนดวงจันทร์: {num_moon}\n"
f"อุณหภูมิคำนวณ: ~{temp_c} °C\n"
f"แรงโน้มถ่วง: ~{g_approx} g\n"
f"ออกซิเจน: {oxygen_percent}%\n"
f"ชนิดดาวเคราะห์ (ไทย): {planet_type_th}\n"
f"สิ่งมีชีวิต (ไทย): {life_th}\n"
)
# 5) แปล planet_name_th -> English
planet_name_en = translate_th_to_en(planet_name_th)
# แปล life_th -> อังกฤษ
life_en = translate_th_to_en(life_th)
# แมป planet_type_th -> Eng
# (ดาวหิน -> rocky planet, ดาวก๊าซ -> gas giant, ดาวน้ำแข็ง -> icy planet)
type_map = {
"ดาวหิน": "rocky planet",
"ดาวก๊าซ": "gas giant",
"ดาวน้ำแข็ง": "icy planet"
}
# (กรณี user พิมพ์ว่า "ดาวหิน" หรือมีวงเล็บ อาจต้อง .replace ให้เคลียร์)
planet_type_key = planet_type_th.replace("(", "").replace(")", "").replace(" ", "").split("ดาว")[-1]
planet_type_key = planet_type_key.strip()
planet_type_en = type_map.get(planet_type_key, "unknown planet")
# 6) ตีความ distance, temp, gravity, tilt, moon, oxygen เพื่ออธิบายเป็นอังกฤษ (non-numeric)
# - distance
distance_desc_th = describe_distance(distance_au)
distance_desc_en = translate_th_to_en(distance_desc_th)
# - temp
temp_desc_th = describe_temp(temp_c)
temp_desc_en = translate_th_to_en(temp_desc_th)
# - gravity
gravity_desc_th = describe_gravity(g_approx)
gravity_desc_en = translate_th_to_en(gravity_desc_th)
# - tilt
tilt_desc_th = describe_tilt(tilt_deg)
tilt_desc_en = translate_th_to_en(tilt_desc_th)
# - moon
moon_desc_th = describe_moons(num_moon)
moon_desc_en = translate_th_to_en(moon_desc_th)
# - oxygen
# ถ้า oxygen 0 -> no oxygen
# oxygen < 5 -> extremely low oxygen
# etc.
if oxygen_percent < 1:
oxygen_desc_th = "ไม่มีออกซิเจน"
elif oxygen_percent < 10:
oxygen_desc_th = "ออกซิเจนจางมาก"
elif oxygen_percent < 25:
oxygen_desc_th = "ออกซิเจนพอเหมาะ"
else:
oxygen_desc_th = "ออกซิเจนสูง"
oxygen_desc_en = translate_th_to_en(oxygen_desc_th)
# 7) สร้าง 3 Prompts (English)
prompt_all = build_prompts_en(
planet_name_en,
f"{star_type_en_select} star", # e.g. "Red Dwarf star"
distance_desc_en,
temp_desc_en,
gravity_desc_en,
tilt_desc_en,
moon_desc_en,
oxygen_desc_en,
life_en
)
return child_summary, detail_th, prompt_all
##############################################
# 6) สร้าง UI (Gradio)
##############################################
css_code = """
body {
background-color: #F9FBFF;
font-family: "Kanit", sans-serif;
}
#title {
color: #4A90E2;
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;
border: 2px dashed #B3DAFF;
border-radius: 10px;
padding: 15px;
color: #333;
margin-bottom: 20px;
}
.btn-main {
background-color: #FFE066;
border: 2px solid #FFCA28;
font-weight: bold;
font-size: 1.1rem;
padding: 10px 30px;
border-radius: 10px;
margin-right: 10px;
}
#child-summary, #detail-th, #prompt-en {
background-color: #FFFDF5;
border: 2px solid #FFE082;
border-radius: 10px;
padding: 10px;
margin-bottom: 20px;
}
"""
def welcome_text():
return "ยินดีต้อนรับสู่ Planetary Adventure+! ลองกรอกข้อมูลแล้วกด 'สร้างโลกแฟนตาซี' กันนะจ๊ะ"
copy_button_html = """
<button style="background-color: #F06292; border: 2px solid #E91E63; font-weight: bold;
font-size: 1.0rem; padding: 8px 20px; border-radius: 10px;"
onclick="copyPromptText()">
คัดลอก Prompt
</button>
<script>
function copyPromptText() {
const promptBox = document.querySelector('#prompt-en textarea');
if (!promptBox) {
alert('ไม่พบข้อความ Prompt!');
return;
}
const promptText = promptBox.value;
navigator.clipboard.writeText(promptText);
alert('คัดลอก Prompt แล้ว! นำไปใช้ใน AI สร้างภาพได้เลย~');
}
</script>
"""
import re
with gr.Blocks(css=css_code) as demo:
gr.Markdown("<h1 id='title'>Planetary Adventure (Advanced) - Thai Input + Real Sci + No Direct Numbers</h1>")
gr.Markdown("""
<div class="game-desc">
<p>สร้างดาวเคราะห์พร้อมหลักวิทยาศาสตร์เบื้องต้น (สูตร Stefan-Boltzmann) และใช้การแปล MarianMT</p>
<ol>
<li>กรอกชื่อดาวเคราะห์ (ภาษาไทย)</li>
<li>เลือกชนิดดาวฤกษ์ (Red Dwarf / Sun-like / Blue Giant)</li>
<li>กรอกระยะห่าง (หน่วย AU), ขนาดเท่าโลก, แกนเอียง, จำนวนดวงจันทร์, % ออกซิเจน</li>
<li>ระบุประเภทดาวเคราะห์ (ไทย) เช่น "ดาวหิน", "ดาวก๊าซ", "ดาวน้ำแข็ง"</li>
<li>พิมพ์สิ่งมีชีวิต (ไทย)</li>
<li>กดปุ่ม <strong>"สร้างโลกแฟนตาซี"</strong></li>
</ol>
<p>ระบบจะ <em>คำนวณอุณหภูมิ</em>, <em>แรงโน้มถ่วง</em>, <em>ตีความเป็นคำบรรยาย</em>, และแปลไทย->อังกฤษ<br>
จากนั้นสร้าง <strong>3 prompts</strong> ที่เลี่ยงตัวเลขตรงๆ ใช้คำเปรียบเทียบแทน</p>
</div>
""")
planet_name_th = gr.Textbox(label="ชื่อดาวเคราะห์ (ภาษาไทย)", placeholder="ตัวอย่าง: ดาวซานาดา")
star_type_select = gr.Dropdown(
label="ประเภทดาวฤกษ์ (English)",
choices=["Red Dwarf", "Sun-like", "Blue Giant"],
value="Sun-like"
)
distance_au = gr.Textbox(label="ระยะห่างจากดาวฤกษ์ (AU)", placeholder="เช่น 1, 0.5, 2")
diameter_factor = gr.Textbox(label="ขนาด (เท่าโลก)", placeholder="เช่น 1, 2, 0.5")
tilt_deg = gr.Textbox(label="แกนเอียง (องศา)", placeholder="0-90")
moon_number = gr.Textbox(label="จำนวนดวงจันทร์", placeholder="0, 1, 2, ...")
oxygen_slider = gr.Slider(
minimum=0, maximum=100, step=1, value=21,
label="% ออกซิเจน (ในบรรยากาศ)"
)
planet_type_th = gr.Dropdown(
label="ชนิดดาวเคราะห์ (ไทย)",
choices=["ดาวหิน", "ดาวก๊าซ", "ดาวน้ำแข็ง"],
value="ดาวหิน"
)
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")
prompt_en_out = gr.Textbox(label="3 Prompts (English)", interactive=False, elem_id="prompt-en")
gr.HTML(copy_button_html)
create_btn.click(
fn=generate_planet_info,
inputs=[
planet_name_th, # text
star_type_select, # red dwarf / sun-like / blue giant
distance_au,
diameter_factor,
tilt_deg,
moon_number,
oxygen_slider,
planet_type_th, # "ดาวหิน", "ดาวก๊าซ", "ดาวน้ำแข็ง"
life_th
],
outputs=[
child_summary_out,
detail_th_out,
prompt_en_out
]
)
demo.load(fn=welcome_text, inputs=None, outputs=child_summary_out)
demo.launch()