Spaces:
Sleeping
Sleeping
import os | |
import time | |
import gradio as gr | |
from gtts import gTTS | |
import hashlib # π΅ νμΌλͺ μ κ³ μ νκ² νκΈ° μν΄ μΆκ° | |
# π λ¨λͺ¨μ(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"} | |
] | |
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 | |
# μμ² μ νμ νΌνκΈ° μν΄ 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 = f"<div class='story-text'>{story['text']}</div>" | |
image = story["image"] | |
audio_file = generate_audio(story["text"]) | |
return new_index, text, image, audio_file, story["text"] | |
# π "μ¬μ" λ²νΌ ν΄λ¦ μ νΈμΆλλ ν¨μ (Gradio μ΅μ λ²μ μ λ§κ² μμ ) | |
def play_story(current_text): | |
return generate_audio(current_text) | |
# π μ΄κΈ° λ°μ΄ν° μ€μ | |
init_index_short, init_text_short, init_image_short, init_audio_short = 0, short_vowel_stories[0]["text"], short_vowel_stories[0]["image"], generate_audio(short_vowel_stories[0]["text"]) | |
init_index_long, init_text_long, init_image_long, init_audio_long = 0, long_vowel_stories[0]["text"], long_vowel_stories[0]["image"], generate_audio(long_vowel_stories[0]["text"]) | |
init_index_blends, init_text_blends, init_image_blends, init_audio_blends = 0, blends_digraphs_stories[0]["text"], blends_digraphs_stories[0]["image"], generate_audio(blends_digraphs_stories[0]["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: 2em; | |
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); | |
} | |
.btn-custom { | |
font-size: 1.5em; | |
font-weight: bold; | |
border-radius: 20px; | |
padding: 10px 20px; | |
margin: 5px; | |
border: none; | |
cursor: pointer; | |
box-shadow: 3px 3px 8px rgba(0,0,0,0.2); | |
} | |
.next-btn { | |
background-color: #FFD700; /* λ Έλμ λ²νΌ */ | |
} | |
.play-btn { | |
background-color: #90EE90; /* μ°ν μ΄λ‘μ λ²νΌ */ | |
} | |
.story-image img { | |
width: 300px !important; | |
height: 300px !important; | |
border-radius: 15px; | |
border: 5px solid #FFFFFF; | |
box-shadow: 4px 4px 10px rgba(0,0,0,0.2); | |
display: block; | |
margin: auto; | |
} | |
</style> | |
""") | |
gr.HTML("<h1>π μ¬λ―Έμλ μμ΄ μ€ν 리 νμ! π</h1>") | |
gr.HTML("<p>π± κ·μ¬μ΄ μ΄μΌκΈ°μ ν¨κ» μμ΄λ₯Ό λ°°μ보μμ! <br> λ²νΌμ λλ¬ λ€μ μ΄μΌκΈ°λ‘ λμ΄κ°κ³ , μμ±μ λ€μΌλ©° λ°λΌ μ½μ΄λ³΄μΈμ! π΅</p>") | |
with gr.Tabs(): | |
with gr.TabItem("Short Vowel (λ¨λͺ¨μ)"): | |
state_index_short = gr.State(value=init_index_short) | |
state_text_short = gr.State(value=init_text_short) | |
story_text_short = gr.HTML(value=f"<div class='story-text'>{init_text_short}</div>") | |
story_image_short = gr.Image(value=init_image_short, width=300, height=300) | |
audio_output_short = gr.Audio(value=init_audio_short, autoplay=False) | |
with gr.Row(): | |
next_button_short = gr.Button("π λ€μ μ΄μΌκΈ°", elem_classes=["btn-custom", "next-btn"]) | |
play_button_short = gr.Button("π λ€μ λ£κΈ°", elem_classes=["btn-custom", "play-btn"]) | |
next_button_short.click( | |
fn=next_story, | |
inputs=[state_index_short, gr.State(value=short_vowel_stories)], | |
outputs=[state_index_short, story_text_short, story_image_short, audio_output_short, state_text_short] | |
) | |
play_button_short.click( | |
fn=play_story, | |
inputs=[state_text_short], | |
outputs=[audio_output_short] | |
) | |
with gr.TabItem("Long Vowel (μ₯λͺ¨μ)"): | |
state_index_long = gr.State(value=init_index_long) | |
state_text_long = gr.State(value=init_text_long) | |
story_text_long = gr.HTML(value=f"<div class='story-text'>{init_text_long}</div>") | |
story_image_long = gr.Image(value=init_image_long, width=300, height=300) | |
audio_output_long = gr.Audio(value=init_audio_long, autoplay=False) | |
with gr.Row(): | |
next_button_long = gr.Button("π λ€μ μ΄μΌκΈ°", elem_classes=["btn-custom", "next-btn"]) | |
play_button_long = gr.Button("π λ€μ λ£κΈ°", elem_classes=["btn-custom", "play-btn"]) | |
next_button_long.click( | |
fn=next_story, | |
inputs=[state_index_long, gr.State(value=long_vowel_stories)], | |
outputs=[state_index_long, story_text_long, story_image_long, audio_output_long, state_text_long] | |
) | |
play_button_long.click( | |
fn=play_story, | |
inputs=[state_text_long], | |
outputs=[audio_output_long] | |
) | |
with gr.TabItem("Blends (μ΄μ€μμ)"): | |
state_index_blends = gr.State(value=init_index_blends) | |
state_text_blends = gr.State(value=init_text_blends) | |
story_text_blends = gr.HTML(value=f"<div class='story-text'>{init_text_blends}</div>") | |
story_image_blends = gr.Image(value=init_image_blends, width=300, height=300) | |
audio_output_blends = gr.Audio(value=init_audio_blends, autoplay=False) | |
with gr.Row(): | |
next_button_blends = gr.Button("π λ€μ μ΄μΌκΈ°", elem_classes=["btn-custom", "next-btn"]) | |
play_button_blends = gr.Button("π λ€μ λ£κΈ°", elem_classes=["btn-custom", "play-btn"]) | |
next_button_blends.click( | |
fn=next_story, | |
inputs=[state_index_blends, gr.State(value=blends_digraphs_stories)], | |
outputs=[state_index_blends, story_text_blends, story_image_blends, audio_output_blends, state_text_blends] | |
) | |
play_button_blends.click( | |
fn=play_story, | |
inputs=[state_text_blends], | |
outputs=[audio_output_blends] | |
) | |
# π μ± μ€ν | |
demo.launch() | |