multimodalart HF Staff commited on
Commit
34035f1
·
verified ·
1 Parent(s): 7541de2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -96
app.py CHANGED
@@ -1,21 +1,11 @@
1
  import gradio as gr
2
- import google.generativeai as genai
3
  import os
4
  from typing import Optional, List
5
  from huggingface_hub import whoami
6
- from PIL import Image
7
- import tempfile
8
- import io # Import io for handling in-memory binary streams
9
 
10
- # --- Google Gemini API Configuration ---
11
- # Set your Google API key as an environment variable
12
- GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY", "")
13
- if not GOOGLE_API_KEY:
14
- raise ValueError("GOOGLE_API_KEY environment variable not set.")
15
- genai.configure(api_key=GOOGLE_API_KEY)
16
-
17
- # --- Define the correct model name ---
18
- GEMINI_MODEL_NAME = 'gemini-2.5-flash-image-preview'
19
 
20
  def verify_pro_status(token: Optional[gr.OAuthToken]) -> bool:
21
  """Verifies if the user is a Hugging Face PRO user or part of an enterprise org."""
@@ -23,105 +13,56 @@ def verify_pro_status(token: Optional[gr.OAuthToken]) -> bool:
23
  return False
24
  try:
25
  user_info = whoami(token=token.token)
 
 
26
  if user_info.get("isPro", False):
27
  return True
 
 
28
  orgs = user_info.get("orgs", [])
29
  if any(org.get("isEnterprise", False) for org in orgs):
30
  return True
 
31
  return False
 
32
  except Exception as e:
33
  print(f"Could not verify user's PRO/Enterprise status: {e}")
34
  return False
35
 
36
  # --- Backend Generation Functions ---
37
 
38
- def run_single_image_logic(prompt: str, image_path: Optional[str] = None) -> str:
39
- """Handles text-to-image or single image-to-image using Google Gemini."""
40
- try:
41
- model = genai.GenerativeModel(GEMINI_MODEL_NAME) # Use the defined model name
42
- contents = [prompt]
43
- if image_path:
44
- input_image = Image.open(image_path)
45
- contents.append(input_image)
46
-
47
- response = model.generate_content(contents)
48
-
49
- # Access the image data correctly based on the response structure
50
- # Assuming the generated content might be in response.candidates[0].content.parts[0].inline_data.data
51
- # Or direct from response.parts if it's a single part with inline_data
52
-
53
- image_data = None
54
- if hasattr(response, 'parts') and response.parts:
55
- for part in response.parts:
56
- if hasattr(part, 'inline_data') and hasattr(part.inline_data, 'data'):
57
- image_data = part.inline_data.data
58
- break
59
- elif hasattr(response, 'candidates') and response.candidates:
60
- for candidate in response.candidates:
61
- if hasattr(candidate, 'content') and hasattr(candidate.content, 'parts') and candidate.content.parts:
62
- for part in candidate.content.parts:
63
- if hasattr(part, 'inline_data') and hasattr(part.inline_data, 'data'):
64
- image_data = part.inline_data.data
65
- break
66
- if image_data:
67
- break
68
-
69
- if not image_data:
70
- raise ValueError("No image data found in the model response.")
71
-
72
- # Save the generated image to a temporary file to return its path
73
- pil_image = Image.open(io.BytesIO(image_data))
74
- with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
75
- pil_image.save(tmpfile.name)
76
- return tmpfile.name
77
-
78
- except Exception as e:
79
- raise gr.Error(f"Image generation failed: {e}")
80
-
81
 
82
  def run_multi_image_logic(prompt: str, images: List[str]) -> str:
83
  """
84
- Handles multi-image editing by sending a list of images and a prompt.
85
  """
86
  if not images:
87
  raise gr.Error("Please upload at least one image in the 'Multiple Images' tab.")
88
-
89
- try:
90
- model = genai.GenerativeModel(GEMINI_MODEL_NAME) # Use the defined model name
91
- # The prompt should be the last part of the contents list
92
- contents = [Image.open(image_path[0]) for image_path in images]
93
- contents.append(prompt)
94
-
95
- response = model.generate_content(contents)
96
-
97
- image_data = None
98
- if hasattr(response, 'parts') and response.parts:
99
- for part in response.parts:
100
- if hasattr(part, 'inline_data') and hasattr(part.inline_data, 'data'):
101
- image_data = part.inline_data.data
102
- break
103
- elif hasattr(response, 'candidates') and response.candidates:
104
- for candidate in response.candidates:
105
- if hasattr(candidate, 'content') and hasattr(candidate.content, 'parts') and candidate.content.parts:
106
- for part in candidate.content.parts:
107
- if hasattr(part, 'inline_data') and hasattr(part.inline_data, 'data'):
108
- image_data = part.inline_data.data
109
- break
110
- if image_data:
111
- break
112
-
113
- if not image_data:
114
- raise ValueError("No image data found in the model response.")
115
-
116
- # Save the generated image to a temporary file to return its path
117
- pil_image = Image.open(io.BytesIO(image_data))
118
- with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
119
- pil_image.save(tmpfile.name)
120
- return tmpfile.name
121
-
122
- except Exception as e:
123
- raise gr.Error(f"Image generation failed: {e}")
124
-
125
 
126
  # --- Gradio App UI ---
127
  css = '''
@@ -131,10 +72,18 @@ css = '''
131
  #output{margin-top: 25px}
132
  .fillable{max-width: 980px !important}
133
  .dark .progress-text {color: white}
 
 
 
134
  '''
135
  with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
136
- gr.HTML("<h1 style='text-align:center'>Image Generation with Google Gemini</h1>")
137
- gr.HTML("<h3 style='text-align:center'>Hugging Face PRO users can use Google's Gemini 2.5 Flash Image Preview on this Space. <a href='https://huggingface.co/pro' target='_blank'>Subscribe to PRO</a></h3>", elem_id="sub_title")
 
 
 
 
 
138
 
139
  pro_message = gr.Markdown(visible=False)
140
  main_interface = gr.Column(visible=False)
 
1
  import gradio as gr
2
+ import fal_client
3
  import os
4
  from typing import Optional, List
5
  from huggingface_hub import whoami
 
 
 
6
 
7
+ FAL_KEY = os.getenv("FAL_KEY", "")
8
+ fal_client.api_key = FAL_KEY
 
 
 
 
 
 
 
9
 
10
  def verify_pro_status(token: Optional[gr.OAuthToken]) -> bool:
11
  """Verifies if the user is a Hugging Face PRO user or part of an enterprise org."""
 
13
  return False
14
  try:
15
  user_info = whoami(token=token.token)
16
+
17
+ # Case 1: User is PRO
18
  if user_info.get("isPro", False):
19
  return True
20
+
21
+ # Case 2: User is in any enterprise org
22
  orgs = user_info.get("orgs", [])
23
  if any(org.get("isEnterprise", False) for org in orgs):
24
  return True
25
+
26
  return False
27
+
28
  except Exception as e:
29
  print(f"Could not verify user's PRO/Enterprise status: {e}")
30
  return False
31
 
32
  # --- Backend Generation Functions ---
33
 
34
+ def run_single_image_logic(prompt: str, image: Optional[str] = None) -> str:
35
+ """Handles text-to-image or single image-to-image and returns a single URL string."""
36
+ if image:
37
+ image_url = fal_client.upload_file(image)
38
+ result = fal_client.run(
39
+ "fal-ai/nano-banana/edit",
40
+ # CORRECTED: The 'edit' endpoint always expects 'image_urls' as a list.
41
+ arguments={"prompt": prompt, "image_urls": [image_url]},
42
+ )
43
+ else:
44
+ result = fal_client.run(
45
+ "fal-ai/nano-banana", arguments={"prompt": prompt}
46
+ )
47
+ return result["images"][0]["url"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  def run_multi_image_logic(prompt: str, images: List[str]) -> str:
50
  """
51
+ Handles multi-image editing by sending a list of URLs in a single API call.
52
  """
53
  if not images:
54
  raise gr.Error("Please upload at least one image in the 'Multiple Images' tab.")
55
+ print(images)
56
+ image_urls = [fal_client.upload_file(image_path[0]) for image_path in images]
57
+ result = fal_client.run(
58
+ "fal-ai/nano-banana/edit",
59
+ arguments={
60
+ "prompt": prompt,
61
+ "image_urls": image_urls,
62
+ "num_images": 1
63
+ },
64
+ )
65
+ return result["images"][0]["url"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  # --- Gradio App UI ---
68
  css = '''
 
72
  #output{margin-top: 25px}
73
  .fillable{max-width: 980px !important}
74
  .dark .progress-text {color: white}
75
+ .logo-dark{display: none}
76
+ .dark .logo-dark{display: block !important}
77
+ .dark .logo-light{display: none}
78
  '''
79
  with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
80
+ gr.HTML('''
81
+ <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' />
82
+ <img class="logo-light" src='https://huggingface.co/spaces/multimodalart/nano-banana/resolve/main/nano_banana_pros_light.png' style='margin: 0 auto; max-width: 500px' />
83
+ ''')
84
+
85
+
86
+ gr.HTML("<h3 style='text-align:center'>Hugging Face PRO users can use Google's Nano Banana (Gemini 2.5 Flash Image Preview) on this Space. <a href='https://huggingface.co/pro' target='_blank'>Subscribe to PRO</a></h3>", elem_id="sub_title")
87
 
88
  pro_message = gr.Markdown(visible=False)
89
  main_interface = gr.Column(visible=False)