multimodalart HF Staff commited on
Commit
596ce81
·
verified ·
1 Parent(s): 9d7c660

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -7
app.py CHANGED
@@ -1,4 +1,5 @@
1
  import gradio as gr
 
2
  from google import genai
3
  from google.genai import types
4
  import os
@@ -49,11 +50,10 @@ def unified_image_generator(
49
  prompt: str,
50
  images: Optional[List[str]] = None,
51
  oauth_token: Optional[gr.OAuthToken] = None
52
- ) -> str:
53
  """
54
  Handles all image generation tasks based on the number of input images.
55
- - 0 images: Text-to-image
56
- - 1+ images: Image-to-image (single or multi-modal)
57
  """
58
  if not verify_pro_status(oauth_token):
59
  raise gr.Error("Access Denied. This service is for PRO users only.")
@@ -84,11 +84,50 @@ def unified_image_generator(
84
  pil_image = Image.open(BytesIO(image_data))
85
  with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
86
  pil_image.save(tmpfile.name)
87
- return tmpfile.name
 
 
 
 
 
 
88
 
89
  except Exception as e:
90
  raise gr.Error(f"Image generation failed: {e}")
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  # --- Gradio App UI ---
94
  css = '''
@@ -103,8 +142,8 @@ css = '''
103
  .grid-container img{object-fit: contain}
104
  .grid-container {display: grid;grid-template-columns: repeat(2, 1fr)}
105
  .grid-container:has(> .gallery-item:only-child) {grid-template-columns: 1fr}
106
-
107
  '''
 
108
  with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
109
  gr.HTML('''
110
  <img class="logo-dark" src='https://huggingface.co/spaces/multimodalart/nano-banana/resolve/main/nano_banana_pros.png' style='margin: 0 auto; max-width: 500px' />
@@ -135,6 +174,9 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
135
  with gr.Column(scale=1):
136
  output_image = gr.Image(label="Output", interactive=False, elem_id="output", type="filepath")
137
  use_image_button = gr.Button("♻️ Use this Image for Next Edit")
 
 
 
138
  gr.Markdown("## Thank you for being a PRO! 🤗")
139
 
140
  login_button = gr.LoginButton()
@@ -142,9 +184,13 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
142
  # --- Event Handlers ---
143
  gr.on(
144
  triggers=[generate_button.click, prompt_input.submit],
 
 
 
 
145
  fn=unified_image_generator,
146
  inputs=[prompt_input, image_input_gallery],
147
- outputs=[output_image],
148
  )
149
 
150
  use_image_button.click(
@@ -152,8 +198,19 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
152
  inputs=[output_image],
153
  outputs=[image_input_gallery]
154
  )
 
 
 
 
 
 
 
 
 
 
 
155
 
156
- # --- Access Control Logic (UNCHANGED) ---
157
  def control_access(
158
  profile: Optional[gr.OAuthProfile] = None,
159
  oauth_token: Optional[gr.OAuthToken] = None
 
1
  import gradio as gr
2
+ from gradio_client import Client, handle_file
3
  from google import genai
4
  from google.genai import types
5
  import os
 
50
  prompt: str,
51
  images: Optional[List[str]] = None,
52
  oauth_token: Optional[gr.OAuthToken] = None
53
+ ) -> tuple:
54
  """
55
  Handles all image generation tasks based on the number of input images.
56
+ Returns: (output_image_path, video_button_visible, video_output_visible)
 
57
  """
58
  if not verify_pro_status(oauth_token):
59
  raise gr.Error("Access Denied. This service is for PRO users only.")
 
84
  pil_image = Image.open(BytesIO(image_data))
85
  with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
86
  pil_image.save(tmpfile.name)
87
+ output_path = tmpfile.name
88
+
89
+ # Determine if video button should be shown (only if exactly 1 input image)
90
+ show_video_button = images and len(images) == 1
91
+
92
+ # Return output image path, video button visibility, and hide video output
93
+ return output_path, gr.update(visible=show_video_button), gr.update(visible=False)
94
 
95
  except Exception as e:
96
  raise gr.Error(f"Image generation failed: {e}")
97
 
98
+ def create_video_transition(
99
+ input_image_gallery: List[str],
100
+ output_image: str,
101
+ oauth_token: Optional[gr.OAuthToken] = None
102
+ ) -> tuple:
103
+ """
104
+ Creates a video transition between the input and output images.
105
+ Returns: (video_path, video_visible)
106
+ """
107
+ if not verify_pro_status(oauth_token):
108
+ raise gr.Error("Access Denied. This service is for PRO users only.")
109
+
110
+ if not input_image_gallery or not output_image:
111
+ raise gr.Error("Both input and output images are required for video creation.")
112
+
113
+ try:
114
+ yield gr.update(visible=True, value=None)
115
+
116
+ video_client = Client("multimodalart/wan-2-2-first-last-frame", hf_token=oauth_token.token)
117
+
118
+ input_image_path = input_image_gallery[0][0]
119
+
120
+ result = video_client.predict(
121
+ start_image_pil=handle_file(input_image_path),
122
+ end_image_pil=handle_file(output_image),
123
+ prompt="Smooth transition between the two images",
124
+ api_name="/generate_video"
125
+ )
126
+
127
+ return result
128
+
129
+ except Exception as e:
130
+ raise gr.Error(f"Video creation failed: {e}")
131
 
132
  # --- Gradio App UI ---
133
  css = '''
 
142
  .grid-container img{object-fit: contain}
143
  .grid-container {display: grid;grid-template-columns: repeat(2, 1fr)}
144
  .grid-container:has(> .gallery-item:only-child) {grid-template-columns: 1fr}
 
145
  '''
146
+
147
  with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
148
  gr.HTML('''
149
  <img class="logo-dark" src='https://huggingface.co/spaces/multimodalart/nano-banana/resolve/main/nano_banana_pros.png' style='margin: 0 auto; max-width: 500px' />
 
174
  with gr.Column(scale=1):
175
  output_image = gr.Image(label="Output", interactive=False, elem_id="output", type="filepath")
176
  use_image_button = gr.Button("♻️ Use this Image for Next Edit")
177
+ create_video_button = gr.Button("Create a video between the two 🎥", variant="primary", visible=False)
178
+ video_output = gr.Video(label="Generated Video", visible=False)
179
+
180
  gr.Markdown("## Thank you for being a PRO! 🤗")
181
 
182
  login_button = gr.LoginButton()
 
184
  # --- Event Handlers ---
185
  gr.on(
186
  triggers=[generate_button.click, prompt_input.submit],
187
+ fn=lambda: [gr.update(visible=False), gr.update(visible=False)],
188
+ inputs=[],
189
+ outputs=[create_video_button, video_output],
190
+ ).then(
191
  fn=unified_image_generator,
192
  inputs=[prompt_input, image_input_gallery],
193
+ outputs=[output_image, create_video_button, video_output],
194
  )
195
 
196
  use_image_button.click(
 
198
  inputs=[output_image],
199
  outputs=[image_input_gallery]
200
  )
201
+
202
+ # Video creation handler
203
+ create_video_button.click(
204
+ fn=lambda: gr.update(visible=True),
205
+ inputs=[],
206
+ outputs=[video_output],
207
+ ).then(
208
+ fn=create_video_transition,
209
+ inputs=[image_input_gallery, output_image],
210
+ outputs=[video_output],
211
+ )
212
 
213
+ # --- Access Control Logic ---
214
  def control_access(
215
  profile: Optional[gr.OAuthProfile] = None,
216
  oauth_token: Optional[gr.OAuthToken] = None