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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +5 -755
app.py CHANGED
@@ -153,7 +153,7 @@ def generate_image(
153
 
154
 
155
  # -----------------------------
156
- # (1) ์—ฌ๊ธฐ์— ์˜์ƒ API ํ˜ธ์ถœ์„ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฝ”๋“œ
157
  # -----------------------------
158
  import requests
159
  import random
@@ -161,7 +161,7 @@ import tempfile
161
  import subprocess
162
  from gradio_client import Client, handle_file
163
 
164
- # ์˜ˆ์‹œ: ์›๊ฒฉ ์„œ๋ฒ„ Endpoint (ํ•„์š”ํ•˜๋‹ค๋ฉด ์ˆ˜์ •)
165
  REMOTE_ENDPOINT = os.getenv("H100_URL")
166
 
167
  client = Client(REMOTE_ENDPOINT)
@@ -169,7 +169,6 @@ client = Client(REMOTE_ENDPOINT)
169
  def run_process_video_api(image_path: str, prompt: str, video_length: float = 2.0):
170
  """
171
  ์›๊ฒฉ /process ์—”๋“œํฌ์ธํŠธ ํ˜ธ์ถœํ•˜์—ฌ ์˜์ƒ์„ ์ƒ์„ฑ.
172
- (์˜ˆ์‹œ: prompt, negative_prompt, seed ๋“ฑ์€ ํ•˜๋“œ์ฝ”๋”ฉํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š”๋Œ€๋กœ ์กฐ์ • ๊ฐ€๋Šฅ)
173
  """
174
  # ๋žœ๋ค ์‹œ๋“œ
175
  seed_val = random.randint(0, 9999999)
@@ -605,7 +604,7 @@ def create_demo():
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
 
@@ -700,7 +699,7 @@ def create_demo():
700
  fn=generate_image,
701
  )
702
 
703
- # ๊ธฐ์กด ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜์™€ ์—ฐ๊ฒฐ
704
  generate_btn.click(
705
  fn=generate_image,
706
  inputs=[
@@ -725,756 +724,7 @@ def create_demo():
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 */
1043
- h1 {
1044
- color: #9c27b0 !important;
1045
- font-weight: 800 !important;
1046
- text-shadow: 2px 2px 4px rgba(156, 39, 176, 0.2) !important;
1047
- letter-spacing: -0.5px !important;
1048
- }
1049
-
1050
- /* Card styling for panels */
1051
- .panel-box {
1052
- border-radius: var(--border-radius) !important;
1053
- box-shadow: 0 8px 16px var(--shadow-color) !important;
1054
- background-color: var(--card-background) !important;
1055
- border: none !important;
1056
- overflow: hidden !important;
1057
- padding: 20px !important;
1058
- margin-bottom: 20px !important;
1059
- }
1060
-
1061
- /* Button styling */
1062
- button.gr-button {
1063
- background: linear-gradient(135deg, var(--primary-color), #e1bee7) !important;
1064
- border-radius: var(--border-radius) !important;
1065
- color: #4a148c !important;
1066
- font-weight: 600 !important;
1067
- border: none !important;
1068
- padding: 10px 20px !important;
1069
- transition: all 0.3s ease !important;
1070
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
1071
- }
1072
-
1073
- button.gr-button:hover {
1074
- transform: translateY(-2px) !important;
1075
- box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15) !important;
1076
- background: linear-gradient(135deg, #e1bee7, var(--primary-color)) !important;
1077
- }
1078
-
1079
- /* Input fields styling */
1080
- input, select, textarea, .gr-input {
1081
- border-radius: 8px !important;
1082
- border: 2px solid #e0e0e0 !important;
1083
- padding: 10px 15px !important;
1084
- transition: all 0.3s ease !important;
1085
- background-color: #fafafa !important;
1086
- }
1087
-
1088
- input:focus, select:focus, textarea:focus, .gr-input:focus {
1089
- border-color: var(--primary-color) !important;
1090
- box-shadow: 0 0 0 3px rgba(248, 195, 205, 0.3) !important;
1091
- }
1092
-
1093
- /* Slider styling */
1094
- .gr-form input[type=range] {
1095
- appearance: none !important;
1096
- width: 100% !important;
1097
- height: 6px !important;
1098
- background: #e0e0e0 !important;
1099
- border-radius: 5px !important;
1100
- outline: none !important;
1101
- }
1102
-
1103
- .gr-form input[type=range]::-webkit-slider-thumb {
1104
- appearance: none !important;
1105
- width: 16px !important;
1106
- height: 16px !important;
1107
- background: var(--primary-color) !important;
1108
- border-radius: 50% !important;
1109
- cursor: pointer !important;
1110
- border: 2px solid white !important;
1111
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
1112
- }
1113
-
1114
- /* Dropdown styling */
1115
- .gr-form select {
1116
- background-color: white !important;
1117
- border: 2px solid #e0e0e0 !important;
1118
- border-radius: 8px !important;
1119
- padding: 10px 15px !important;
1120
- }
1121
-
1122
- .gr-form select option {
1123
- padding: 10px !important;
1124
- }
1125
-
1126
- /* Image upload area */
1127
- .gr-image-input {
1128
- border: 2px dashed #b39ddb !important;
1129
- border-radius: var(--border-radius) !important;
1130
- background-color: #f3e5f5 !important;
1131
- padding: 20px !important;
1132
- display: flex !important;
1133
- flex-direction: column !important;
1134
- align-items: center !important;
1135
- justify-content: center !important;
1136
- transition: all 0.3s ease !important;
1137
- }
1138
-
1139
- .gr-image-input:hover {
1140
- background-color: #ede7f6 !important;
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 */
1150
- .gr-gallery {
1151
- grid-gap: 15px !important;
1152
- }
1153
-
1154
- .gr-gallery-item {
1155
- border-radius: var(--border-radius) !important;
1156
- overflow: hidden !important;
1157
- box-shadow: 0 4px 8px var(--shadow-color) !important;
1158
- transition: transform 0.3s ease !important;
1159
- }
1160
-
1161
- .gr-gallery-item:hover {
1162
- transform: scale(1.02) !important;
1163
- }
1164
-
1165
- /* Label styling */
1166
- .gr-form label {
1167
- font-weight: 600 !important;
1168
- color: #673ab7 !important;
1169
- margin-bottom: 5px !important;
1170
- }
1171
-
1172
- /* Improve spacing */
1173
- .gr-padded {
1174
- padding: 20px !important;
1175
- }
1176
-
1177
- .gr-compact {
1178
- gap: 15px !important;
1179
- }
1180
-
1181
- .gr-form > div {
1182
- margin-bottom: 16px !important;
1183
- }
1184
-
1185
- /* Headings */
1186
- .gr-form h3 {
1187
- color: #7b1fa2 !important;
1188
- margin-top: 5px !important;
1189
- margin-bottom: 15px !important;
1190
- border-bottom: 2px solid #e1bee7 !important;
1191
- padding-bottom: 8px !important;
1192
- }
1193
-
1194
- /* Examples section */
1195
- #examples-panel {
1196
- background-color: #f3e5f5 !important;
1197
- border-radius: var(--border-radius) !important;
1198
- padding: 15px !important;
1199
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05) !important;
1200
- }
1201
-
1202
- #examples-panel h2 {
1203
- color: #7b1fa2 !important;
1204
- font-size: 1.5rem !important;
1205
- margin-bottom: 15px !important;
1206
- }
1207
-
1208
- /* Accordion styling */
1209
- .gr-accordion {
1210
- border: 1px solid #e0e0e0 !important;
1211
- border-radius: var(--border-radius) !important;
1212
- overflow: hidden !important;
1213
- }
1214
-
1215
- .gr-accordion summary {
1216
- padding: 12px 16px !important;
1217
- background-color: #f9f9f9 !important;
1218
- cursor: pointer !important;
1219
- font-weight: 600 !important;
1220
- color: #673ab7 !important;
1221
- }
1222
-
1223
- /* Generate button special styling */
1224
- #generate-btn {
1225
- background: linear-gradient(135deg, #ff9a9e, #fad0c4) !important;
1226
- font-size: 1.1rem !important;
1227
- padding: 12px 24px !important;
1228
- margin-top: 10px !important;
1229
- margin-bottom: 15px !important;
1230
- width: 100% !important;
1231
- }
1232
-
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>
1265
- </div>
1266
-
1267
- <div style="background: white; padding: 15px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);">
1268
- <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>
1269
- </div>
1270
-
1271
- </div>
1272
-
1273
- <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);">
1274
- <h3 style="margin-top: 0; color: #ff6f00;">๐Ÿšฉ Update Notes:</h3>
1275
- <ul style="margin-bottom: 0; padding-left: 20px;">
1276
- <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>
1277
- <li><b>2025.05.13:</b> 'DreamO Video' Integration version Release</li>
1278
- </ul>
1279
- </div>
1280
- '''
1281
-
1282
- _CITE_ = r"""
1283
- <div style="background: white; padding: 20px; border-radius: 12px; margin-top: 20px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);">
1284
- <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>
1285
- <hr style="border: none; height: 1px; background-color: #e0e0e0; margin: 15px 0;">
1286
- <h4 style="margin: 0 0 10px; color: #7b1fa2;">๐Ÿ“ง Contact</h4>
1287
- <p style="margin: 0;">If you have any questions or feedback, feel free to open a discussion or contact <b>[email protected]</b></p>
1288
- </div>
1289
- """
1290
-
1291
- def create_demo():
1292
- with gr.Blocks(css=_CUSTOM_CSS_) as demo:
1293
- gr.HTML(_HEADER_)
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>
1301
-
1302
- <a href="https://discord.gg/openfreeai" target="_blank">
1303
- <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">
1304
- </a>
1305
- </div>
1306
- """
1307
- )
1308
-
1309
- with gr.Row():
1310
- with gr.Column(scale=6):
1311
- with gr.Group(elem_id="input-panel", elem_classes="panel-box"):
1312
- gr.Markdown("### ๐Ÿ“ธ Reference Images")
1313
- with gr.Row():
1314
- with gr.Column():
1315
- ref_image1 = gr.Image(label="Reference Image 1", type="numpy", height=256, elem_id="ref-image-1")
1316
- ref_task1 = gr.Dropdown(choices=["ip", "id", "style"], value="ip", label="Task for Reference Image 1", elem_id="ref-task-1")
1317
-
1318
- with gr.Column():
1319
- ref_image2 = gr.Image(label="Reference Image 2", type="numpy", height=256, elem_id="ref-image-2")
1320
- ref_task2 = gr.Dropdown(choices=["ip", "id", "style"], value="ip", label="Task for Reference Image 2", elem_id="ref-task-2")
1321
-
1322
- gr.Markdown("### โœ๏ธ Generation Parameters")
1323
- prompt = gr.Textbox(label="Prompt", value="a person playing guitar in the street", elem_id="prompt-input")
1324
-
1325
- with gr.Row():
1326
- width = gr.Slider(768, 1024, 1024, step=16, label="Width", elem_id="width-slider")
1327
- height = gr.Slider(768, 1024, 1024, step=16, label="Height", elem_id="height-slider")
1328
-
1329
- with gr.Row():
1330
- num_steps = gr.Slider(8, 30, 12, step=1, label="Number of Steps", elem_id="steps-slider")
1331
- guidance = gr.Slider(1.0, 10.0, 3.5, step=0.1, label="Guidance Scale", elem_id="guidance-slider")
1332
-
1333
- seed = gr.Textbox(label="Seed (-1 for random)", value="-1", elem_id="seed-input")
1334
-
1335
- with gr.Accordion("Advanced Options", open=False):
1336
- ref_res = gr.Slider(512, 1024, 512, step=16, label="Resolution for Reference Image")
1337
- neg_prompt = gr.Textbox(label="Negative Prompt", value="")
1338
- neg_guidance = gr.Slider(1.0, 10.0, 3.5, step=0.1, label="Negative Guidance")
1339
-
1340
- with gr.Row():
1341
- true_cfg = gr.Slider(1, 5, 1, step=0.1, label="True CFG")
1342
- first_step_guidance = gr.Slider(0, 10, 0, step=0.1, label="First Step Guidance")
1343
-
1344
- with gr.Row():
1345
- cfg_start_step = gr.Slider(0, 30, 0, step=1, label="CFG Start Step")
1346
- cfg_end_step = gr.Slider(0, 30, 0, step=1, label="CFG End Step")
1347
-
1348
- generate_btn = gr.Button("โœจ Generate Image", elem_id="generate-btn")
1349
- gr.HTML(_CITE_)
1350
-
1351
- with gr.Column(scale=6):
1352
- with gr.Group(elem_id="output-panel", elem_classes="panel-box"):
1353
- gr.Markdown("### ๐Ÿ–ผ๏ธ Generated Result")
1354
- output_image = gr.Image(label="Generated Image", elem_id="output-image", format='png')
1355
- seed_output = gr.Textbox(label="Used Seed", elem_id="seed-output")
1356
-
1357
- # (2) ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ & ์ถœ๋ ฅ ์˜์—ญ ์ถ”๊ฐ€
1358
- generate_video_btn = gr.Button("๐ŸŽฌ Generate Video from Image")
1359
- output_video = gr.Video(label="Generated Video", elem_id="video-output")
1360
-
1361
- gr.Markdown("### ๐Ÿ” Preprocessing")
1362
- debug_image = gr.Gallery(
1363
- label="Preprocessing Results (including face crop and background removal)",
1364
- elem_id="debug-gallery",
1365
- )
1366
-
1367
- with gr.Group(elem_id="examples-panel", elem_classes="panel-box"):
1368
- gr.Markdown("## ๐Ÿ“š Examples")
1369
- example_inps = [
1370
- [
1371
- 'example_inputs/choi.jpg',
1372
- None,
1373
- 'ip',
1374
- 'ip',
1375
- 'a woman sitting on the cloud, playing guitar',
1376
- 1206523688721442817,
1377
- ],
1378
- [
1379
- 'example_inputs/choi.jpg',
1380
- None,
1381
- 'id',
1382
- 'ip',
1383
- 'a woman holding a sign saying "TOP", on the mountain',
1384
- 10441727852953907380,
1385
- ],
1386
- [
1387
- 'example_inputs/perfume.png',
1388
- None,
1389
- 'ip',
1390
- 'ip',
1391
- 'a perfume under spotlight',
1392
- 116150031980664704,
1393
- ],
1394
- [
1395
- 'example_inputs/choi.jpg',
1396
- None,
1397
- 'id',
1398
- 'ip',
1399
- 'portrait, in alps',
1400
- 5443415087540486371,
1401
- ],
1402
- [
1403
- 'example_inputs/mickey.png',
1404
- None,
1405
- 'style',
1406
- 'ip',
1407
- 'generate a same style image. A rooster wearing overalls.',
1408
- 6245580464677124951,
1409
- ],
1410
- [
1411
- 'example_inputs/mountain.png',
1412
- None,
1413
- 'style',
1414
- 'ip',
1415
- 'generate a same style image. A pavilion by the river, and the distant mountains are endless',
1416
- 5248066378927500767,
1417
- ],
1418
- [
1419
- 'example_inputs/shirt.png',
1420
- 'example_inputs/skirt.jpeg',
1421
- 'ip',
1422
- 'ip',
1423
- 'A girl is wearing a short-sleeved shirt and a short skirt on the beach.',
1424
- 9514069256241143615,
1425
- ],
1426
- [
1427
- 'example_inputs/woman2.png',
1428
- 'example_inputs/dress.png',
1429
- 'id',
1430
- 'ip',
1431
- 'the woman wearing a dress, In the banquet hall',
1432
- 7698454872441022867,
1433
- ],
1434
- [
1435
- 'example_inputs/dog1.png',
1436
- 'example_inputs/dog2.png',
1437
- 'ip',
1438
- 'ip',
1439
- 'two dogs in the jungle',
1440
- 6187006025405083344,
1441
- ],
1442
- ]
1443
- gr.Examples(
1444
- examples=example_inps,
1445
- inputs=[ref_image1, ref_image2, ref_task1, ref_task2, prompt, seed],
1446
- label='Examples by category: IP task (rows 1-4), ID task (row 5), Style task (rows 6-7), Try-On task (rows 8-9)',
1447
- cache_examples='lazy',
1448
- outputs=[output_image, debug_image, seed_output],
1449
- fn=generate_image,
1450
- )
1451
-
1452
- # ๊ธฐ์กด ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜์™€ ์—ฐ๊ฒฐ
1453
- generate_btn.click(
1454
- fn=generate_image,
1455
- inputs=[
1456
- ref_image1,
1457
- ref_image2,
1458
- ref_task1,
1459
- ref_task2,
1460
- prompt,
1461
- seed,
1462
- width,
1463
- height,
1464
- ref_res,
1465
- num_steps,
1466
- guidance,
1467
- true_cfg,
1468
- cfg_start_step,
1469
- cfg_end_step,
1470
- neg_prompt,
1471
- neg_guidance,
1472
- first_step_guidance,
1473
- ],
1474
- outputs=[output_image, debug_image, seed_output],
1475
- )
1476
-
1477
- # (3) ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ -> generate_video_from_image() ํ˜ธ์ถœ
1478
  def on_click_generate_video(img):
1479
  if img is None:
1480
  raise gr.Error("๋จผ์ € ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.")
 
153
 
154
 
155
  # -----------------------------
156
+ # ์˜์ƒ API ํ˜ธ์ถœ์„ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฝ”๋“œ
157
  # -----------------------------
158
  import requests
159
  import random
 
161
  import subprocess
162
  from gradio_client import Client, handle_file
163
 
164
+ # ์›๊ฒฉ ์„œ๋ฒ„ Endpoint
165
  REMOTE_ENDPOINT = os.getenv("H100_URL")
166
 
167
  client = Client(REMOTE_ENDPOINT)
 
169
  def run_process_video_api(image_path: str, prompt: str, video_length: float = 2.0):
170
  """
171
  ์›๊ฒฉ /process ์—”๋“œํฌ์ธํŠธ ํ˜ธ์ถœํ•˜์—ฌ ์˜์ƒ์„ ์ƒ์„ฑ.
 
172
  """
173
  # ๋žœ๋ค ์‹œ๋“œ
174
  seed_val = random.randint(0, 9999999)
 
604
  output_image = gr.Image(label="Generated Image", elem_id="output-image", format='png')
605
  seed_output = gr.Textbox(label="Used Seed", elem_id="seed-output")
606
 
607
+ # ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ & ์ถœ๋ ฅ ์˜์—ญ
608
  generate_video_btn = gr.Button("๐ŸŽฌ Generate Video from Image")
609
  output_video = gr.Video(label="Generated Video", elem_id="video-output")
610
 
 
699
  fn=generate_image,
700
  )
701
 
702
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜์™€ ์—ฐ๊ฒฐ
703
  generate_btn.click(
704
  fn=generate_image,
705
  inputs=[
 
724
  outputs=[output_image, debug_image, seed_output],
725
  )
726
 
727
+ # ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ -> generate_video_from_image() ํ˜ธ์ถœ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
728
  def on_click_generate_video(img):
729
  if img is None:
730
  raise gr.Error("๋จผ์ € ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.")