Gertie01 John6666 commited on
Commit
912cea8
·
1 Parent(s): 64aa63b

Upload 2 files (#2)

Browse files

- Upload 2 files (245fe4f92bf8ccb1f4e8e522370d407469bbec99)


Co-authored-by: John Smith <John6666@users.noreply.huggingface.co>

Files changed (2) hide show
  1. app.py +156 -145
  2. requirements.txt +2 -1
app.py CHANGED
@@ -1,161 +1,172 @@
 
 
 
 
 
 
1
  import gradio as gr
2
- import google.generativeai as genai
3
- from typing import Optional, Tuple
4
-
5
- # Configuration
6
- MODEL_ID = "gemini-2.0-flash-exp-image-generation"
7
-
8
- def process_media(
9
- api_key: str,
10
- prompt: str,
11
- img1: Optional[str],
12
- img2: Optional[str],
13
- img3: Optional[str]
14
- ) -> Tuple[Optional[str], str]:
15
- """
16
- Handles both Text-to-Image generation and Image Editing/Understanding
17
- using Google Gemini 2.0 Flash Exp.
18
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  if not api_key:
20
- return None, "⚠️ Please enter your Google API Key to start."
21
-
22
- if not prompt:
23
- return None, "⚠️ Please enter a prompt."
24
 
25
  try:
26
- genai.configure(api_key=api_key)
27
- model = genai.GenerativeModel(MODEL_ID)
28
-
29
- # Prepare inputs: Prompt first, then any uploaded images
30
- inputs = [prompt]
31
-
32
- uploaded_images = [img for img in [img1, img2, img3] if img is not None]
33
-
34
- # Append images to the input list
35
- for img in uploaded_images:
36
- inputs.append(img)
37
-
38
- # Call the model
39
- response = model.generate_content(inputs)
40
-
41
- # Resolve the response (for streaming compatibility, though we use simple generate here)
42
- response.resolve()
43
-
44
- # Extract the result
45
- # The model may return an image (inline_data) or text (suggestions/analysis)
46
- result_image = None
47
- result_text = ""
48
-
49
- for candidate in response.candidates:
50
- for part in candidate.content.parts:
51
- if part.inline_data:
52
- # Return image data (base64 encoded by Gradio automatically)
53
- result_image = part.inline_data.data
54
- elif part.text:
55
- result_text += part.text
56
-
57
- # If we got an image, return it with any accompanying text
58
- if result_image:
59
- return result_image, result_text if result_text else "Image generated/edited successfully."
60
-
61
- # If no image, return the text (likely understanding/suggestions)
62
- if result_text:
63
- return None, result_text
64
-
65
- return None, "No content generated. Try rephrasing your prompt."
 
 
 
 
 
 
66
 
67
  except Exception as e:
68
- error_msg = f"Error: {str(e)}"
69
- if "API key" in str(e).lower():
70
- error_msg = "Invalid API Key. Please check your Google AI Studio key."
71
- return None, error_msg
72
 
73
- # Gradio 6 Application
74
  with gr.Blocks() as demo:
75
-
76
- # Header Section
77
- gr.Markdown(
78
- """
79
- # 🎨 Gemini 2.0 Flash Studio
80
- **Image Generation & Editing powered by Google DeepMind**
81
-
82
- Drag and drop up to 3 images to edit or understand them, or just use text to generate new art.
83
- """
84
- )
85
-
86
- gr.HTML(
87
- '<div style="text-align: center; margin-bottom: 20px;">'
88
- '<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: #6366f1; font-weight: bold; text-decoration: none;">Built with anycoder</a>'
89
- '</div>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  )
91
 
 
 
 
92
  with gr.Row():
93
- with gr.Column(scale=1):
94
- gr.Markdown("### 🔑 Configuration")
95
- api_key_input = gr.Textbox(
96
- label="Google API Key",
97
- type="password",
98
- placeholder="Get your key at ai.google.dev",
99
- info="Your key is stored locally and not sent to any server other than Google's API."
100
- )
101
-
102
- gr.Markdown("### 🖼️ Inputs (Optional)")
103
- gr.Markdown("Drag images here to edit or analyze:")
104
- with gr.Row():
105
- img_input_1 = gr.Image(type="pil", label="Image 1")
106
- img_input_2 = gr.Image(type="pil", label="Image 2")
107
- img_input_3 = gr.Image(type="pil", label="Image 3")
108
-
109
- prompt_input = gr.Textbox(
110
- label="✨ Prompt",
111
- placeholder="Describe what you want to generate or how you want to edit the images...",
112
- lines=3,
113
- max_lines=5
114
- )
115
-
116
- submit_btn = gr.Button("Generate / Edit", variant="primary", size="lg")
117
-
118
- with gr.Column(scale=1):
119
- gr.Markdown("### 🚀 Output")
120
- with gr.Tabs():
121
- with gr.TabItem("Generated Image"):
122
- output_image = gr.Image(label="Result", type="pil")
123
- with gr.TabItem("Analysis & Suggestions"):
124
- output_text = gr.Textbox(
125
- label="Details / Suggestions",
126
- lines=15,
127
- placeholder="AI suggestions and analysis will appear here...",
128
- interactive=False
129
- )
130
-
131
- # Footer / Instructions
132
- gr.Markdown(
133
- """
134
- ---
135
- ### 💡 Tips
136
- 1. **Text-to-Image:** Enter only a prompt to create a new image.
137
- 2. **Image Editing:** Upload images and describe the changes (e.g., "Change the background to a cyberpunk city").
138
- 3. **Understanding:** Upload an image and ask questions about it.
139
- """
140
  )
141
 
142
- # Event Listener
143
- submit_btn.click(
144
- fn=process_media,
145
- inputs=[api_key_input, prompt_input, img_input_1, img_input_2, img_input_3],
146
  outputs=[output_image, output_text],
147
- api_visibility="public"
148
  )
149
 
150
- # Launch with Gradio 6 specific parameters
151
- demo.launch(
152
- theme=gr.themes.Soft(
153
- primary_hue="indigo",
154
- secondary_hue="purple",
155
- font=gr.themes.GoogleFont("Inter"),
156
- text_size="lg",
157
- spacing_size="lg",
158
- radius_size="md"
159
- ),
160
- footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}]
161
- )
 
 
 
 
 
 
 
1
+ import os
2
+ import mimetypes
3
+ import tempfile
4
+ import urllib.parse
5
+ import urllib.request
6
+
7
  import gradio as gr
8
+ from PIL import Image # kept for compatibility / future UI use
9
+
10
+ from google import genai
11
+ from google.genai import types
12
+
13
+ # Config
14
+ MODEL_ID = os.environ.get("GEMINI_MODEL", "gemini-2.5-flash-image")
15
+
16
+
17
+ def _load_bytes(path_or_url: str) -> tuple[bytes, str]:
18
+ """Return (data, mime_type) from either a local path or a http(s) URL."""
19
+ parsed = urllib.parse.urlparse(path_or_url)
20
+ is_url = parsed.scheme in ("http", "https")
21
+
22
+ if is_url:
23
+ req = urllib.request.Request(path_or_url, headers={"User-Agent": "Mozilla/5.0"})
24
+ with urllib.request.urlopen(req, timeout=30) as resp:
25
+ data = resp.read()
26
+ mime_type = resp.headers.get_content_type() or "application/octet-stream"
27
+ if mime_type in ("application/octet-stream", "binary/octet-stream"):
28
+ guess, _ = mimetypes.guess_type(path_or_url)
29
+ if guess:
30
+ mime_type = guess
31
+ return data, mime_type
32
+
33
+ with open(path_or_url, "rb") as f:
34
+ data = f.read()
35
+ mime_type, _ = mimetypes.guess_type(path_or_url)
36
+ return data, (mime_type or "application/octet-stream")
37
+
38
+
39
+ def generate_content(prompt: str, image1: str | None, image2: str | None, image3: str | None, api_key: str) -> tuple[str | None, str | None]:
40
+ """Generate content using the current Google GenAI SDK (google-genai)."""
41
+ api_key = (api_key or "").strip() or os.environ.get("GEMINI_API_KEY")
42
  if not api_key:
43
+ raise gr.Error("Please set Space secret GEMINI_API_KEY (recommended) or paste your key into the UI field.")
 
 
 
44
 
45
  try:
46
+ client = genai.Client(api_key=api_key)
47
+
48
+ # Prepare request contents: images first, then instruction text
49
+ contents: list[types.Part | str] = []
50
+ for img_path in [image1, image2, image3]:
51
+ if img_path:
52
+ data, mime_type = _load_bytes(img_path)
53
+ contents.append(types.Part.from_bytes(data=data, mime_type=mime_type))
54
+
55
+ contents.append((prompt or "").strip() or "Describe the provided images.")
56
+
57
+ # Ask for TEXT+IMAGE when supported; retry as TEXT-only if needed.
58
+ try:
59
+ response = client.models.generate_content(
60
+ model=MODEL_ID,
61
+ contents=contents,
62
+ config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
63
+ )
64
+ except Exception:
65
+ response = client.models.generate_content(model=MODEL_ID, contents=contents)
66
+
67
+ image_output: str | None = None
68
+ text_chunks: list[str] = []
69
+
70
+ if getattr(response, "candidates", None):
71
+ for part in response.candidates[0].content.parts:
72
+ if getattr(part, "text", None):
73
+ text_chunks.append(part.text)
74
+
75
+ inline = getattr(part, "inline_data", None)
76
+ if inline and getattr(inline, "data", None) and image_output is None:
77
+ filename = os.path.join(tempfile.gettempdir(), f"gemini_output_{os.urandom(4).hex()}.png")
78
+ with open(filename, "wb") as f:
79
+ f.write(inline.data)
80
+ image_output = filename
81
+
82
+ if not text_chunks and getattr(response, "text", None):
83
+ text_chunks.append(response.text)
84
+
85
+ text_output = "\n".join([t for t in text_chunks if t]).strip() or None
86
+
87
+ if image_output:
88
+ return image_output, text_output or "Image generated successfully!"
89
+ if text_output:
90
+ return None, text_output
91
+ return None, "No content generated. Try a different prompt or model."
92
 
93
  except Exception as e:
94
+ raise gr.Error(f"Error generating content: {type(e).__name__}: {str(e)}")
95
+
 
 
96
 
97
+ # Gradio app
98
  with gr.Blocks() as demo:
99
+ gr.HTML(''' <div style="text-align: center; margin-bottom: 20px;">
100
+ <h1>✨ Gemini Flash Studio</h1>
101
+ <p>Image Generation & Editing powered by the Gemini API</p>
102
+ <p style="opacity:0.8;">Model: <code>{model}</code> (override with <code>GEMINI_MODEL</code>)</p>
103
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank"
104
+ style="color: #007bff; text-decoration: none; font-weight: bold;">Built with anycoder</a>
105
+ </div>
106
+ '''.format(model=MODEL_ID))
107
+
108
+ gr.Markdown("### Configuration")
109
+ with gr.Row():
110
+ api_key_input = gr.Textbox(
111
+ label="Gemini API Key (optional if GEMINI_API_KEY secret is set)",
112
+ type="password",
113
+ placeholder="If you set GEMINI_API_KEY in Space Secrets, you can leave this empty.",
114
+ scale=4,
115
+ )
116
+
117
+ gr.Markdown("### Inputs")
118
+ with gr.Row():
119
+ img_input_1 = gr.Image(label="Image 1 (Drag & Drop)", type="filepath", sources=["upload", "clipboard"], height=300)
120
+ img_input_2 = gr.Image(label="Image 2 (Drag & Drop)", type="filepath", sources=["upload", "clipboard"], height=300)
121
+ img_input_3 = gr.Image(label="Image 3 (Drag & Drop)", type="filepath", sources=["upload", "clipboard"], height=300)
122
+
123
+ prompt_input = gr.Textbox(
124
+ label="✍️ Prompt",
125
+ placeholder="Describe the image you want to generate or how you want to edit the uploaded images...",
126
+ lines=3,
127
+ show_copy_button=True,
128
  )
129
 
130
+ generate_btn = gr.Button("✨ Generate", variant="primary", size="lg")
131
+
132
+ gr.Markdown("### Output")
133
  with gr.Row():
134
+ with gr.Column():
135
+ output_image = gr.Image(label="Generated Image", type="filepath", height=400)
136
+ with gr.Column():
137
+ output_text = gr.Textbox(label="Response / Description", lines=10)
138
+
139
+ gr.Examples(
140
+ examples=[
141
+ ["Generate a futuristic cyberpunk city with neon lights", None, None, None],
142
+ ["Describe what is in this image", "https://gradio-builds.s3.amazonaws.com/assets/cheetah-003.jpg", None, None],
143
+ ["Edit this image: make it look like a painting", None, None, None],
144
+ ],
145
+ inputs=[prompt_input, img_input_1, img_input_2, img_input_3],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  )
147
 
148
+ generate_btn.click(
149
+ fn=generate_content,
150
+ inputs=[prompt_input, img_input_1, img_input_2, img_input_3, api_key_input],
 
151
  outputs=[output_image, output_text],
152
+ api_visibility="public",
153
  )
154
 
155
+ demo.launch(
156
+ theme=gr.themes.Soft(
157
+ primary_hue="indigo",
158
+ secondary_hue="cyan",
159
+ neutral_hue="slate",
160
+ font=gr.themes.GoogleFont("Inter"),
161
+ text_size="lg",
162
+ spacing_size="lg",
163
+ radius_size="md",
164
+ ).set(
165
+ button_primary_background_fill="*primary_500",
166
+ button_primary_background_fill_hover="*primary_600",
167
+ button_primary_text_color="white",
168
+ block_border_width="0px",
169
+ block_shadow="*shadow_drop_lg",
170
+ ),
171
+ footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}],
172
+ )
requirements.txt CHANGED
@@ -1,2 +1,3 @@
1
- gradio>=6.0.2
2
  google-genai
 
 
1
+ Pillow
2
  google-genai
3
+ gradio>=6.0.2