multimodalart HF Staff commited on
Commit
273b01b
·
verified ·
1 Parent(s): 16e0d88

Swap to Google

Browse files
Files changed (1) hide show
  1. app.py +76 -46
app.py CHANGED
@@ -1,11 +1,22 @@
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,56 +24,83 @@ def verify_pro_status(token: Optional[gr.OAuthToken]) -> bool:
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,18 +110,10 @@ 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)
 
1
  import gradio as gr
2
+ from google import genai
3
+ from google.genai import types
4
  import os
5
  from typing import Optional, List
6
  from huggingface_hub import whoami
7
+ from PIL import Image
8
+ from io import BytesIO
9
+ import tempfile
10
 
11
+ # --- Google Gemini API Configuration ---
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
+
16
+ genai.configure(api_key=GOOGLE_API_KEY)
17
+ client = genai.Client()
18
+
19
+ GEMINI_MODEL_NAME = 'gemini-2.5-flash-image-preview'
20
 
21
  def verify_pro_status(token: Optional[gr.OAuthToken]) -> bool:
22
  """Verifies if the user is a Hugging Face PRO user or part of an enterprise org."""
 
24
  return False
25
  try:
26
  user_info = whoami(token=token.token)
 
 
27
  if user_info.get("isPro", False):
28
  return True
 
 
29
  orgs = user_info.get("orgs", [])
30
  if any(org.get("isEnterprise", False) for org in orgs):
31
  return True
 
32
  return False
 
33
  except Exception as e:
34
  print(f"Could not verify user's PRO/Enterprise status: {e}")
35
  return False
36
 
37
+ def _extract_image_data_from_response(response) -> Optional[bytes]:
38
+ """Helper to extract image data from the model's response."""
39
+ if hasattr(response, 'candidates') and response.candidates:
40
+ for candidate in response.candidates:
41
+ if hasattr(candidate, 'content') and hasattr(candidate.content, 'parts') and candidate.content.parts:
42
+ for part in candidate.content.parts:
43
+ if hasattr(part, 'inline_data') and hasattr(part.inline_data, 'data'):
44
+ return part.inline_data.data
45
+ return None
46
+
47
+ def run_single_image_logic(prompt: str, image_path: Optional[str] = None) -> str:
48
+ """Handles text-to-image or single image-to-image using Google Gemini."""
49
+ try:
50
+ contents = [prompt]
51
+ if image_path:
52
+ input_image = Image.open(image_path)
53
+ contents.append(input_image)
54
+
55
+ response = client.models.generate_content(
56
+ model=GEMINI_MODEL_NAME,
57
+ contents=contents,
58
  )
59
+
60
+ image_data = _extract_image_data_from_response(response)
61
+
62
+ if not image_data:
63
+ raise ValueError("No image data found in the model response.")
64
+
65
+ # Save the generated image to a temporary file to return its path
66
+ pil_image = Image.open(BytesIO(image_data))
67
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
68
+ pil_image.save(tmpfile.name)
69
+ return tmpfile.name
70
+
71
+ except Exception as e:
72
+ raise gr.Error(f"Image generation failed: {e}")
73
+
74
 
75
  def run_multi_image_logic(prompt: str, images: List[str]) -> str:
76
  """
77
+ Handles multi-image editing by sending a list of images and a prompt.
78
  """
79
  if not images:
80
  raise gr.Error("Please upload at least one image in the 'Multiple Images' tab.")
81
+
82
+ try:
83
+ contents = [Image.open(image_path[0]) for image_path in images]
84
+ contents.append(prompt)
85
+
86
+ response = client.models.generate_content(
87
+ model=GEMINI_MODEL_NAME,
88
+ contents=contents,
89
+ )
90
+
91
+ image_data = _extract_image_data_from_response(response)
92
+
93
+ if not image_data:
94
+ raise ValueError("No image data found in the model response.")
95
+
96
+ pil_image = Image.open(BytesIO(image_data))
97
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
98
+ pil_image.save(tmpfile.name)
99
+ return tmpfile.name
100
+
101
+ except Exception as e:
102
+ raise gr.Error(f"Image generation failed: {e}")
103
+
104
 
105
  # --- Gradio App UI ---
106
  css = '''
 
110
  #output{margin-top: 25px}
111
  .fillable{max-width: 980px !important}
112
  .dark .progress-text {color: white}
 
 
 
113
  '''
114
  with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
115
+ gr.HTML("<h1 style='text-align:center'>Image Generation with Google Gemini</h1>")
116
+ 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")
 
 
 
 
 
117
 
118
  pro_message = gr.Markdown(visible=False)
119
  main_interface = gr.Column(visible=False)