dream2589632147 commited on
Commit
724cc21
·
verified ·
1 Parent(s): 05dfabe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +10 -157
app.py CHANGED
@@ -15,9 +15,7 @@ import math
15
  from huggingface_hub import hf_hub_download
16
  from safetensors.torch import load_file
17
 
18
- from PIL import Image
19
  import os
20
- import gradio as gr
21
  from gradio_client import Client, handle_file
22
  import tempfile
23
  from typing import Optional, Tuple, Any
@@ -70,38 +68,25 @@ def _generate_video_segment(
70
  """
71
  Generate a single video segment between two frames by calling an external
72
  Wan 2.2 image-to-video service hosted on Hugging Face Spaces.
73
-
74
- This helper function is used internally when the user asks to create
75
- a video between the input and output images.
76
-
77
- Args:
78
- input_image_path (str):
79
- Path to the starting frame image on disk.
80
- output_image_path (str):
81
- Path to the ending frame image on disk.
82
- prompt (str):
83
- Text prompt describing the camera movement / transition.
84
- request (gr.Request):
85
- Gradio request object, used here to forward the `x-ip-token`
86
- header to the downstream Space for authentication/rate limiting.
87
-
88
- Returns:
89
- str:
90
- A string returned by the external service, usually a URL or path
91
- to the generated video.
92
  """
93
  x_ip_token = request.headers['x-ip-token']
94
  video_client = Client(
95
  "multimodalart/wan-2-2-first-last-frame",
96
  headers={"x-ip-token": x_ip_token}
97
  )
 
 
98
  result = video_client.predict(
99
  start_image_pil=handle_file(input_image_path),
100
  end_image_pil=handle_file(output_image_path),
101
  prompt=prompt,
102
  api_name="/generate_video",
103
  )
104
- return result[0]["video"]
 
 
 
 
105
 
106
 
107
  def build_camera_prompt(
@@ -112,28 +97,6 @@ def build_camera_prompt(
112
  ) -> str:
113
  """
114
  Build a camera movement prompt based on the chosen controls.
115
-
116
- This converts the provided control values into a prompt instruction with the corresponding trigger words for the multiple-angles LoRA.
117
-
118
- Args:
119
- rotate_deg (float, optional):
120
- Horizontal rotation in degrees. Positive values rotate left,
121
- negative values rotate right. Defaults to 0.0.
122
- move_forward (float, optional):
123
- Forward movement / zoom factor. Larger values imply moving the
124
- camera closer or into a close-up. Defaults to 0.0.
125
- vertical_tilt (float, optional):
126
- Vertical angle of the camera:
127
- - Negative ≈ bird's-eye view
128
- - Positive ≈ worm's-eye view
129
- Defaults to 0.0.
130
- wideangle (bool, optional):
131
- Whether to switch to a wide-angle lens style. Defaults to False.
132
-
133
- Returns:
134
- str:
135
- A text prompt describing the camera motion. If no controls are
136
- active, returns `"no camera movement"`.
137
  """
138
  prompt_parts = []
139
 
@@ -185,56 +148,10 @@ def infer_camera_edit(
185
  prev_output: Optional[Image.Image] = None,
186
  ) -> Tuple[Image.Image, int, str]:
187
  """
188
- Edit the camera angles/view of an image with Qwen Image Edit 2509 and dx8152's Qwen-Edit-2509-Multiple-angles LoRA.
189
-
190
- Applies a camera-style transformation (rotation, zoom, tilt, lens)
191
- to an input image.
192
-
193
- Args:
194
- image (PIL.Image.Image | None, optional):
195
- Input image to edit. If `None`, the function will instead try to
196
- use `prev_output`. At least one of `image` or `prev_output` must
197
- be available. Defaults to None.
198
- rotate_deg (float, optional):
199
- Horizontal rotation in degrees (-90, -45, 0, 45, 90). Positive values rotate
200
- to the left, negative to the right. Defaults to 0.0.
201
- move_forward (float, optional):
202
- Forward movement / zoom factor (0, 5, 10). Higher values move the
203
- camera closer; values >5 switch to a close-up style. Defaults to 0.0.
204
- vertical_tilt (float, optional):
205
- Vertical tilt (-1 to 1). -1 ≈ bird's-eye view, +1 ≈ worm's-eye view.
206
- Defaults to 0.0.
207
- wideangle (bool, optional):
208
- Whether to use a wide-angle lens style. Defaults to False.
209
- seed (int, optional):
210
- Random seed for the generation. Ignored if `randomize_seed=True`.
211
- Defaults to 0.
212
- randomize_seed (bool, optional):
213
- If True, a random seed (0..MAX_SEED) is chosen per call.
214
- Defaults to True.
215
- true_guidance_scale (float, optional):
216
- CFG / guidance scale controlling prompt adherence.
217
- Defaults to 1.0 since the demo is using a distilled transformer for faster inference.
218
- num_inference_steps (int, optional):
219
- Number of inference steps. Defaults to 4.
220
- height (int, optional):
221
- Output image height. Must typically be a multiple of 8.
222
- If set to 0, the model will infer a size. Defaults to 1024 if none is provided.
223
- width (int, optional):
224
- Output image width. Must typically be a multiple of 8.
225
- If set to 0, the model will infer a size. Defaults to 1024 if none is provided.
226
- prev_output (PIL.Image.Image | None, optional):
227
- Previous output image to use as input when no new image is uploaded.
228
- Defaults to None.
229
-
230
- Returns:
231
- Tuple[PIL.Image.Image, int, str]:
232
- - The edited output image.
233
- - The actual seed used for generation.
234
- - The constructed camera prompt string.
235
  """
236
  progress = gr.Progress(track_tqdm=True)
237
-
238
  prompt = build_camera_prompt(rotate_deg, move_forward, vertical_tilt, wideangle)
239
  print(f"Generated Prompt: {prompt}")
240
 
@@ -281,25 +198,6 @@ def create_video_between_images(
281
  """
282
  Create a short transition video between the input and output images via the
283
  Wan 2.2 first-last-frame Space.
284
-
285
- Args:
286
- input_image (PIL.Image.Image | None):
287
- Starting frame image (the original / previous view).
288
- output_image (numpy.ndarray | None):
289
- Ending frame image - the output image with the the edited camera angles.
290
- prompt (str):
291
- The camera movement prompt used to describe the transition.
292
- request (gr.Request):
293
- Gradio request object, used to forward the `x-ip-token` header
294
- to the video generation app.
295
-
296
- Returns:
297
- str:
298
- a path pointing to the generated video.
299
-
300
- Raises:
301
- gr.Error:
302
- If either image is missing or if the video generation fails.
303
  """
304
  if input_image is None or output_image is None:
305
  raise gr.Error("Both input and output images are required to create a video.")
@@ -334,33 +232,11 @@ css = '''#col-container { max-width: 800px; margin: 0 auto; }
334
  def reset_all() -> list:
335
  """
336
  Reset all camera control knobs and flags to their default values.
337
-
338
- This is used by the "Reset" button to set:
339
- - rotate_deg = 0
340
- - move_forward = 0
341
- - vertical_tilt = 0
342
- - wideangle = False
343
- - is_reset = True
344
-
345
- Returns:
346
- list:
347
- A list of values matching the order of the reset outputs:
348
- [rotate_deg, move_forward, vertical_tilt, wideangle, is_reset, True]
349
  """
350
  return [0, 0, 0, 0, False, True]
351
 
352
 
353
  def end_reset() -> bool:
354
- """
355
- Mark the end of a reset cycle.
356
-
357
- This helper is chained after `reset_all` to set the internal
358
- `is_reset` flag back to False, so that live inference can resume.
359
-
360
- Returns:
361
- bool:
362
- Always returns False.
363
- """
364
  return False
365
 
366
 
@@ -370,14 +246,6 @@ def update_dimensions_on_upload(
370
  """
371
  Compute recommended (width, height) for the output resolution when an
372
  image is uploaded while preserveing the aspect ratio.
373
-
374
- Args:
375
- image (PIL.Image.Image | None):
376
- The uploaded image. If `None`, defaults to (1024, 1024).
377
-
378
- Returns:
379
- Tuple[int, int]:
380
- The new (width, height).
381
  """
382
  if image is None:
383
  return 1024, 1024
@@ -515,21 +383,6 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
515
 
516
  # Manual generation with video button visibility control
517
  def infer_and_show_video_button(*args: Any):
518
- """
519
- Wrapper around `infer_camera_edit` that also controls the visibility
520
- of the 'Create Video Between Images' button.
521
-
522
- The first argument in `args` is expected to be the input image; if both
523
- input and output images are present, the video button is shown.
524
-
525
- Args:
526
- *args:
527
- Positional arguments forwarded directly to `infer_camera_edit`.
528
-
529
- Returns:
530
- tuple:
531
- (output_image, seed, prompt, video_button_visibility_update)
532
- """
533
  result_img, result_seed, result_prompt = infer_camera_edit(*args)
534
  # Show video button if we have both input and output images
535
  show_button = args[0] is not None and result_img is not None
@@ -629,4 +482,4 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
629
  gr.api(infer_camera_edit, api_name="infer_edit_camera_angles")
630
  gr.api(create_video_between_images, api_name="create_video_between_images")
631
 
632
- demo.launch(mcp_server=True, show_api=True)
 
15
  from huggingface_hub import hf_hub_download
16
  from safetensors.torch import load_file
17
 
 
18
  import os
 
19
  from gradio_client import Client, handle_file
20
  import tempfile
21
  from typing import Optional, Tuple, Any
 
68
  """
69
  Generate a single video segment between two frames by calling an external
70
  Wan 2.2 image-to-video service hosted on Hugging Face Spaces.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  """
72
  x_ip_token = request.headers['x-ip-token']
73
  video_client = Client(
74
  "multimodalart/wan-2-2-first-last-frame",
75
  headers={"x-ip-token": x_ip_token}
76
  )
77
+
78
+ # استدعاء التوقع
79
  result = video_client.predict(
80
  start_image_pil=handle_file(input_image_path),
81
  end_image_pil=handle_file(output_image_path),
82
  prompt=prompt,
83
  api_name="/generate_video",
84
  )
85
+
86
+ # --- FIX START ---
87
+ # الخطأ كان هنا: result[0] هو مسار الفيديو مباشرة كنص، وليس قاموساً
88
+ return result[0]
89
+ # --- FIX END ---
90
 
91
 
92
  def build_camera_prompt(
 
97
  ) -> str:
98
  """
99
  Build a camera movement prompt based on the chosen controls.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  """
101
  prompt_parts = []
102
 
 
148
  prev_output: Optional[Image.Image] = None,
149
  ) -> Tuple[Image.Image, int, str]:
150
  """
151
+ Edit the camera angles/view of an image with Qwen Image Edit 2509.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  """
153
  progress = gr.Progress(track_tqdm=True)
154
+
155
  prompt = build_camera_prompt(rotate_deg, move_forward, vertical_tilt, wideangle)
156
  print(f"Generated Prompt: {prompt}")
157
 
 
198
  """
199
  Create a short transition video between the input and output images via the
200
  Wan 2.2 first-last-frame Space.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  """
202
  if input_image is None or output_image is None:
203
  raise gr.Error("Both input and output images are required to create a video.")
 
232
  def reset_all() -> list:
233
  """
234
  Reset all camera control knobs and flags to their default values.
 
 
 
 
 
 
 
 
 
 
 
 
235
  """
236
  return [0, 0, 0, 0, False, True]
237
 
238
 
239
  def end_reset() -> bool:
 
 
 
 
 
 
 
 
 
 
240
  return False
241
 
242
 
 
246
  """
247
  Compute recommended (width, height) for the output resolution when an
248
  image is uploaded while preserveing the aspect ratio.
 
 
 
 
 
 
 
 
249
  """
250
  if image is None:
251
  return 1024, 1024
 
383
 
384
  # Manual generation with video button visibility control
385
  def infer_and_show_video_button(*args: Any):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  result_img, result_seed, result_prompt = infer_camera_edit(*args)
387
  # Show video button if we have both input and output images
388
  show_button = args[0] is not None and result_img is not None
 
482
  gr.api(infer_camera_edit, api_name="infer_edit_camera_angles")
483
  gr.api(create_video_between_images, api_name="create_video_between_images")
484
 
485
+ demo.launch(mcp_server=True, show_api=True)