taesiri commited on
Commit
37696a6
·
verified ·
1 Parent(s): fd6bc5b

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +205 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from google import genai
4
+ from google.genai import types
5
+ import tempfile
6
+ import uuid
7
+ from pathlib import Path
8
+
9
+ # Initialize the Gemini client globally
10
+ client = None
11
+ if os.environ.get("GOOGLE_API_KEY"):
12
+ client = genai.Client(api_key=os.environ.get("GOOGLE_API_KEY"))
13
+
14
+
15
+ def save_binary_file(file_name, data):
16
+ with open(file_name, "wb") as f:
17
+ f.write(data)
18
+ return file_name
19
+
20
+
21
+ def process_image_with_gemini(image, instruction) -> tuple[str, str, str]:
22
+ # Create output directory if it doesn't exist
23
+ output_dir = Path("output_gemini")
24
+ output_dir.mkdir(exist_ok=True)
25
+
26
+ # Generate a unique ID for this request
27
+ request_id = f"request_{uuid.uuid4().hex[:8]}"
28
+ request_folder = output_dir / request_id
29
+ request_folder.mkdir(exist_ok=True)
30
+
31
+ # Save the input image to the request folder
32
+ input_image_path = request_folder / "input.jpg"
33
+ image.save(input_image_path)
34
+
35
+ try:
36
+ # Create a temporary directory that will be automatically cleaned up
37
+ with tempfile.TemporaryDirectory() as temp_dir:
38
+ # Save the image to a temporary file
39
+ temp_image_path = Path(temp_dir) / "temp_input_image.jpg"
40
+ image.save(temp_image_path)
41
+
42
+ # Upload the temporary file to Gemini API using global client
43
+ files = [
44
+ client.files.upload(file=str(temp_image_path)),
45
+ ]
46
+
47
+ model = "gemini-2.0-flash-exp-image-generation"
48
+ contents = [
49
+ types.Content(
50
+ role="user",
51
+ parts=[
52
+ types.Part.from_uri(
53
+ file_uri=files[0].uri,
54
+ mime_type="image/jpeg",
55
+ ),
56
+ types.Part.from_text(text=instruction),
57
+ ],
58
+ ),
59
+ ]
60
+ generate_content_config = types.GenerateContentConfig(
61
+ temperature=1,
62
+ top_p=0.95,
63
+ top_k=40,
64
+ max_output_tokens=8192,
65
+ response_modalities=[
66
+ "image",
67
+ "text",
68
+ ],
69
+ safety_settings=[
70
+ types.SafetySetting(
71
+ category="HARM_CATEGORY_CIVIC_INTEGRITY",
72
+ threshold="OFF", # Off
73
+ ),
74
+ ],
75
+ response_mime_type="text/plain",
76
+ )
77
+
78
+ response_text = ""
79
+ edited_image_path = None
80
+
81
+ for chunk in client.models.generate_content_stream(
82
+ model=model,
83
+ contents=contents,
84
+ config=generate_content_config,
85
+ ):
86
+ if (
87
+ not chunk.candidates
88
+ or not chunk.candidates[0].content
89
+ or not chunk.candidates[0].content.parts
90
+ ):
91
+ continue
92
+
93
+ # Handle image response
94
+ if hasattr(chunk.candidates[0].content.parts[0], "inline_data"):
95
+ # Save the generated image
96
+ edited_image_path = request_folder / "edited.jpg"
97
+ save_binary_file(
98
+ str(edited_image_path),
99
+ chunk.candidates[0].content.parts[0].inline_data.data,
100
+ )
101
+ # Handle text response
102
+ elif hasattr(chunk.candidates[0].content.parts[0], "text"):
103
+ response_text += chunk.candidates[0].content.parts[0].text
104
+
105
+ # Simplify the return statement and ensure consistent types
106
+ if edited_image_path and edited_image_path.exists():
107
+ return str(edited_image_path), response_text or "", "Success"
108
+ return None, response_text or "", "No image generated"
109
+
110
+ except Exception as e:
111
+ error_message = str(e)
112
+ if (
113
+ "RESOURCE_EXHAUSTED" in error_message
114
+ or "rate limit" in error_message.lower()
115
+ ):
116
+ return None, "", "Rate limit exceeded. Please try again later."
117
+ return None, "", f"Error: {error_message}"
118
+
119
+
120
+ def process_image(image, instruction):
121
+ """Process an image with Gemini based on given instructions.
122
+
123
+ Args:
124
+ image: Input PIL image
125
+ instruction: Text instructions for editing
126
+
127
+ Returns:
128
+ Tuple containing (output_image_path, response_text, status_message)
129
+ """
130
+ if image is None:
131
+ return None, "", "Please upload an image."
132
+
133
+ if not instruction or instruction.strip() == "":
134
+ return None, "", "Please provide an instruction."
135
+
136
+ if client is None:
137
+ return (
138
+ None,
139
+ "",
140
+ "Error: Google API key not found. Please set the GOOGLE_API_KEY environment variable.",
141
+ )
142
+
143
+ try:
144
+ return process_image_with_gemini(image, instruction)
145
+ except Exception as e:
146
+ return None, "", f"Unexpected error: {str(e)}"
147
+
148
+
149
+ with gr.Blocks(title="Gemini Image Editor") as app:
150
+ with gr.Column():
151
+ gr.Markdown("# 🖼️ Gemini Image Editor")
152
+ gr.Markdown(
153
+ "Upload an image and provide instructions for Gemini to edit it. The AI will generate a new image based on your instructions."
154
+ )
155
+
156
+ with gr.Row():
157
+ with gr.Column():
158
+ input_image = gr.Image(type="pil", label="Upload Image")
159
+ instruction = gr.Textbox(
160
+ label="Editing Instructions",
161
+ placeholder="Describe the edits you want to make...",
162
+ lines=3,
163
+ )
164
+ submit_btn = gr.Button("✨ Process Image", variant="primary")
165
+
166
+ with gr.Column():
167
+ output_image = gr.Image(label="Edited Image")
168
+ response_text = gr.Textbox(
169
+ label="Gemini's Response", lines=3, interactive=False
170
+ )
171
+ status = gr.Textbox(label="Status", interactive=False)
172
+
173
+ submit_btn.click(
174
+ fn=process_image,
175
+ inputs=[input_image, instruction],
176
+ outputs=[output_image, response_text, status],
177
+ )
178
+
179
+ # Add sample instructions (without example images)
180
+ gr.Markdown("### Sample Instructions (upload your own image and try these)")
181
+ sample_instructions = gr.Examples(
182
+ examples=[
183
+ "Make the sky more blue and add birds flying",
184
+ "Convert this to a watercolor painting style",
185
+ "Add a sunset effect to this image",
186
+ "Turn this into a night scene with stars",
187
+ "Make this look like it was taken in winter with snow",
188
+ ],
189
+ inputs=instruction,
190
+ )
191
+
192
+ gr.Markdown(
193
+ """
194
+ ### Notes
195
+ - Processing may take up to 30 seconds
196
+ - If you need to duplicate this space, just remember to set the Google API key as an environment variable
197
+ """,
198
+ elem_classes="footer",
199
+ )
200
+
201
+
202
+ # Launch the app
203
+ if __name__ == "__main__":
204
+ print("Starting Gemini Image Editor...")
205
+ app.launch(ssr_mode=True)
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ google-genai
2
+ gradio