openfree commited on
Commit
b8a57cc
ยท
verified ยท
1 Parent(s): 2010fa1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +788 -14
app.py CHANGED
@@ -275,6 +275,768 @@ body {
275
  .gradio-container {
276
  max-width: 1200px !important;
277
  margin: 0 auto !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
279
 
280
  /* Header styling */
@@ -379,19 +1141,9 @@ input:focus, select:focus, textarea:focus, .gr-input:focus {
379
  border-color: #9575cd !important;
380
  }
381
 
382
- /* Add a nice pattern to the background */
383
  body::before {
384
- content: "" !important;
385
- position: fixed !important;
386
- top: 0 !important;
387
- left: 0 !important;
388
- width: 100% !important;
389
- height: 100% !important;
390
- background:
391
- radial-gradient(circle at 10% 20%, rgba(248, 195, 205, 0.1) 0%, rgba(245, 245, 247, 0) 20%),
392
- radial-gradient(circle at 80% 70%, rgba(179, 229, 252, 0.1) 0%, rgba(245, 245, 247, 0) 20%) !important;
393
- pointer-events: none !important;
394
- z-index: -1 !important;
395
  }
396
 
397
  /* Gallery styling */
@@ -481,10 +1233,32 @@ body::before {
481
  #generate-btn:hover {
482
  background: linear-gradient(135deg, #fad0c4, #ff9a9e) !important;
483
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
  """
485
 
486
  _HEADER_ = '''
487
- <div style="text-align: center; max-width: 850px; margin: 0 auto; padding: 25px 0;">
488
  <div style="background: linear-gradient(135deg, #f8c3cd, #e1bee7, #b3e5fc); color: white; padding: 15px; border-radius: 15px; box-shadow: 0 10px 20px rgba(0,0,0,0.1); margin-bottom: 20px;">
489
  <h1 style="font-size: 3rem; font-weight: 800; margin: 0; color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.2);">โœจ DreamO Video โœจ</h1>
490
  <p style="font-size: 1.2rem; margin: 10px 0 0;">Create customized images with advanced AI</p>
@@ -520,7 +1294,7 @@ def create_demo():
520
 
521
  gr.HTML(
522
  """
523
- <div class='container' style='display:flex; justify-content:center; gap:12px;'>
524
  <a href="https://huggingface.co/spaces/openfree/Best-AI" target="_blank">
525
  <img src="https://img.shields.io/static/v1?label=OpenFree&message=BEST%20AI%20Services&color=%230000ff&labelColor=%23000080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="OpenFree badge">
526
  </a>
 
275
  .gradio-container {
276
  max-width: 1200px !important;
277
  margin: 0 auto !important;
278
+ padding-top: 0 !important;
279
+ }
280
+
281
+ /* Remove any default margins that might push content up */
282
+ #component-0 {
283
+ margin-top: 0 !important;
284
+ padding-top: 0 !important;
285
+ }
286
+
287
+ /* Ensure the main container starts from the top */
288
+ .main {
289
+ margin-top: 0 !important;
290
+ padding-top: 10px !important;
291
+ }
292
+
293
+ /* Header styling */
294
+ h1 {
295
+ color: #9c27b0 !important;
296
+ font-weight: 800 !important;
297
+ text-shadow: 2px 2px 4px rgba(156, 39, 176, 0.2) !important;
298
+ letter-spacing: -0.5px !important;
299
+ }
300
+
301
+ /* Card styling for panels */
302
+ .panel-box {
303
+ border-radius: var(--border-radius) !important;
304
+ box-shadow: 0 8px 16px var(--shadow-color) !important;
305
+ background-color: var(--card-background) !important;
306
+ border: none !important;
307
+ overflow: hidden !important;
308
+ padding: 20px !important;
309
+ margin-bottom: 20px !important;
310
+ }
311
+
312
+ /* Button styling */
313
+ button.gr-button {
314
+ background: linear-gradient(135deg, var(--primary-color), #e1bee7) !important;
315
+ border-radius: var(--border-radius) !important;
316
+ color: #4a148c !important;
317
+ font-weight: 600 !important;
318
+ border: none !important;
319
+ padding: 10px 20px !important;
320
+ transition: all 0.3s ease !important;
321
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
322
+ }
323
+
324
+ button.gr-button:hover {
325
+ transform: translateY(-2px) !important;
326
+ box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15) !important;
327
+ background: linear-gradient(135deg, #e1bee7, var(--primary-color)) !important;
328
+ }
329
+
330
+ /* Input fields styling */
331
+ input, select, textarea, .gr-input {
332
+ border-radius: 8px !important;
333
+ border: 2px solid #e0e0e0 !important;
334
+ padding: 10px 15px !important;
335
+ transition: all 0.3s ease !important;
336
+ background-color: #fafafa !important;
337
+ }
338
+
339
+ input:focus, select:focus, textarea:focus, .gr-input:focus {
340
+ border-color: var(--primary-color) !important;
341
+ box-shadow: 0 0 0 3px rgba(248, 195, 205, 0.3) !important;
342
+ }
343
+
344
+ /* Slider styling */
345
+ .gr-form input[type=range] {
346
+ appearance: none !important;
347
+ width: 100% !important;
348
+ height: 6px !important;
349
+ background: #e0e0e0 !important;
350
+ border-radius: 5px !important;
351
+ outline: none !important;
352
+ }
353
+
354
+ .gr-form input[type=range]::-webkit-slider-thumb {
355
+ appearance: none !important;
356
+ width: 16px !important;
357
+ height: 16px !important;
358
+ background: var(--primary-color) !important;
359
+ border-radius: 50% !important;
360
+ cursor: pointer !important;
361
+ border: 2px solid white !important;
362
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
363
+ }
364
+
365
+ /* Dropdown styling */
366
+ .gr-form select {
367
+ background-color: white !important;
368
+ border: 2px solid #e0e0e0 !important;
369
+ border-radius: 8px !important;
370
+ padding: 10px 15px !important;
371
+ }
372
+
373
+ .gr-form select option {
374
+ padding: 10px !important;
375
+ }
376
+
377
+ /* Image upload area */
378
+ .gr-image-input {
379
+ border: 2px dashed #b39ddb !important;
380
+ border-radius: var(--border-radius) !important;
381
+ background-color: #f3e5f5 !important;
382
+ padding: 20px !important;
383
+ display: flex !important;
384
+ flex-direction: column !important;
385
+ align-items: center !important;
386
+ justify-content: center !important;
387
+ transition: all 0.3s ease !important;
388
+ }
389
+
390
+ .gr-image-input:hover {
391
+ background-color: #ede7f6 !important;
392
+ border-color: #9575cd !important;
393
+ }
394
+
395
+ /* Remove the background pattern that might interfere with visibility */
396
+ body::before {
397
+ display: none !important;
398
+ }
399
+
400
+ /* Gallery styling */
401
+ .gr-gallery {
402
+ grid-gap: 15px !important;
403
+ }
404
+
405
+ .gr-gallery-item {
406
+ border-radius: var(--border-radius) !important;
407
+ overflow: hidden !important;
408
+ box-shadow: 0 4px 8px var(--shadow-color) !important;
409
+ transition: transform 0.3s ease !important;
410
+ }
411
+
412
+ .gr-gallery-item:hover {
413
+ transform: scale(1.02) !important;
414
+ }
415
+
416
+ /* Label styling */
417
+ .gr-form label {
418
+ font-weight: 600 !important;
419
+ color: #673ab7 !important;
420
+ margin-bottom: 5px !important;
421
+ }
422
+
423
+ /* Improve spacing */
424
+ .gr-padded {
425
+ padding: 20px !important;
426
+ }
427
+
428
+ .gr-compact {
429
+ gap: 15px !important;
430
+ }
431
+
432
+ .gr-form > div {
433
+ margin-bottom: 16px !important;
434
+ }
435
+
436
+ /* Headings */
437
+ .gr-form h3 {
438
+ color: #7b1fa2 !important;
439
+ margin-top: 5px !important;
440
+ margin-bottom: 15px !important;
441
+ border-bottom: 2px solid #e1bee7 !important;
442
+ padding-bottom: 8px !important;
443
+ }
444
+
445
+ /* Examples section */
446
+ #examples-panel {
447
+ background-color: #f3e5f5 !important;
448
+ border-radius: var(--border-radius) !important;
449
+ padding: 15px !important;
450
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05) !important;
451
+ }
452
+
453
+ #examples-panel h2 {
454
+ color: #7b1fa2 !important;
455
+ font-size: 1.5rem !important;
456
+ margin-bottom: 15px !important;
457
+ }
458
+
459
+ /* Accordion styling */
460
+ .gr-accordion {
461
+ border: 1px solid #e0e0e0 !important;
462
+ border-radius: var(--border-radius) !important;
463
+ overflow: hidden !important;
464
+ }
465
+
466
+ .gr-accordion summary {
467
+ padding: 12px 16px !important;
468
+ background-color: #f9f9f9 !important;
469
+ cursor: pointer !important;
470
+ font-weight: 600 !important;
471
+ color: #673ab7 !important;
472
+ }
473
+
474
+ /* Generate button special styling */
475
+ #generate-btn {
476
+ background: linear-gradient(135deg, #ff9a9e, #fad0c4) !important;
477
+ font-size: 1.1rem !important;
478
+ padding: 12px 24px !important;
479
+ margin-top: 10px !important;
480
+ margin-bottom: 15px !important;
481
+ width: 100% !important;
482
+ }
483
+
484
+ #generate-btn:hover {
485
+ background: linear-gradient(135deg, #fad0c4, #ff9a9e) !important;
486
+ }
487
+
488
+ /* Ensure proper scrolling behavior */
489
+ html {
490
+ scroll-behavior: smooth !important;
491
+ }
492
+
493
+ /* Fix any overflow issues that might hide content */
494
+ .contain {
495
+ overflow: visible !important;
496
+ }
497
+
498
+ /* Additional fixes for header visibility */
499
+ .header-wrap {
500
+ position: relative !important;
501
+ margin-top: 0 !important;
502
+ }
503
+
504
+ /* Ensure the first element is visible */
505
+ .gradio-container > :first-child {
506
+ margin-top: 0 !important;
507
+ padding-top: 10px !important;
508
+ }
509
+ """
510
+
511
+ _HEADER_ = '''
512
+ <div style="text-align: center; max-width: 850px; margin: 0 auto; padding: 20px 0;">
513
+ <div style="background: linear-gradient(135deg, #f8c3cd, #e1bee7, #b3e5fc); color: white; padding: 15px; border-radius: 15px; box-shadow: 0 10px 20px rgba(0,0,0,0.1); margin-bottom: 20px;">
514
+ <h1 style="font-size: 3rem; font-weight: 800; margin: 0; color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.2);">โœจ DreamO Video โœจ</h1>
515
+ <p style="font-size: 1.2rem; margin: 10px 0 0;">Create customized images with advanced AI</p>
516
+ </div>
517
+
518
+ <div style="background: white; padding: 15px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);">
519
+ <p style="font-size: 1rem; margin: 0;">In the current demo version, due to ZeroGPU limitations, video generation is restricted to 2 seconds only. (The full version supports generation of up to 60 seconds)</p>
520
+ </div>
521
+
522
+ </div>
523
+
524
+ <div style="background: #fff9c4; padding: 15px; border-radius: 12px; margin-bottom: 20px; border-left: 5px solid #ffd54f; box-shadow: 0 5px 15px rgba(0,0,0,0.05);">
525
+ <h3 style="margin-top: 0; color: #ff6f00;">๐Ÿšฉ Update Notes:</h3>
526
+ <ul style="margin-bottom: 0; padding-left: 20px;">
527
+ <li><b>2025.05.11:</b> We have updated the model to mitigate over-saturation and plastic-face issues. The new version shows consistent improvements over the previous release.</li>
528
+ <li><b>2025.05.13:</b> 'DreamO Video' Integration version Release</li>
529
+ </ul>
530
+ </div>
531
+ '''
532
+
533
+ _CITE_ = r"""
534
+ <div style="background: white; padding: 20px; border-radius: 12px; margin-top: 20px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);">
535
+ <p style="margin: 0; font-size: 1.1rem;">If DreamO is helpful, please help to โญ the <a href='https://discord.gg/openfreeai' target='_blank' style="color: #9c27b0; font-weight: 600;">community</a>. Thanks!</p>
536
+ <hr style="border: none; height: 1px; background-color: #e0e0e0; margin: 15px 0;">
537
+ <h4 style="margin: 0 0 10px; color: #7b1fa2;">๐Ÿ“ง Contact</h4>
538
+ <p style="margin: 0;">If you have any questions or feedback, feel free to open a discussion or contact <b>[email protected]</b></p>
539
+ </div>
540
+ """
541
+
542
+ def create_demo():
543
+ with gr.Blocks(css=_CUSTOM_CSS_) as demo:
544
+ gr.HTML(_HEADER_)
545
+
546
+ gr.HTML(
547
+ """
548
+ <div class='container' style='display:flex; justify-content:center; gap:12px; margin-bottom: 20px;'>
549
+ <a href="https://huggingface.co/spaces/openfree/Best-AI" target="_blank">
550
+ <img src="https://img.shields.io/static/v1?label=OpenFree&message=BEST%20AI%20Services&color=%230000ff&labelColor=%23000080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="OpenFree badge">
551
+ </a>
552
+
553
+ <a href="https://discord.gg/openfreeai" target="_blank">
554
+ <img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="Discord badge">
555
+ </a>
556
+ </div>
557
+ """
558
+ )
559
+
560
+ with gr.Row():
561
+ with gr.Column(scale=6):
562
+ with gr.Group(elem_id="input-panel", elem_classes="panel-box"):
563
+ gr.Markdown("### ๐Ÿ“ธ Reference Images")
564
+ with gr.Row():
565
+ with gr.Column():
566
+ ref_image1 = gr.Image(label="Reference Image 1", type="numpy", height=256, elem_id="ref-image-1")
567
+ ref_task1 = gr.Dropdown(choices=["ip", "id", "style"], value="ip", label="Task for Reference Image 1", elem_id="ref-task-1")
568
+
569
+ with gr.Column():
570
+ ref_image2 = gr.Image(label="Reference Image 2", type="numpy", height=256, elem_id="ref-image-2")
571
+ ref_task2 = gr.Dropdown(choices=["ip", "id", "style"], value="ip", label="Task for Reference Image 2", elem_id="ref-task-2")
572
+
573
+ gr.Markdown("### โœ๏ธ Generation Parameters")
574
+ prompt = gr.Textbox(label="Prompt", value="a person playing guitar in the street", elem_id="prompt-input")
575
+
576
+ with gr.Row():
577
+ width = gr.Slider(768, 1024, 1024, step=16, label="Width", elem_id="width-slider")
578
+ height = gr.Slider(768, 1024, 1024, step=16, label="Height", elem_id="height-slider")
579
+
580
+ with gr.Row():
581
+ num_steps = gr.Slider(8, 30, 12, step=1, label="Number of Steps", elem_id="steps-slider")
582
+ guidance = gr.Slider(1.0, 10.0, 3.5, step=0.1, label="Guidance Scale", elem_id="guidance-slider")
583
+
584
+ seed = gr.Textbox(label="Seed (-1 for random)", value="-1", elem_id="seed-input")
585
+
586
+ with gr.Accordion("Advanced Options", open=False):
587
+ ref_res = gr.Slider(512, 1024, 512, step=16, label="Resolution for Reference Image")
588
+ neg_prompt = gr.Textbox(label="Negative Prompt", value="")
589
+ neg_guidance = gr.Slider(1.0, 10.0, 3.5, step=0.1, label="Negative Guidance")
590
+
591
+ with gr.Row():
592
+ true_cfg = gr.Slider(1, 5, 1, step=0.1, label="True CFG")
593
+ first_step_guidance = gr.Slider(0, 10, 0, step=0.1, label="First Step Guidance")
594
+
595
+ with gr.Row():
596
+ cfg_start_step = gr.Slider(0, 30, 0, step=1, label="CFG Start Step")
597
+ cfg_end_step = gr.Slider(0, 30, 0, step=1, label="CFG End Step")
598
+
599
+ generate_btn = gr.Button("โœจ Generate Image", elem_id="generate-btn")
600
+ gr.HTML(_CITE_)
601
+
602
+ with gr.Column(scale=6):
603
+ with gr.Group(elem_id="output-panel", elem_classes="panel-box"):
604
+ gr.Markdown("### ๐Ÿ–ผ๏ธ Generated Result")
605
+ output_image = gr.Image(label="Generated Image", elem_id="output-image", format='png')
606
+ seed_output = gr.Textbox(label="Used Seed", elem_id="seed-output")
607
+
608
+ # (2) ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ & ์ถœ๋ ฅ ์˜์—ญ ์ถ”๊ฐ€
609
+ generate_video_btn = gr.Button("๐ŸŽฌ Generate Video from Image")
610
+ output_video = gr.Video(label="Generated Video", elem_id="video-output")
611
+
612
+ gr.Markdown("### ๐Ÿ” Preprocessing")
613
+ debug_image = gr.Gallery(
614
+ label="Preprocessing Results (including face crop and background removal)",
615
+ elem_id="debug-gallery",
616
+ )
617
+
618
+ with gr.Group(elem_id="examples-panel", elem_classes="panel-box"):
619
+ gr.Markdown("## ๐Ÿ“š Examples")
620
+ example_inps = [
621
+ [
622
+ 'example_inputs/choi.jpg',
623
+ None,
624
+ 'ip',
625
+ 'ip',
626
+ 'a woman sitting on the cloud, playing guitar',
627
+ 1206523688721442817,
628
+ ],
629
+ [
630
+ 'example_inputs/choi.jpg',
631
+ None,
632
+ 'id',
633
+ 'ip',
634
+ 'a woman holding a sign saying "TOP", on the mountain',
635
+ 10441727852953907380,
636
+ ],
637
+ [
638
+ 'example_inputs/perfume.png',
639
+ None,
640
+ 'ip',
641
+ 'ip',
642
+ 'a perfume under spotlight',
643
+ 116150031980664704,
644
+ ],
645
+ [
646
+ 'example_inputs/choi.jpg',
647
+ None,
648
+ 'id',
649
+ 'ip',
650
+ 'portrait, in alps',
651
+ 5443415087540486371,
652
+ ],
653
+ [
654
+ 'example_inputs/mickey.png',
655
+ None,
656
+ 'style',
657
+ 'ip',
658
+ 'generate a same style image. A rooster wearing overalls.',
659
+ 6245580464677124951,
660
+ ],
661
+ [
662
+ 'example_inputs/mountain.png',
663
+ None,
664
+ 'style',
665
+ 'ip',
666
+ 'generate a same style image. A pavilion by the river, and the distant mountains are endless',
667
+ 5248066378927500767,
668
+ ],
669
+ [
670
+ 'example_inputs/shirt.png',
671
+ 'example_inputs/skirt.jpeg',
672
+ 'ip',
673
+ 'ip',
674
+ 'A girl is wearing a short-sleeved shirt and a short skirt on the beach.',
675
+ 9514069256241143615,
676
+ ],
677
+ [
678
+ 'example_inputs/woman2.png',
679
+ 'example_inputs/dress.png',
680
+ 'id',
681
+ 'ip',
682
+ 'the woman wearing a dress, In the banquet hall',
683
+ 7698454872441022867,
684
+ ],
685
+ [
686
+ 'example_inputs/dog1.png',
687
+ 'example_inputs/dog2.png',
688
+ 'ip',
689
+ 'ip',
690
+ 'two dogs in the jungle',
691
+ 6187006025405083344,
692
+ ],
693
+ ]
694
+ gr.Examples(
695
+ examples=example_inps,
696
+ inputs=[ref_image1, ref_image2, ref_task1, ref_task2, prompt, seed],
697
+ label='Examples by category: IP task (rows 1-4), ID task (row 5), Style task (rows 6-7), Try-On task (rows 8-9)',
698
+ cache_examples='lazy',
699
+ outputs=[output_image, debug_image, seed_output],
700
+ fn=generate_image,
701
+ )
702
+
703
+ # ๊ธฐ์กด ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜์™€ ์—ฐ๊ฒฐ
704
+ generate_btn.click(
705
+ fn=generate_image,
706
+ inputs=[
707
+ ref_image1,
708
+ ref_image2,
709
+ ref_task1,
710
+ ref_task2,
711
+ prompt,
712
+ seed,
713
+ width,
714
+ height,
715
+ ref_res,
716
+ num_steps,
717
+ guidance,
718
+ true_cfg,
719
+ cfg_start_step,
720
+ cfg_end_step,
721
+ neg_prompt,
722
+ neg_guidance,
723
+ first_step_guidance,
724
+ ],
725
+ outputs=[output_image, debug_image, seed_output],
726
+ )
727
+
728
+ # (3) ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ -> generate_video_from_image() ํ˜ธ์ถœ
729
+ def on_click_generate_video(img):
730
+ if img is None:
731
+ raise gr.Error("๋จผ์ € ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.")
732
+ video_path = generate_video_from_image(img)
733
+ return video_path
734
+
735
+ generate_video_btn.click(
736
+ fn=on_click_generate_video,
737
+ inputs=[output_image],
738
+ outputs=[output_video],
739
+ )
740
+
741
+ return demo
742
+
743
+
744
+ if __name__ == '__main__':
745
+ demo = create_demo()
746
+ demo.launch(
747
+ server_name="0.0.0.0",
748
+ share=True,
749
+ ssr_mode=False
750
+ )import spaces
751
+ import argparse
752
+ import os
753
+ import shutil
754
+ import cv2
755
+ import gradio as gr
756
+ import numpy as np
757
+ import torch
758
+ from facexlib.utils.face_restoration_helper import FaceRestoreHelper
759
+ import huggingface_hub
760
+ from huggingface_hub import hf_hub_download
761
+ from PIL import Image
762
+ from torchvision.transforms.functional import normalize
763
+
764
+ from dreamo.dreamo_pipeline import DreamOPipeline
765
+ from dreamo.utils import img2tensor, resize_numpy_image_area, tensor2img, resize_numpy_image_long
766
+ from tools import BEN2
767
+
768
+ parser = argparse.ArgumentParser()
769
+ parser.add_argument('--port', type=int, default=8080)
770
+ parser.add_argument('--no_turbo', action='store_true')
771
+ args = parser.parse_args()
772
+
773
+ huggingface_hub.login(os.getenv('HF_TOKEN'))
774
+
775
+ try:
776
+ shutil.rmtree('gradio_cached_examples')
777
+ except FileNotFoundError:
778
+ print("cache folder not exist")
779
+
780
+ class Generator:
781
+ def __init__(self):
782
+ device = torch.device('cuda')
783
+ # preprocessing models
784
+ # background remove model: BEN2
785
+ self.bg_rm_model = BEN2.BEN_Base().to(device).eval()
786
+ hf_hub_download(repo_id='PramaLLC/BEN2', filename='BEN2_Base.pth', local_dir='models')
787
+ self.bg_rm_model.loadcheckpoints('models/BEN2_Base.pth')
788
+ # face crop and align tool: facexlib
789
+ self.face_helper = FaceRestoreHelper(
790
+ upscale_factor=1,
791
+ face_size=512,
792
+ crop_ratio=(1, 1),
793
+ det_model='retinaface_resnet50',
794
+ save_ext='png',
795
+ device=device,
796
+ )
797
+
798
+ # load dreamo
799
+ model_root = 'black-forest-labs/FLUX.1-dev'
800
+ dreamo_pipeline = DreamOPipeline.from_pretrained(model_root, torch_dtype=torch.bfloat16)
801
+ dreamo_pipeline.load_dreamo_model(device, use_turbo=not args.no_turbo)
802
+ self.dreamo_pipeline = dreamo_pipeline.to(device)
803
+
804
+ @torch.no_grad()
805
+ def get_align_face(self, img):
806
+ # the face preprocessing code is same as PuLID
807
+ self.face_helper.clean_all()
808
+ image_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
809
+ self.face_helper.read_image(image_bgr)
810
+ self.face_helper.get_face_landmarks_5(only_center_face=True)
811
+ self.face_helper.align_warp_face()
812
+ if len(self.face_helper.cropped_faces) == 0:
813
+ return None
814
+ align_face = self.face_helper.cropped_faces[0]
815
+
816
+ input = img2tensor(align_face, bgr2rgb=True).unsqueeze(0) / 255.0
817
+ input = input.to(torch.device("cuda"))
818
+ parsing_out = self.face_helper.face_parse(normalize(input, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]))[0]
819
+ parsing_out = parsing_out.argmax(dim=1, keepdim=True)
820
+ bg_label = [0, 16, 18, 7, 8, 9, 14, 15]
821
+ bg = sum(parsing_out == i for i in bg_label).bool()
822
+ white_image = torch.ones_like(input)
823
+ # only keep the face features
824
+ face_features_image = torch.where(bg, white_image, input)
825
+ face_features_image = tensor2img(face_features_image, rgb2bgr=False)
826
+
827
+ return face_features_image
828
+
829
+
830
+ generator = Generator()
831
+
832
+
833
+ @spaces.GPU
834
+ @torch.inference_mode()
835
+ def generate_image(
836
+ ref_image1,
837
+ ref_image2,
838
+ ref_task1,
839
+ ref_task2,
840
+ prompt,
841
+ seed,
842
+ width=1024,
843
+ height=1024,
844
+ ref_res=512,
845
+ num_steps=12,
846
+ guidance=3.5,
847
+ true_cfg=1,
848
+ cfg_start_step=0,
849
+ cfg_end_step=0,
850
+ neg_prompt='',
851
+ neg_guidance=3.5,
852
+ first_step_guidance=0,
853
+ ):
854
+ print(prompt)
855
+ ref_conds = []
856
+ debug_images = []
857
+
858
+ ref_images = [ref_image1, ref_image2]
859
+ ref_tasks = [ref_task1, ref_task2]
860
+
861
+ for idx, (ref_image, ref_task) in enumerate(zip(ref_images, ref_tasks)):
862
+ if ref_image is not None:
863
+ if ref_task == "id":
864
+ ref_image = resize_numpy_image_long(ref_image, 1024)
865
+ ref_image = generator.get_align_face(ref_image)
866
+ elif ref_task != "style":
867
+ ref_image = generator.bg_rm_model.inference(Image.fromarray(ref_image))
868
+ if ref_task != "id":
869
+ ref_image = resize_numpy_image_area(np.array(ref_image), ref_res * ref_res)
870
+ debug_images.append(ref_image)
871
+ ref_image = img2tensor(ref_image, bgr2rgb=False).unsqueeze(0) / 255.0
872
+ ref_image = 2 * ref_image - 1.0
873
+ ref_conds.append(
874
+ {
875
+ 'img': ref_image,
876
+ 'task': ref_task,
877
+ 'idx': idx + 1,
878
+ }
879
+ )
880
+
881
+ seed = int(seed)
882
+ if seed == -1:
883
+ seed = torch.Generator(device="cpu").seed()
884
+
885
+ image = generator.dreamo_pipeline(
886
+ prompt=prompt,
887
+ width=width,
888
+ height=height,
889
+ num_inference_steps=num_steps,
890
+ guidance_scale=guidance,
891
+ ref_conds=ref_conds,
892
+ generator=torch.Generator(device="cpu").manual_seed(seed),
893
+ true_cfg_scale=true_cfg,
894
+ true_cfg_start_step=cfg_start_step,
895
+ true_cfg_end_step=cfg_end_step,
896
+ negative_prompt=neg_prompt,
897
+ neg_guidance_scale=neg_guidance,
898
+ first_step_guidance_scale=first_step_guidance if first_step_guidance > 0 else guidance,
899
+ ).images[0]
900
+
901
+ return image, debug_images, seed
902
+
903
+
904
+ # -----------------------------
905
+ # (1) ์—ฌ๊ธฐ์— ์˜์ƒ API ํ˜ธ์ถœ์„ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฝ”๋“œ
906
+ # -----------------------------
907
+ import requests
908
+ import random
909
+ import tempfile
910
+ import subprocess
911
+ from gradio_client import Client, handle_file
912
+
913
+ # ์˜ˆ์‹œ: ์›๊ฒฉ ์„œ๋ฒ„ Endpoint (ํ•„์š”ํ•˜๋‹ค๋ฉด ์ˆ˜์ •)
914
+ REMOTE_ENDPOINT = os.getenv("H100_URL")
915
+
916
+ client = Client(REMOTE_ENDPOINT)
917
+
918
+ def run_process_video_api(image_path: str, prompt: str, video_length: float = 2.0):
919
+ """
920
+ ์›๊ฒฉ /process ์—”๋“œํฌ์ธํŠธ ํ˜ธ์ถœํ•˜์—ฌ ์˜์ƒ์„ ์ƒ์„ฑ.
921
+ (์˜ˆ์‹œ: prompt, negative_prompt, seed ๋“ฑ์€ ํ•˜๋“œ์ฝ”๋”ฉํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š”๋Œ€๋กœ ์กฐ์ • ๊ฐ€๋Šฅ)
922
+ """
923
+ # ๋žœ๋ค ์‹œ๋“œ
924
+ seed_val = random.randint(0, 9999999)
925
+ # negative_prompt = "" ๋“ฑ ๊ณ ์ •
926
+ negative_prompt = ""
927
+ use_teacache = True
928
+
929
+ # /process ํ˜ธ์ถœ (gradio_client)
930
+ result = client.predict(
931
+ input_image=handle_file(image_path),
932
+ prompt=prompt,
933
+ n_prompt=negative_prompt,
934
+ seed=seed_val,
935
+ use_teacache=use_teacache,
936
+ video_length=video_length,
937
+ api_name="/process",
938
+ )
939
+ # result๋Š” (video_dict, preview_dict, md_text, html_text) ๊ตฌ์กฐ
940
+ video_dict, preview_dict, md_text, html_text = result
941
+ video_path = video_dict.get("video") if isinstance(video_dict, dict) else None
942
+ return video_path
943
+
944
+ def add_watermark_to_video(input_video_path: str, watermark_text="Ginigen.com") -> str:
945
+ """
946
+ FFmpeg๋กœ ์˜์ƒ์— ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ ์›Œํ„ฐ๋งˆํฌ๋ฅผ ์ถ”๊ฐ€ํ•œ ์ƒˆ ์˜์ƒ์„ ๋ฆฌํ„ด
947
+ """
948
+ if not os.path.exists(input_video_path):
949
+ raise FileNotFoundError(f"Input video not found: {input_video_path}")
950
+
951
+ # ์ถœ๋ ฅ ๊ฒฝ๋กœ
952
+ base, ext = os.path.splitext(input_video_path)
953
+ watermarked_path = base + "_wm" + ext
954
+ # ffmpeg ๋ช…๋ น์–ด ๊ตฌ์„ฑ
955
+ # - y: ๋ฎ์–ด์“ฐ๊ธฐ
956
+ # drawtext ํ•„ํ„ฐ๋กœ ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ(x=w-tw-10, y=h-th-10)์— boxcolor=black ๋ฐ˜ํˆฌ๋ช… ๋ฐ•์Šค
957
+ cmd = [
958
+ "ffmpeg", "-y",
959
+ "-i", input_video_path,
960
+ "-vf", f"drawtext=fontsize=20:fontcolor=white:text='{watermark_text}':x=w-tw-10:y=h-th-10:box=1:[email protected]:boxborderw=5",
961
+ "-codec:a", "copy",
962
+ watermarked_path
963
+ ]
964
+ try:
965
+ subprocess.run(cmd, check=True)
966
+ except Exception as e:
967
+ print(f"[WARN] FFmpeg watermark failed: {e}")
968
+ return input_video_path # ์‹คํŒจ ์‹œ ์›๋ณธ ๋ฐ˜ํ™˜
969
+
970
+ return watermarked_path
971
+
972
+ def generate_video_from_image(image_array: np.ndarray):
973
+ """
974
+ 1) Numpy ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
975
+ 2) ์›๊ฒฉ API๋กœ 2์ดˆ ์˜์ƒ ๏ฟฝ๏ฟฝ๏ฟฝ์„ฑ (๊ธฐ๋ณธ prompt ๊ณ ์ •)
976
+ 3) FFmpeg๋กœ 'Ginigen.com' ์›Œํ„ฐ๋งˆํฌ ์ถ”๊ฐ€
977
+ 4) ์ตœ์ข… mp4 ๊ฒฝ๋กœ ๋ฐ˜ํ™˜
978
+ """
979
+ if image_array is None:
980
+ raise gr.Error("์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")
981
+
982
+ # (1) ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
983
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as fp:
984
+ temp_img_path = fp.name
985
+ Image.fromarray(image_array).save(temp_img_path, format="PNG")
986
+
987
+ # (2) ์›๊ฒฉ API ํ˜ธ์ถœ
988
+ default_video_prompt = "Generate a video with smooth and natural movement. Objects should have visible motion while maintaining fluid transitions."
989
+ result_video_path = run_process_video_api(
990
+ image_path=temp_img_path,
991
+ prompt=default_video_prompt,
992
+ video_length=2.0,
993
+ )
994
+ if result_video_path is None:
995
+ raise gr.Error("์˜์ƒ API ํ˜ธ์ถœ ์‹คํŒจ ๋˜๋Š” ๊ฒฐ๊ณผ ์—†์Œ")
996
+
997
+ # (3) FFmpeg ์›Œํ„ฐ๋งˆํฌ ์ถ”๊ฐ€
998
+ final_video = add_watermark_to_video(result_video_path, watermark_text="Ginigen.com")
999
+ return final_video
1000
+
1001
+
1002
+ # -----------------------------
1003
+ # Custom CSS, Headers, etc.
1004
+ # -----------------------------
1005
+ _CUSTOM_CSS_ = """
1006
+ :root {
1007
+ --primary-color: #f8c3cd; /* Sakura pink - primary accent */
1008
+ --secondary-color: #b3e5fc; /* Pastel blue - secondary accent */
1009
+ --background-color: #f5f5f7; /* Very light gray background */
1010
+ --card-background: #ffffff; /* White for cards */
1011
+ --text-color: #424242; /* Dark gray for text */
1012
+ --accent-color: #ffb6c1; /* Light pink for accents */
1013
+ --success-color: #c8e6c9; /* Pastel green for success */
1014
+ --warning-color: #fff9c4; /* Pastel yellow for warnings */
1015
+ --shadow-color: rgba(0, 0, 0, 0.1); /* Shadow color */
1016
+ --border-radius: 12px; /* Rounded corners */
1017
+ }
1018
+
1019
+ body {
1020
+ background-color: var(--background-color) !important;
1021
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
1022
+ }
1023
+
1024
+ .gradio-container {
1025
+ max-width: 1200px !important;
1026
+ margin: 0 auto !important;
1027
+ padding-top: 0 !important;
1028
+ }
1029
+
1030
+ /* Remove any default margins that might push content up */
1031
+ #component-0 {
1032
+ margin-top: 0 !important;
1033
+ padding-top: 0 !important;
1034
+ }
1035
+
1036
+ /* Ensure the main container starts from the top */
1037
+ .main {
1038
+ margin-top: 0 !important;
1039
+ padding-top: 10px !important;
1040
  }
1041
 
1042
  /* Header styling */
 
1141
  border-color: #9575cd !important;
1142
  }
1143
 
1144
+ /* Remove the background pattern that might interfere with visibility */
1145
  body::before {
1146
+ display: none !important;
 
 
 
 
 
 
 
 
 
 
1147
  }
1148
 
1149
  /* Gallery styling */
 
1233
  #generate-btn:hover {
1234
  background: linear-gradient(135deg, #fad0c4, #ff9a9e) !important;
1235
  }
1236
+
1237
+ /* Ensure proper scrolling behavior */
1238
+ html {
1239
+ scroll-behavior: smooth !important;
1240
+ }
1241
+
1242
+ /* Fix any overflow issues that might hide content */
1243
+ .contain {
1244
+ overflow: visible !important;
1245
+ }
1246
+
1247
+ /* Additional fixes for header visibility */
1248
+ .header-wrap {
1249
+ position: relative !important;
1250
+ margin-top: 0 !important;
1251
+ }
1252
+
1253
+ /* Ensure the first element is visible */
1254
+ .gradio-container > :first-child {
1255
+ margin-top: 0 !important;
1256
+ padding-top: 10px !important;
1257
+ }
1258
  """
1259
 
1260
  _HEADER_ = '''
1261
+ <div style="text-align: center; max-width: 850px; margin: 0 auto; padding: 20px 0;">
1262
  <div style="background: linear-gradient(135deg, #f8c3cd, #e1bee7, #b3e5fc); color: white; padding: 15px; border-radius: 15px; box-shadow: 0 10px 20px rgba(0,0,0,0.1); margin-bottom: 20px;">
1263
  <h1 style="font-size: 3rem; font-weight: 800; margin: 0; color: white; text-shadow: 2px 2px 4px rgba(0,0,0,0.2);">โœจ DreamO Video โœจ</h1>
1264
  <p style="font-size: 1.2rem; margin: 10px 0 0;">Create customized images with advanced AI</p>
 
1294
 
1295
  gr.HTML(
1296
  """
1297
+ <div class='container' style='display:flex; justify-content:center; gap:12px; margin-bottom: 20px;'>
1298
  <a href="https://huggingface.co/spaces/openfree/Best-AI" target="_blank">
1299
  <img src="https://img.shields.io/static/v1?label=OpenFree&message=BEST%20AI%20Services&color=%230000ff&labelColor=%23000080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="OpenFree badge">
1300
  </a>