openfree commited on
Commit
f9ed6cb
ยท
verified ยท
1 Parent(s): 5c0cffc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -5
app.py CHANGED
@@ -152,7 +152,107 @@ def generate_image(
152
  return image, debug_images, seed
153
 
154
 
155
- # Custom CSS for pastel theme
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  _CUSTOM_CSS_ = """
157
  :root {
158
  --primary-color: #f8c3cd; /* Sakura pink - primary accent */
@@ -419,7 +519,6 @@ def create_demo():
419
 
420
  with gr.Row():
421
  with gr.Column(scale=6):
422
- # Input panel - using a Group div with custom class instead of Box
423
  with gr.Group(elem_id="input-panel", elem_classes="panel-box"):
424
  gr.Markdown("### ๐Ÿ“ธ Reference Images")
425
  with gr.Row():
@@ -461,19 +560,21 @@ def create_demo():
461
  gr.HTML(_CITE_)
462
 
463
  with gr.Column(scale=6):
464
- # Output panel - using a Group div with custom class instead of Box
465
  with gr.Group(elem_id="output-panel", elem_classes="panel-box"):
466
  gr.Markdown("### ๐Ÿ–ผ๏ธ Generated Result")
467
  output_image = gr.Image(label="Generated Image", elem_id="output-image", format='png')
468
  seed_output = gr.Textbox(label="Used Seed", elem_id="seed-output")
469
 
 
 
 
 
470
  gr.Markdown("### ๐Ÿ” Preprocessing")
471
  debug_image = gr.Gallery(
472
  label="Preprocessing Results (including face crop and background removal)",
473
  elem_id="debug-gallery",
474
  )
475
 
476
- # Examples panel - using a Group div with custom class instead of Box
477
  with gr.Group(elem_id="examples-panel", elem_classes="panel-box"):
478
  gr.Markdown("## ๐Ÿ“š Examples")
479
  example_inps = [
@@ -559,6 +660,7 @@ def create_demo():
559
  fn=generate_image,
560
  )
561
 
 
562
  generate_btn.click(
563
  fn=generate_image,
564
  inputs=[
@@ -583,9 +685,22 @@ def create_demo():
583
  outputs=[output_image, debug_image, seed_output],
584
  )
585
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
  return demo
587
 
588
 
589
  if __name__ == '__main__':
590
  demo = create_demo()
591
- demo.launch()
 
152
  return image, debug_images, seed
153
 
154
 
155
+ # -----------------------------
156
+ # (1) ์—ฌ๊ธฐ์— ์˜์ƒ API ํ˜ธ์ถœ์„ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฝ”๋“œ
157
+ # -----------------------------
158
+ import requests
159
+ import random
160
+ import tempfile
161
+ import subprocess
162
+ from gradio_client import Client, handle_file
163
+
164
+ # ์˜ˆ์‹œ: ์›๊ฒฉ ์„œ๋ฒ„ Endpoint (ํ•„์š”ํ•˜๋‹ค๋ฉด ์ˆ˜์ •)
165
+ REMOTE_ENDPOINT = "http://211.233.58.201:7875/"
166
+
167
+ client = Client(REMOTE_ENDPOINT)
168
+
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)
176
+ # negative_prompt = "" ๋“ฑ ๊ณ ์ •
177
+ negative_prompt = ""
178
+ use_teacache = True
179
+
180
+ # /process ํ˜ธ์ถœ (gradio_client)
181
+ result = client.predict(
182
+ input_image=handle_file(image_path),
183
+ prompt=prompt,
184
+ n_prompt=negative_prompt,
185
+ seed=seed_val,
186
+ use_teacache=use_teacache,
187
+ video_length=video_length,
188
+ api_name="/process",
189
+ )
190
+ # result๋Š” (video_dict, preview_dict, md_text, html_text) ๊ตฌ์กฐ
191
+ video_dict, preview_dict, md_text, html_text = result
192
+ video_path = video_dict.get("video") if isinstance(video_dict, dict) else None
193
+ return video_path
194
+
195
+ def add_watermark_to_video(input_video_path: str, watermark_text="Ginigen.com") -> str:
196
+ """
197
+ FFmpeg๋กœ ์˜์ƒ์— ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ ์›Œํ„ฐ๋งˆํฌ๋ฅผ ์ถ”๊ฐ€ํ•œ ์ƒˆ ์˜์ƒ์„ ๋ฆฌํ„ด
198
+ """
199
+ if not os.path.exists(input_video_path):
200
+ raise FileNotFoundError(f"Input video not found: {input_video_path}")
201
+
202
+ # ์ถœ๋ ฅ ๊ฒฝ๋กœ
203
+ base, ext = os.path.splitext(input_video_path)
204
+ watermarked_path = base + "_wm" + ext
205
+ # ffmpeg ๋ช…๋ น์–ด ๊ตฌ์„ฑ
206
+ # - y: ๋ฎ์–ด์“ฐ๊ธฐ
207
+ # drawtext ํ•„ํ„ฐ๋กœ ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ(x=w-tw-10, y=h-th-10)์— boxcolor=black ๋ฐ˜ํˆฌ๋ช… ๋ฐ•์Šค
208
+ cmd = [
209
+ "ffmpeg", "-y",
210
+ "-i", input_video_path,
211
+ "-vf", f"drawtext=fontsize=20:fontcolor=white:text='{watermark_text}':x=w-tw-10:y=h-th-10:box=1:[email protected]:boxborderw=5",
212
+ "-codec:a", "copy",
213
+ watermarked_path
214
+ ]
215
+ try:
216
+ subprocess.run(cmd, check=True)
217
+ except Exception as e:
218
+ print(f"[WARN] FFmpeg watermark failed: {e}")
219
+ return input_video_path # ์‹คํŒจ ์‹œ ์›๋ณธ ๋ฐ˜ํ™˜
220
+
221
+ return watermarked_path
222
+
223
+ def generate_video_from_image(image_array: np.ndarray):
224
+ """
225
+ 1) Numpy ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
226
+ 2) ์›๊ฒฉ API๋กœ 2์ดˆ ์˜์ƒ ์ƒ์„ฑ (๊ธฐ๋ณธ prompt ๊ณ ์ •)
227
+ 3) FFmpeg๋กœ 'Ginigen.com' ์›Œํ„ฐ๋งˆํฌ ์ถ”๊ฐ€
228
+ 4) ์ตœ์ข… mp4 ๊ฒฝ๋กœ ๋ฐ˜ํ™˜
229
+ """
230
+ if image_array is None:
231
+ raise gr.Error("์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")
232
+
233
+ # (1) ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
234
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as fp:
235
+ temp_img_path = fp.name
236
+ Image.fromarray(image_array).save(temp_img_path, format="PNG")
237
+
238
+ # (2) ์›๊ฒฉ API ํ˜ธ์ถœ
239
+ default_video_prompt = "Generate a video with smooth and natural movement. Objects should have visible motion while maintaining fluid transitions."
240
+ result_video_path = run_process_video_api(
241
+ image_path=temp_img_path,
242
+ prompt=default_video_prompt,
243
+ video_length=2.0,
244
+ )
245
+ if result_video_path is None:
246
+ raise gr.Error("์˜์ƒ API ํ˜ธ์ถœ ์‹คํŒจ ๋˜๋Š” ๊ฒฐ๊ณผ ์—†์Œ")
247
+
248
+ # (3) FFmpeg ์›Œํ„ฐ๋งˆํฌ ์ถ”๊ฐ€
249
+ final_video = add_watermark_to_video(result_video_path, watermark_text="Ginigen.com")
250
+ return final_video
251
+
252
+
253
+ # -----------------------------
254
+ # Custom CSS, Headers, etc.
255
+ # -----------------------------
256
  _CUSTOM_CSS_ = """
257
  :root {
258
  --primary-color: #f8c3cd; /* Sakura pink - primary accent */
 
519
 
520
  with gr.Row():
521
  with gr.Column(scale=6):
 
522
  with gr.Group(elem_id="input-panel", elem_classes="panel-box"):
523
  gr.Markdown("### ๐Ÿ“ธ Reference Images")
524
  with gr.Row():
 
560
  gr.HTML(_CITE_)
561
 
562
  with gr.Column(scale=6):
 
563
  with gr.Group(elem_id="output-panel", elem_classes="panel-box"):
564
  gr.Markdown("### ๐Ÿ–ผ๏ธ Generated Result")
565
  output_image = gr.Image(label="Generated Image", elem_id="output-image", format='png')
566
  seed_output = gr.Textbox(label="Used Seed", elem_id="seed-output")
567
 
568
+ # (2) ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ & ์ถœ๋ ฅ ์˜์—ญ ์ถ”๊ฐ€
569
+ generate_video_btn = gr.Button("๐ŸŽฌ Generate Video from Image")
570
+ output_video = gr.Video(label="Generated Video", elem_id="video-output")
571
+
572
  gr.Markdown("### ๐Ÿ” Preprocessing")
573
  debug_image = gr.Gallery(
574
  label="Preprocessing Results (including face crop and background removal)",
575
  elem_id="debug-gallery",
576
  )
577
 
 
578
  with gr.Group(elem_id="examples-panel", elem_classes="panel-box"):
579
  gr.Markdown("## ๐Ÿ“š Examples")
580
  example_inps = [
 
660
  fn=generate_image,
661
  )
662
 
663
+ # ๊ธฐ์กด ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜์™€ ์—ฐ๊ฒฐ
664
  generate_btn.click(
665
  fn=generate_image,
666
  inputs=[
 
685
  outputs=[output_image, debug_image, seed_output],
686
  )
687
 
688
+ # (3) ์˜์ƒ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ -> generate_video_from_image() ํ˜ธ์ถœ
689
+ def on_click_generate_video(img):
690
+ if img is None:
691
+ raise gr.Error("๋จผ์ € ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.")
692
+ video_path = generate_video_from_image(img)
693
+ return video_path
694
+
695
+ generate_video_btn.click(
696
+ fn=on_click_generate_video,
697
+ inputs=[output_image],
698
+ outputs=[output_video],
699
+ )
700
+
701
  return demo
702
 
703
 
704
  if __name__ == '__main__':
705
  demo = create_demo()
706
+ demo.launch(server_port=args.port)