Spaces:
Sleeping
Sleeping
import os | |
import time | |
import gradio as gr | |
from gtts import gTTS | |
import hashlib # π΅ νμΌλͺ μ κ³ μ νκ² νκΈ° μν΄ μΆκ° | |
# μμ±λ μ€λμ€ νμΌμ μ¬μ¬μ©νκΈ° μν μΊμ λμ λ리 | |
cached_audio = {} | |
# π λ¨λͺ¨μ(Short Vowel) μ€ν 리 λ°μ΄ν° (ν μ€νΈ + μ΄λ―Έμ§ URL ν¬ν¨) | |
image_base_url = "https://huggingface.co/spaces/englissi/englishstories/resolve/main/image/" | |
short_vowel_stories = [ | |
{"text": "Sam has a cat.", "image": f"{image_base_url}1.webp"}, | |
{"text": "The cat is fat and tan.", "image": f"{image_base_url}2.webp"}, | |
{"text": "Sam and the cat nap on a mat.", "image": f"{image_base_url}3.webp"}, | |
{"text": "Ben has a red pen.", "image": f"{image_base_url}4.webp"}, | |
{"text": "He pets a hen in a den.", "image": f"{image_base_url}5.webp"}, | |
{"text": "Tim sits and grins.", "image": f"{image_base_url}6.webp"}, | |
{"text": "A big pig digs in the mud.", "image": f"{image_base_url}7.webp"}, | |
{"text": "Dot the dog jogs and hops.", "image": f"{image_base_url}8.webp"}, | |
{"text": "Gus the pup has a cup.", "image": f"{image_base_url}9.webp"}, | |
{"text": "Fun in the sun is the best!", "image": f"{image_base_url}10.webp"} | |
] | |
# π μ₯λͺ¨μ(Long Vowel) μ€ν 리 λ°μ΄ν° | |
long_vowel_stories = [ | |
{"text": "Kate ate a big cake.", "image": f"{image_base_url}11.webp"}, | |
{"text": "The train is late today.", "image": f"{image_base_url}12.webp"}, | |
{"text": "I see a green tree.", "image": f"{image_base_url}13.webp"}, | |
{"text": "He likes to read a book.", "image": f"{image_base_url}14.webp"}, | |
{"text": "The kite is flying high.", "image": f"{image_base_url}15.webp"}, | |
{"text": "The light is very bright.", "image": f"{image_base_url}16.webp"}, | |
{"text": "The rose is red.", "image": f"{image_base_url}17.webp"}, | |
{"text": "We saw a boat on the lake.", "image": f"{image_base_url}18.webp"}, | |
{"text": "He is cute and kind.", "image": f"{image_base_url}19.webp"}, | |
{"text": "A baby bird flew away.", "image": f"{image_base_url}20.webp"} | |
] | |
# π Blends & Digraphs μ€ν 리 λ°μ΄ν° | |
blends_digraphs_stories = [ | |
{"text": "Blake blows a blue blimp.", "image": f"{image_base_url}21.webp"}, | |
{"text": "Brad brings a brown brush.", "image": f"{image_base_url}22.webp"}, | |
{"text": "The clock clicks and claps.", "image": f"{image_base_url}23.webp"}, | |
{"text": "Crispy crackers crunch.", "image": f"{image_base_url}24.webp"}, | |
{"text": "A frog frogs on a free log.", "image": f"{image_base_url}25.webp"}, | |
{"text": "Green grapes grow big.", "image": f"{image_base_url}26.webp"}, | |
{"text": "The train trips on tracks.", "image": f"{image_base_url}27.webp"}, | |
{"text": "The ship shines in the sun.", "image": f"{image_base_url}28.webp"}, | |
{"text": "Chip and cheese are on my chin.", "image": f"{image_base_url}29.webp"}, | |
{"text": "The thumb is thick.", "image": f"{image_base_url}30.webp"}, | |
{"text": "White whales whisper.", "image": f"{image_base_url}31.webp"}, | |
{"text": "A skunk skips sky-high.", "image": f"{image_base_url}32.webp"}, | |
{"text": "The sleepy sloth slides.", "image": f"{image_base_url}33.webp"}, | |
{"text": "Small smiles smell sweet.", "image": f"{image_base_url}34.webp"}, | |
{"text": "The snail snaps a snack.", "image": f"{image_base_url}35.webp"}, | |
{"text": "The spider spins a spotty web.", "image": f"{image_base_url}36.webp"}, | |
{"text": "The star stands in the storm.", "image": f"{image_base_url}37.webp"}, | |
{"text": "A swan swims in the sweet lake.", "image": f"{image_base_url}38.webp"} | |
] | |
# π "The Red Ball" μ€ν 리 λ°μ΄ν° | |
the_red_ball_story = [ | |
{"text": "Tom has a red ball. He throws the ball up. The ball goes high. Then it falls down!", "image": f"{image_base_url}39.webp"} | |
] | |
# π "The Big Cat" μ€ν 리 λ°μ΄ν° | |
the_big_cat_story = [ | |
{"text": "The cat is big. It jumps on the mat. The mat is soft. The cat takes a nap.", "image": f"{image_base_url}40.webp"} | |
] | |
# π "The Hot Sun" μ€ν 리 λ°μ΄ν° | |
the_hot_sun_story = [ | |
{"text": "The sun is hot. I wear my hat. I drink some water. Now I feel cool!", "image": f"{image_base_url}41.webp"} | |
] | |
# π gTTSλ₯Ό μ΄μ©ν΄ μ€λμ€ νμΌμ μμ±νκ±°λ, μ΄λ―Έ μμΌλ©΄ μ¬μ¬μ© | |
def generate_audio(text): | |
try: | |
# μ΄λ―Έ μμ±λ μμ±μ΄ μμΌλ©΄ μ¬μ¬μ© (429 μ€λ₯ λ°©μ§) | |
if text in cached_audio: | |
return cached_audio[text] | |
# κ³ μ ν νμΌλͺ μμ± (ν΄μ μ 10μ리 μ¬μ©) | |
hash_key = hashlib.md5(text.encode()).hexdigest()[:10] | |
filename = f"audio_{hash_key}.mp3" | |
# gTTSλ₯Ό μ¬μ©νμ¬ μμ± μμ± | |
tts = gTTS(text=text, lang="en") | |
tts.save(filename) | |
# μ λ κ²½λ‘λ‘ λ³ν | |
abs_filename = os.path.abspath(filename) | |
print(f"β μμ± νμΌ μμ± μλ£: {abs_filename}") | |
# μμ±λ νμΌ κ²½λ‘ μΊμ± | |
cached_audio[text] = abs_filename | |
# API μμ² μ νμ νΌνκΈ° μν΄ 1.5μ΄ λκΈ° | |
time.sleep(1.5) | |
return abs_filename | |
except Exception as e: | |
print(f"β οΈ μμ± μμ± μ€ν¨: {e}") | |
return None | |
# π "λ€μ" λ²νΌ ν΄λ¦ μ νΈμΆλλ ν¨μ (HTML ν¬ν¨) | |
def next_story(current_index, story_list): | |
new_index = (current_index + 1) % len(story_list) | |
story = story_list[new_index] | |
text_html = f"<div class='story-text'>{story['text']}</div>" | |
image = story["image"] | |
audio_file = generate_audio(story["text"]) | |
return new_index, text_html, image, audio_file, story["text"] | |
# π "μ¬μ" λ²νΌ ν΄λ¦ μ νΈμΆλλ ν¨μ | |
def play_story(current_text): | |
return generate_audio(current_text) | |
# π μ΄κΈ° κ° μ€μ | |
init_index_short = 0 | |
init_text_short = short_vowel_stories[0]["text"] | |
init_image_short = short_vowel_stories[0]["image"] | |
init_audio_short = generate_audio(init_text_short) | |
init_index_long = 0 | |
init_text_long = long_vowel_stories[0]["text"] | |
init_image_long = long_vowel_stories[0]["image"] | |
init_audio_long = generate_audio(init_text_long) | |
init_index_blends = 0 | |
init_text_blends = blends_digraphs_stories[0]["text"] | |
init_image_blends = blends_digraphs_stories[0]["image"] | |
init_audio_blends = generate_audio(init_text_blends) | |
the_red_ball_index = 0 | |
the_red_ball_text = the_red_ball_story[0]["text"] | |
the_red_ball_image = the_red_ball_story[0]["image"] | |
the_red_ball_audio = generate_audio(the_red_ball_text) | |
the_big_cat_index = 0 | |
the_big_cat_text = the_big_cat_story[0]["text"] | |
the_big_cat_image = the_big_cat_story[0]["image"] | |
the_big_cat_audio = generate_audio(the_big_cat_text) | |
the_hot_sun_index = 0 | |
the_hot_sun_text = the_hot_sun_story[0]["text"] | |
the_hot_sun_image = the_hot_sun_story[0]["image"] | |
the_hot_sun_audio = generate_audio(the_hot_sun_text) | |
# π Gradio UI κ΅¬μ± | |
with gr.Blocks(title="π κ·μ¬μ΄ μ€ν 리 μ±") as demo: | |
gr.HTML(""" | |
<style> | |
body { | |
background-color: #FFFAF0; | |
font-family: 'Comic Sans MS', cursive, sans-serif; | |
} | |
h1 { | |
color: #FF6347; | |
text-align: center; | |
font-size: 3em; | |
font-weight: bold; | |
margin-top: 20px; | |
} | |
p { | |
text-align: center; | |
font-size: 1.2em; | |
color: #6B4226; | |
} | |
.story-text { | |
font-size: 2.5em; | |
font-weight: bold; | |
text-align: center; | |
color: #FF4500; | |
padding: 20px; | |
border-radius: 15px; | |
background: #FFF3E0; | |
display: inline-block; | |
box-shadow: 4px 4px 10px rgba(0,0,0,0.2); | |
} | |
</style> | |
""") | |
gr.HTML("<h1>π μ¬λ―Έμλ μμ΄ μ€ν 리 νμ! π</h1>") | |
gr.HTML("<p>π± κ·μ¬μ΄ μ΄μΌκΈ°μ ν¨κ» μμ΄λ₯Ό λ°°μ보μμ! π΅</p>") | |
with gr.Tabs(): | |
for story_name, story_data in [ | |
("Short Vowel", short_vowel_stories), | |
("Long Vowel", long_vowel_stories), | |
("Blends & Digraphs", blends_digraphs_stories), | |
("The Red Ball", the_red_ball_story), | |
("The Big Cat", the_big_cat_story), | |
("The Hot Sun", the_hot_sun_story) | |
]: | |
with gr.TabItem(story_name): | |
state_index = gr.State(value=0) | |
state_text = gr.State(value=story_data[0]["text"]) | |
story_text = gr.HTML(value=f"<div class='story-text'>{story_data[0]['text']}</div>") | |
story_image = gr.Image(value=story_data[0]["image"], width=300, height=300) | |
audio_output = gr.Audio(value=generate_audio(story_data[0]["text"]), autoplay=False) | |
with gr.Row(): | |
next_button = gr.Button("π λ€μ μ΄μΌκΈ°", elem_classes=["btn-custom", "next-btn"]) | |
play_button = gr.Button("π λ€μ λ£κΈ°", elem_classes=["btn-custom", "play-btn"]) | |
next_button.click( | |
fn=next_story, | |
inputs=[state_index, gr.State(value=story_data)], | |
outputs=[state_index, story_text, story_image, audio_output, state_text] | |
) | |
play_button.click( | |
fn=play_story, | |
inputs=[state_text], | |
outputs=[audio_output] | |
) | |
# π μ± μ€ν | |
demo.launch() | |