Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -183,23 +183,15 @@ import gradio as gr
|
|
183 |
|
184 |
# ==== 静态资源 ====
|
185 |
background_images = [
|
186 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family.jpg"
|
187 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family1.jpg",
|
188 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family2.jpg",
|
189 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family3.jpg",
|
190 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family4.jpg",
|
191 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family5.jpg",
|
192 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family6.jpg",
|
193 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family7.jpg",
|
194 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family8.jpg",
|
195 |
-
"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family9.jpg"
|
196 |
]
|
197 |
-
#
|
198 |
background_css_rules = "".join([
|
199 |
f" {i * 10}% {{ background-image: url('{img}'); }}\n" for i, img in enumerate(background_images)
|
200 |
])
|
201 |
background_css = f"@keyframes backgroundCycle {{\n{background_css_rules}}}"
|
202 |
|
|
|
203 |
avatar_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/bean.jpg"
|
204 |
cake_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/birthday.jpg"
|
205 |
music1 = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/FNG.mp3"
|
@@ -207,163 +199,148 @@ music2 = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/PGY.mp3"
|
|
207 |
bark_sound = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/voice.mp3"
|
208 |
gift_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/gift.jpg"
|
209 |
popup_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/srkl.jpg"
|
|
|
210 |
|
211 |
-
# ==== HTML/CSS/JS
|
212 |
html_template = '''
|
213 |
<style>
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
animation: typewriter 1s steps(40, end);
|
231 |
-
}
|
232 |
-
@keyframes typewriter {
|
233 |
-
from { width: 0 }
|
234 |
-
to { width: 100% }
|
235 |
-
}
|
236 |
-
#sophia-avatar {
|
237 |
-
position: fixed;
|
238 |
-
top: 40px;
|
239 |
-
left: 30px;
|
240 |
-
width: 80px;
|
241 |
-
height: 80px;
|
242 |
-
border-radius: 50%;
|
243 |
-
z-index: 9999;
|
244 |
-
cursor: grab;
|
245 |
-
animation: spinBounce 4s infinite;
|
246 |
-
}
|
247 |
-
@keyframes spinBounce {
|
248 |
-
0% { transform: rotate(0deg) translateY(0); }
|
249 |
-
50% { transform: rotate(180deg) translateY(-10px); }
|
250 |
-
100% { transform: rotate(360deg) translateY(0); }
|
251 |
-
}
|
252 |
-
#birthday-cake {
|
253 |
-
position: fixed;
|
254 |
-
bottom: 20px;
|
255 |
-
right: 20px;
|
256 |
-
width: 80px;
|
257 |
-
animation: bounce 1.5s infinite;
|
258 |
-
z-index: 9999;
|
259 |
-
}
|
260 |
-
@keyframes bounce {
|
261 |
-
0% { transform: translateY(0); }
|
262 |
-
50% { transform: translateY(-15px); }
|
263 |
-
100% { transform: translateY(0); }
|
264 |
-
}
|
265 |
-
#gift {
|
266 |
-
position: fixed;
|
267 |
-
width: 60px;
|
268 |
-
cursor: pointer;
|
269 |
-
z-index: 9998;
|
270 |
-
transition: transform 0.5s;
|
271 |
-
}
|
272 |
-
#popup {
|
273 |
-
display: none;
|
274 |
-
position: fixed;
|
275 |
-
top: 50%; left: 50%;
|
276 |
-
transform: translate(-50%, -50%);
|
277 |
-
max-width: 80vw;
|
278 |
-
max-height: 80vh;
|
279 |
-
z-index: 10000;
|
280 |
-
border: 4px solid #fff;
|
281 |
-
border-radius: 12px;
|
282 |
-
box-shadow: 0 0 20px rgba(0,0,0,0.5);
|
283 |
-
}
|
284 |
-
#popup-close {
|
285 |
-
position: absolute;
|
286 |
-
top: 8px; right: 12px;
|
287 |
-
font-size: 24px;
|
288 |
-
color: #fff;
|
289 |
-
cursor: pointer;
|
290 |
-
z-index: 10001;
|
291 |
-
}
|
292 |
</style>
|
|
|
|
|
293 |
<img id="sophia-avatar" src="{avatar_url}" />
|
294 |
<img id="birthday-cake" src="{cake_url}" />
|
295 |
<img id="gift" src="{gift_url}" />
|
296 |
-
<
|
297 |
-
|
298 |
-
<
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
<audio id="bark" src="{bark_sound}"></audio>
|
|
|
303 |
<script>
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
audio.
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
};
|
325 |
-
|
326 |
-
avatar.
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
334 |
}
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
</script>
|
345 |
'''
|
346 |
|
347 |
# 安全插值
|
348 |
-
html_content = html_template.replace(
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
|
|
356 |
|
357 |
# ==== Gradio 界面 ====
|
358 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
359 |
-
|
360 |
-
gr.
|
361 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
362 |
msg = gr.Textbox(label="想对豌豆说啥?", placeholder="比如:你在干嘛?", lines=2)
|
363 |
state = gr.State([])
|
364 |
btn = gr.Button("投喂")
|
365 |
-
btn.click(chat, inputs=[msg,
|
366 |
-
msg.submit(chat, inputs=[msg,
|
367 |
|
368 |
-
if __name__ ==
|
369 |
-
demo.launch()
|
|
|
183 |
|
184 |
# ==== 静态资源 ====
|
185 |
background_images = [
|
186 |
+
f"https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/family{i}.jpg" for i in range(10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
]
|
188 |
+
# 生成背景轮播 keyframes
|
189 |
background_css_rules = "".join([
|
190 |
f" {i * 10}% {{ background-image: url('{img}'); }}\n" for i, img in enumerate(background_images)
|
191 |
])
|
192 |
background_css = f"@keyframes backgroundCycle {{\n{background_css_rules}}}"
|
193 |
|
194 |
+
# 其他资源
|
195 |
avatar_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/bean.jpg"
|
196 |
cake_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/birthday.jpg"
|
197 |
music1 = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/FNG.mp3"
|
|
|
199 |
bark_sound = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/voice.mp3"
|
200 |
gift_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/gift.jpg"
|
201 |
popup_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/srkl.jpg"
|
202 |
+
balloon_url = "https://huggingface.co/spaces/Ronaldo1111/Sophia/resolve/main/ballon.jpg"
|
203 |
|
204 |
+
# ==== HTML/CSS/JS 模板,合并优化,并移除旧烟花 canvas 与 autoplay ====
|
205 |
html_template = '''
|
206 |
<style>
|
207 |
+
body {
|
208 |
+
margin: 0;
|
209 |
+
animation: backgroundCycle 60s infinite;
|
210 |
+
background-size: cover;
|
211 |
+
background-position: center;
|
212 |
+
transition: background-image 1s ease-in-out;
|
213 |
+
}
|
214 |
+
{background_css}
|
215 |
+
|
216 |
+
/* 半透明聊天气泡 */
|
217 |
+
.gradio-container .chatbot .message .bubble {
|
218 |
+
background-color: rgba(255,255,255,0.5) !important;
|
219 |
+
backdrop-filter: blur(8px);
|
220 |
+
}
|
221 |
+
/* 隐藏默认的背景画布 */
|
222 |
+
canvas#fireworks_old { display: none !important; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
</style>
|
224 |
+
|
225 |
+
<!-- 控件元素 -->
|
226 |
<img id="sophia-avatar" src="{avatar_url}" />
|
227 |
<img id="birthday-cake" src="{cake_url}" />
|
228 |
<img id="gift" src="{gift_url}" />
|
229 |
+
<div id="popup-close" style="display:none;">×</div>
|
230 |
+
|
231 |
+
<button id="music-control" style="position:fixed;bottom:20px;left:20px;width:50px;border:none;background:url('music.jpg')center/contain no-repeat;cursor:pointer;z-index:9999;opacity:1;">
|
232 |
+
</button>
|
233 |
+
|
234 |
+
<audio id="bg-music" loop></audio>
|
235 |
<audio id="bark" src="{bark_sound}"></audio>
|
236 |
+
|
237 |
<script>
|
238 |
+
// 背景音乐 手动触发 (移除 autoplay)
|
239 |
+
const audio = document.getElementById('bg-music');
|
240 |
+
const tracks = ['{music1}','{music2}'];
|
241 |
+
document.getElementById('music-control').addEventListener('click',()=>{
|
242 |
+
if(audio.paused){
|
243 |
+
audio.src = tracks[Math.floor(Math.random()*tracks.length)];
|
244 |
+
audio.play();
|
245 |
+
document.getElementById('music-control').style.opacity=0.6;
|
246 |
+
} else {
|
247 |
+
audio.pause();
|
248 |
+
document.getElementById('music-control').style.opacity=1;
|
249 |
+
}
|
250 |
+
});
|
251 |
+
|
252 |
+
// 头像拖拽与 bark 播放
|
253 |
+
const avatar = document.getElementById('sophia-avatar');
|
254 |
+
const bark = document.getElementById('bark');
|
255 |
+
avatar.onmousedown = e=>{
|
256 |
+
const dx=e.clientX-avatar.getBoundingClientRect().left;
|
257 |
+
const dy=e.clientY-avatar.getBoundingClientRect().top;
|
258 |
+
const move=e=>{ avatar.style.left=e.pageX-dx+'px'; avatar.style.top=e.pageY-dy+'px'; };
|
259 |
+
document.addEventListener('mousemove',move);
|
260 |
+
avatar.onmouseup=()=>document.removeEventListener('mousemove',move);
|
261 |
+
};
|
262 |
+
avatar.ondragstart=()=>false;
|
263 |
+
avatar.onclick=()=>{ bark.pause(); bark.currentTime=0; bark.play(); };
|
264 |
+
|
265 |
+
// 蛋糕弹跳已留存,无需修改
|
266 |
+
|
267 |
+
// 礼物随机移动 & 点击切换弹窗
|
268 |
+
const gift = document.getElementById('gift');
|
269 |
+
let showPopup=false;
|
270 |
+
setInterval(()=>{
|
271 |
+
const x=Math.random()*(window.innerWidth-gift.offsetWidth);
|
272 |
+
const y=Math.random()*(window.innerHeight-gift.offsetHeight);
|
273 |
+
gift.style.left=x+'px'; gift.style.top=y+'px';
|
274 |
+
},2000);
|
275 |
+
gift.onclick=()=>{
|
276 |
+
showPopup=!showPopup;
|
277 |
+
const pop=document.getElementById('popup');
|
278 |
+
document.getElementById('popup-close').style.display=showPopup?'block':'none';
|
279 |
+
if(showPopup){
|
280 |
+
pop.style.display='block';
|
281 |
+
pop.src='{popup_url}';
|
282 |
+
pop.style.position='fixed'; pop.style.top='50%'; pop.style.left='50%';
|
283 |
+
pop.style.transform='translate(-50%,-50%)';
|
284 |
+
pop.style.maxWidth='80vw'; pop.style.maxHeight='80vh';
|
285 |
+
pop.style.border='4px solid white'; pop.style.borderRadius='12px';
|
286 |
+
pop.style.boxShadow='0 0 20px rgba(0,0,0,0.5)'; pop.style.zIndex='10000';
|
287 |
+
} else {
|
288 |
+
pop.style.display='none';
|
289 |
}
|
290 |
+
};
|
291 |
+
|
292 |
+
// 点击关闭弹窗也可二次点击礼物或点击 close
|
293 |
+
document.getElementById('popup-close').onclick=()=>gift.onclick();
|
294 |
+
|
295 |
+
// 漂浮气球
|
296 |
+
for(let i=0;i<5;i++){
|
297 |
+
const b=new Image(); b.src='{balloon_url}'; b.className='balloon';
|
298 |
+
b.style.position='fixed'; b.style.width='40px'; b.style.bottom='-50px';
|
299 |
+
b.style.left=Math.random()*90+'vw'; b.style.opacity=0.8;
|
300 |
+
b.style.animation=`floatUp ${(5+Math.random()*5)}s linear infinite`;
|
301 |
+
document.body.appendChild(b);
|
302 |
+
}
|
303 |
+
const style=document.createElement('style'); style.textContent="@keyframes floatUp{0%{transform:translateY(0)}100%{transform:translateY(-120vh)}}";
|
304 |
+
document.head.appendChild(style);
|
305 |
+
|
306 |
+
// 点击触发 HSL 烟花动画
|
307 |
+
const canvas=document.createElement('canvas');
|
308 |
+
canvas.id='fireworks'; canvas.style='position:fixed;top:0;left:0;pointer-events:none;z-index:0;';
|
309 |
+
document.body.appendChild(canvas);
|
310 |
+
const ctx=canvas.getContext('2d'); function resize(){canvas.width=window.innerWidth; canvas.height=window.innerHeight;} resize(); window.addEventListener('resize',resize);
|
311 |
+
function firework(x,y){ for(let i=0;i<50;i++){ const a=Math.random()*2*Math.PI, s=2+Math.random()*3, dx=Math.cos(a)*s, dy=Math.sin(a)*s, h=Math.random()*360; let t=0; const id=setInterval(()=>{ if(t>15){clearInterval(id);return;} ctx.beginPath(); ctx.arc(x+dx*t,y+dy*t,2,0,2*Math.PI); ctx.fillStyle=`hsl(${h},100%,50%)`; ctx.fill(); t++; },30);} }
|
312 |
+
document.body.addEventListener('click',e=>firework(e.clientX,e.clientY));
|
313 |
</script>
|
314 |
'''
|
315 |
|
316 |
# 安全插值
|
317 |
+
html_content = html_template.replace('{background_css}',background_css)
|
318 |
+
html_content = html_content.replace('{avatar_url}',avatar_url)
|
319 |
+
html_content = html_content.replace('{cake_url}',cake_url)
|
320 |
+
html_content = html_content.replace('{music1}',music1)
|
321 |
+
html_content = html_content.replace('{music2}',music2)
|
322 |
+
html_content = html_content.replace('{bark_sound}',bark_sound)
|
323 |
+
html_content = html_content.replace('{gift_url}',gift_url)
|
324 |
+
html_content = html_content.replace('{popup_url}',popup_url)
|
325 |
+
html_content = html_content.replace('{balloon_url}',balloon_url)
|
326 |
|
327 |
# ==== Gradio 界面 ====
|
328 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
329 |
+
# 注入定制 HTML/CSS/JS
|
330 |
+
gr.HTML(html_content)
|
331 |
+
|
332 |
+
# 寿星照片墙
|
333 |
+
gr.Markdown("### 🎂 寿星照片墙")
|
334 |
+
gallery = gr.Gallery(value=background_images, label="照片墙", show_label=False).style(grid=[5], height=200)
|
335 |
+
|
336 |
+
# 聊天区
|
337 |
+
gr.Markdown("## 🌸 Horse and 7 Agent:欢迎进入豌豆的世界 ")
|
338 |
+
chatbot = gr.Chatbot(label="Pea", type="messages", show_copy_button=True)
|
339 |
msg = gr.Textbox(label="想对豌豆说啥?", placeholder="比如:你在干嘛?", lines=2)
|
340 |
state = gr.State([])
|
341 |
btn = gr.Button("投喂")
|
342 |
+
btn.click(chat, inputs=[msg,state], outputs=[chatbot,state])
|
343 |
+
msg.submit(chat, inputs=[msg,state], outputs=[chatbot,state])
|
344 |
|
345 |
+
if __name__ == '__main__':
|
346 |
+
demo.launch()
|