Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -16,6 +16,12 @@ def img2text(url):
|
|
16 |
return text
|
17 |
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
# text2story
|
20 |
def text2story(text):
|
21 |
# Initialize the text generation pipeline
|
@@ -35,10 +41,10 @@ def text2story(text):
|
|
35 |
return story
|
36 |
|
37 |
|
38 |
-
def text2audio(text):
|
39 |
try:
|
40 |
-
# Create a gTTS object
|
41 |
-
tts = gTTS(text=text, lang=
|
42 |
# Save to BytesIO object
|
43 |
audio_bytes = io.BytesIO()
|
44 |
tts.write_to_fp(audio_bytes)
|
@@ -49,17 +55,18 @@ def text2audio(text):
|
|
49 |
'sampling_rate': 24000 # gTTS default sampling rate
|
50 |
}
|
51 |
except Exception as e:
|
52 |
-
st.error(f"
|
53 |
return None
|
54 |
|
55 |
|
56 |
# Apply custom CSS for modern, stylish kid-friendly UI
|
57 |
-
st.set_page_config(page_title="
|
58 |
|
59 |
st.markdown("""
|
60 |
<style>
|
61 |
/* Modern, stylish kid-friendly design */
|
62 |
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600;700&display=swap');
|
|
|
63 |
|
64 |
:root {
|
65 |
--primary-color: #6C63FF;
|
@@ -73,7 +80,7 @@ st.markdown("""
|
|
73 |
|
74 |
.stApp {
|
75 |
background: linear-gradient(135deg, #F4F9FF, #EEFAFF);
|
76 |
-
font-family: '
|
77 |
color: var(--text-dark);
|
78 |
}
|
79 |
|
@@ -85,7 +92,7 @@ st.markdown("""
|
|
85 |
|
86 |
/* Modern headers */
|
87 |
h1, h2, h3 {
|
88 |
-
font-family: '
|
89 |
font-weight: 700;
|
90 |
color: var(--primary-color);
|
91 |
}
|
@@ -125,7 +132,7 @@ st.markdown("""
|
|
125 |
|
126 |
/* Accent borders for stages */
|
127 |
.css-nahz7x, .css-ocqkz7, .css-4z1n4l {
|
128 |
-
border-left: 5px solid var(--primary-color) !important;
|
129 |
}
|
130 |
|
131 |
.css-1r6slb0, .css-1ubpcwi {
|
@@ -183,7 +190,7 @@ st.markdown("""
|
|
183 |
padding: 0.6rem 1.5rem !important;
|
184 |
font-size: 1.1rem !important;
|
185 |
font-weight: 600 !important;
|
186 |
-
font-family: '
|
187 |
transition: all 0.3s ease !important;
|
188 |
box-shadow: 0 5px 15px rgba(65, 184, 131, 0.3) !important;
|
189 |
}
|
@@ -243,14 +250,14 @@ st.markdown("""
|
|
243 |
</style>
|
244 |
""", unsafe_allow_html=True)
|
245 |
|
246 |
-
# App header
|
247 |
-
st.title("✨
|
248 |
-
st.markdown("<p class='subtitle'
|
249 |
unsafe_allow_html=True)
|
250 |
|
251 |
-
# File uploader
|
252 |
with st.container():
|
253 |
-
st.subheader("
|
254 |
uploaded_file = st.file_uploader("", key="upload")
|
255 |
|
256 |
if uploaded_file is not None:
|
@@ -263,42 +270,55 @@ if uploaded_file is not None:
|
|
263 |
|
264 |
# Stage 1: Image to Text
|
265 |
with st.container():
|
266 |
-
st.markdown("<h3><span class='stage-icon'>🔍</span>
|
267 |
scenario = img2text(uploaded_file.name)
|
268 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
|
270 |
# Stage 2: Text to Story
|
271 |
with st.container():
|
272 |
-
st.markdown("<h3><span class='stage-icon'>📝</span>
|
273 |
story = text2story(scenario)
|
274 |
-
|
|
|
|
|
|
|
|
|
|
|
275 |
|
276 |
# Stage 3: Story to Audio data
|
277 |
with st.container():
|
278 |
-
st.markdown("<h3><span class='stage-icon'>🔊</span>
|
279 |
-
|
|
|
|
|
280 |
|
281 |
-
# Play button
|
282 |
-
if st.button("🔊
|
283 |
if audio_data:
|
284 |
st.audio(audio_data['audio'],
|
285 |
format="audio/wav",
|
286 |
start_time=0,
|
287 |
sample_rate=audio_data['sampling_rate'])
|
288 |
else:
|
289 |
-
st.error("
|
290 |
|
291 |
# Cleanup: Remove the temporary file
|
292 |
if os.path.exists(uploaded_file.name):
|
293 |
os.remove(uploaded_file.name)
|
294 |
else:
|
295 |
-
# Welcome message
|
296 |
st.markdown("""
|
297 |
<div class="welcome-message">
|
298 |
<div class="welcome-icon">✨</div>
|
299 |
-
<h2
|
300 |
<p style="font-size: 1.2rem; color: #6B7897; max-width: 500px; margin: 0 auto 30px;">
|
301 |
-
|
302 |
</p>
|
303 |
<div>
|
304 |
<span class="emoji">🚀</span>
|
|
|
16 |
return text
|
17 |
|
18 |
|
19 |
+
# Translation function EN to ZH
|
20 |
+
def translate_to_chinese(text):
|
21 |
+
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-en-zh")
|
22 |
+
translation = translator(text)[0]["translation_text"]
|
23 |
+
return translation
|
24 |
+
|
25 |
# text2story
|
26 |
def text2story(text):
|
27 |
# Initialize the text generation pipeline
|
|
|
41 |
return story
|
42 |
|
43 |
|
44 |
+
def text2audio(text, lang='zh'):
|
45 |
try:
|
46 |
+
# Create a gTTS object with Chinese language
|
47 |
+
tts = gTTS(text=text, lang=lang)
|
48 |
# Save to BytesIO object
|
49 |
audio_bytes = io.BytesIO()
|
50 |
tts.write_to_fp(audio_bytes)
|
|
|
55 |
'sampling_rate': 24000 # gTTS default sampling rate
|
56 |
}
|
57 |
except Exception as e:
|
58 |
+
st.error(f"音頻製作出左問題: {str(e)}")
|
59 |
return None
|
60 |
|
61 |
|
62 |
# Apply custom CSS for modern, stylish kid-friendly UI
|
63 |
+
st.set_page_config(page_title="故事魔法", page_icon="✨", layout="wide")
|
64 |
|
65 |
st.markdown("""
|
66 |
<style>
|
67 |
/* Modern, stylish kid-friendly design */
|
68 |
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600;700&display=swap');
|
69 |
+
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+HK:wght@400;500;700&display=swap');
|
70 |
|
71 |
:root {
|
72 |
--primary-color: #6C63FF;
|
|
|
80 |
|
81 |
.stApp {
|
82 |
background: linear-gradient(135deg, #F4F9FF, #EEFAFF);
|
83 |
+
font-family: 'Noto Sans HK', sans-serif;
|
84 |
color: var(--text-dark);
|
85 |
}
|
86 |
|
|
|
92 |
|
93 |
/* Modern headers */
|
94 |
h1, h2, h3 {
|
95 |
+
font-family: 'Noto Sans HK', sans-serif;
|
96 |
font-weight: 700;
|
97 |
color: var(--primary-color);
|
98 |
}
|
|
|
132 |
|
133 |
/* Accent borders for stages */
|
134 |
.css-nahz7x, .css-ocqkz7, .css-4z1n4l {
|
135 |
+
border-left: it 5px solid var(--primary-color) !important;
|
136 |
}
|
137 |
|
138 |
.css-1r6slb0, .css-1ubpcwi {
|
|
|
190 |
padding: 0.6rem 1.5rem !important;
|
191 |
font-size: 1.1rem !important;
|
192 |
font-weight: 600 !important;
|
193 |
+
font-family: 'Noto Sans HK', sans-serif !important;
|
194 |
transition: all 0.3s ease !important;
|
195 |
box-shadow: 0 5px 15px rgba(65, 184, 131, 0.3) !important;
|
196 |
}
|
|
|
250 |
</style>
|
251 |
""", unsafe_allow_html=True)
|
252 |
|
253 |
+
# App header with Cantonese
|
254 |
+
st.title("✨ 故事魔法")
|
255 |
+
st.markdown("<p class='subtitle'>上載一張圖片,睇下佢點變成一個神奇嘅故事!</p>",
|
256 |
unsafe_allow_html=True)
|
257 |
|
258 |
+
# File uploader with Cantonese
|
259 |
with st.container():
|
260 |
+
st.subheader("揀一張靚相啦!")
|
261 |
uploaded_file = st.file_uploader("", key="upload")
|
262 |
|
263 |
if uploaded_file is not None:
|
|
|
270 |
|
271 |
# Stage 1: Image to Text
|
272 |
with st.container():
|
273 |
+
st.markdown("<h3><span class='stage-icon'>🔍</span> 圖片解讀中</h3>", unsafe_allow_html=True)
|
274 |
scenario = img2text(uploaded_file.name)
|
275 |
+
|
276 |
+
# Translate the caption to Chinese
|
277 |
+
scenario_zh = translate_to_chinese(scenario)
|
278 |
+
|
279 |
+
# Display Chinese caption
|
280 |
+
st.text("中文描述:")
|
281 |
+
st.text(scenario_zh)
|
282 |
|
283 |
# Stage 2: Text to Story
|
284 |
with st.container():
|
285 |
+
st.markdown("<h3><span class='stage-icon'>📝</span> 故事創作中</h3>", unsafe_allow_html=True)
|
286 |
story = text2story(scenario)
|
287 |
+
# Translate the story to Chinese
|
288 |
+
story_zh = translate_to_chinese(story)
|
289 |
+
|
290 |
+
# Display Chinese story
|
291 |
+
st.text("中文故事:")
|
292 |
+
st.text(story_zh)
|
293 |
|
294 |
# Stage 3: Story to Audio data
|
295 |
with st.container():
|
296 |
+
st.markdown("<h3><span class='stage-icon'>🔊</span> 故事朗讀準備中</h3>", unsafe_allow_html=True)
|
297 |
+
|
298 |
+
# Create audio for Chinese story
|
299 |
+
audio_data = text2audio(story_zh, lang='zh')
|
300 |
|
301 |
+
# Play button with Cantonese text
|
302 |
+
if st.button("🔊 播放故事"):
|
303 |
if audio_data:
|
304 |
st.audio(audio_data['audio'],
|
305 |
format="audio/wav",
|
306 |
start_time=0,
|
307 |
sample_rate=audio_data['sampling_rate'])
|
308 |
else:
|
309 |
+
st.error("哎呀!聲音整唔到喎,再試多次啦!")
|
310 |
|
311 |
# Cleanup: Remove the temporary file
|
312 |
if os.path.exists(uploaded_file.name):
|
313 |
os.remove(uploaded_file.name)
|
314 |
else:
|
315 |
+
# Welcome message in Cantonese
|
316 |
st.markdown("""
|
317 |
<div class="welcome-message">
|
318 |
<div class="welcome-icon">✨</div>
|
319 |
+
<h2>歡迎嚟到故事魔法!</h2>
|
320 |
<p style="font-size: 1.2rem; color: #6B7897; max-width: 500px; margin: 0 auto 30px;">
|
321 |
+
上載一張你鍾意嘅相片,我哋嘅魔法師會幫你變出一個好好玩嘅故事!
|
322 |
</p>
|
323 |
<div>
|
324 |
<span class="emoji">🚀</span>
|