Ronaldo1111 commited on
Commit
40cb176
·
verified ·
1 Parent(s): 66a36cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -150
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
- # 生成 background keyframes
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 模板(使用 .replace 安全插值) ====
212
  html_template = '''
213
  <style>
214
- body {
215
- margin: 0;
216
- animation: backgroundCycle 60s infinite;
217
- background-size: cover;
218
- background-position: center;
219
- transition: background-image 1s ease-in-out;
220
- }
221
- {background_css}
222
- .gr-chatbot {
223
- background: rgba(255, 255, 255, 0.5) !important;
224
- border-radius: 16px;
225
- padding: 10px;
226
- }
227
- .gr-textbox textarea {
228
- font-family: monospace;
229
- font-size: 1.1em;
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
- <img id="popup" src="{popup_url}" />
297
- <div id="popup-close">×</div>
298
- <audio id="bg-music" autoplay loop>
299
- <source src="{music1}" type="audio/mpeg" />
300
- <source src="{music2}" type="audio/mpeg" />
301
- </audio>
302
  <audio id="bark" src="{bark_sound}"></audio>
 
303
  <script>
304
- // 背景音乐轮播
305
- const tracks = ["{music1}", "{music2}"];
306
- const audio = document.getElementById("bg-music");
307
- let current = 0;
308
- audio.addEventListener("ended", () => {
309
- current = (current + 1) % tracks.length;
310
- audio.src = tracks[current]; audio.load(); audio.play();
311
- });
312
- // 头像拖拽 & Bark 音效
313
- const avatar = document.getElementById("sophia-avatar");
314
- const bark = document.getElementById("bark");
315
- avatar.onmousedown = function(e) {
316
- const shiftX = e.clientX - avatar.getBoundingClientRect().left;
317
- const shiftY = e.clientY - avatar.getBoundingClientRect().top;
318
- function moveAt(e) {
319
- avatar.style.left = e.pageX - shiftX + 'px';
320
- avatar.style.top = e.pageY - shiftY + 'px';
321
- }
322
- document.addEventListener('mousemove', moveAt);
323
- avatar.onmouseup = () => { document.removeEventListener('mousemove', moveAt); avatar.onmouseup = null; };
324
- };
325
- avatar.ondragstart = () => false;
326
- avatar.addEventListener("click", () => { bark.pause(); bark.currentTime = 0; bark.play(); });
327
- // 蛋糕动效已存在
328
- // 礼物随机移动 & 点击弹出图片
329
- const gift = document.getElementById("gift");
330
- function moveGift() {
331
- const x = Math.random() * (window.innerWidth - gift.offsetWidth);
332
- const y = Math.random() * (window.innerHeight - gift.offsetHeight);
333
- gift.style.transform = `translate(${x}px, ${y}px)`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  }
335
- setInterval(moveGift, 2000);
336
- gift.addEventListener("click", () => {
337
- document.getElementById("popup").style.display = 'block';
338
- document.getElementById("popup-close").style.display = 'block';
339
- });
340
- document.getElementById("popup-close").addEventListener("click", () => {
341
- document.getElementById("popup").style.display = 'none';
342
- document.getElementById("popup-close").style.display = 'none';
343
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  </script>
345
  '''
346
 
347
  # 安全插值
348
- html_content = html_template.replace("{background_css}", background_css) \
349
- .replace("{avatar_url}", avatar_url) \
350
- .replace("{cake_url}", cake_url) \
351
- .replace("{music1}", music1) \
352
- .replace("{music2}", music2) \
353
- .replace("{bark_sound}", bark_sound) \
354
- .replace("{gift_url}", gift_url) \
355
- .replace("{popup_url}", popup_url)
 
356
 
357
  # ==== Gradio 界面 ====
358
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
359
- gr.HTML(html_content) # 注入自定义样式和脚本
360
- gr.Markdown("## 🌸 Horse and 7 Agent:欢迎进入豌豆的世界 🌸")
361
- chatbot = gr.Chatbot(label="Sophia", type="messages", show_copy_button=True)
 
 
 
 
 
 
 
362
  msg = gr.Textbox(label="想对豌豆说啥?", placeholder="比如:你在干嘛?", lines=2)
363
  state = gr.State([])
364
  btn = gr.Button("投喂")
365
- btn.click(chat, inputs=[msg, state], outputs=[chatbot, state])
366
- msg.submit(chat, inputs=[msg, state], outputs=[chatbot, state])
367
 
368
- if __name__ == "__main__":
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()