scmlewis commited on
Commit
cd8a6c1
·
verified ·
1 Parent(s): 327e265

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -36
app.py CHANGED
@@ -10,14 +10,10 @@ def save_binary_file(file_name, data):
10
  f.write(data)
11
 
12
  def generate_edit(prompt, pil_image, api_key, model="gemini-2.0-flash-exp"):
13
- # Initialize Gemini client with provided key or env fallback
14
  client = genai.Client(api_key=(api_key.strip() if api_key and api_key.strip() != "" else os.environ.get("GEMINI_API_KEY")))
15
-
16
- # Save PIL Image to a temporary file path for upload
17
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
18
  image_path = tmp_file.name
19
  pil_image.save(image_path)
20
-
21
  files = [client.files.upload(file=image_path)]
22
  contents = [
23
  types.Content(
@@ -28,19 +24,16 @@ def generate_edit(prompt, pil_image, api_key, model="gemini-2.0-flash-exp"):
28
  ],
29
  ),
30
  ]
31
-
32
  generate_content_config = types.GenerateContentConfig(
33
  temperature=1,
34
  top_p=0.95,
35
  top_k=40,
36
  max_output_tokens=8192,
37
  response_modalities=["image", "text"],
38
- response_mime_type="text/plain", # Important for streaming image inline data
39
  )
40
-
41
  text_response = ""
42
  image_path_result = None
43
-
44
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
45
  temp_path = tmp.name
46
  for chunk in client.models.generate_content_stream(
@@ -54,11 +47,10 @@ def generate_edit(prompt, pil_image, api_key, model="gemini-2.0-flash-exp"):
54
  if candidate.inline_data:
55
  save_binary_file(temp_path, candidate.inline_data.data)
56
  image_path_result = temp_path
57
- break # Stop on first image data chunk
58
  else:
59
  text_response += chunk.text + "\n"
60
  del files
61
-
62
  return image_path_result, text_response
63
 
64
  def process_image_and_prompt(pil_image, prompt, api_key):
@@ -76,47 +68,92 @@ def process_image_and_prompt(pil_image, prompt, api_key):
76
 
77
  css_style = """
78
  .app-container {
79
- max-width: 750px !important;
80
  margin-left: auto !important;
81
  margin-right: auto !important;
82
  padding: 2rem 1rem;
 
 
 
 
 
 
 
 
 
 
83
  }
84
- .header-container {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  display: flex;
86
- gap: 1em;
87
- align-items: center;
88
  }
89
- .header-container img {
90
- height: 40px;
91
  }
92
- .header-container div h1 {
93
- margin: 0;
94
  }
95
  """
96
 
97
  with gr.Blocks(css=css_style) as demo:
98
- with gr.Row(elem_classes="app-container"):
99
- with gr.Column():
 
100
  gr.Markdown(
101
  """
102
- <div class="header-container">
103
- <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" alt="Gemini logo"/>
104
- <div>
105
- <h1>Gemini for Image Editing</h1>
106
- <p>Powered by <a href="https://gradio.app/">Gradio</a> ⚡️</p>
107
- </div>
108
- </div>
 
 
 
 
 
 
 
 
109
  """
110
  )
111
- image_input = gr.Image(type="pil", label="Upload PNG Image", image_mode="RGBA")
112
- prompt_input = gr.Textbox(label="Edit Prompt", placeholder="Describe how to edit the image", lines=2)
113
- api_key_input = gr.Textbox(label="Gemini API Key (optional)", placeholder="Enter your Gemini API key here", type="password")
114
-
115
- submit_btn = gr.Button("Generate Edit")
116
-
117
- gallery_output = gr.Gallery(label="Generated Image", elem_classes="output-gallery", height=280)
118
- text_output = gr.Textbox(label="Generation Status or Text Output", interactive=False)
119
-
 
 
 
120
  submit_btn.click(
121
  fn=process_image_and_prompt,
122
  inputs=[image_input, prompt_input, api_key_input],
 
10
  f.write(data)
11
 
12
  def generate_edit(prompt, pil_image, api_key, model="gemini-2.0-flash-exp"):
 
13
  client = genai.Client(api_key=(api_key.strip() if api_key and api_key.strip() != "" else os.environ.get("GEMINI_API_KEY")))
 
 
14
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
15
  image_path = tmp_file.name
16
  pil_image.save(image_path)
 
17
  files = [client.files.upload(file=image_path)]
18
  contents = [
19
  types.Content(
 
24
  ],
25
  ),
26
  ]
 
27
  generate_content_config = types.GenerateContentConfig(
28
  temperature=1,
29
  top_p=0.95,
30
  top_k=40,
31
  max_output_tokens=8192,
32
  response_modalities=["image", "text"],
33
+ response_mime_type="text/plain",
34
  )
 
35
  text_response = ""
36
  image_path_result = None
 
37
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
38
  temp_path = tmp.name
39
  for chunk in client.models.generate_content_stream(
 
47
  if candidate.inline_data:
48
  save_binary_file(temp_path, candidate.inline_data.data)
49
  image_path_result = temp_path
50
+ break
51
  else:
52
  text_response += chunk.text + "\n"
53
  del files
 
54
  return image_path_result, text_response
55
 
56
  def process_image_and_prompt(pil_image, prompt, api_key):
 
68
 
69
  css_style = """
70
  .app-container {
71
+ max-width: 900px !important;
72
  margin-left: auto !important;
73
  margin-right: auto !important;
74
  padding: 2rem 1rem;
75
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
76
+ }
77
+ .header-text {
78
+ font-size: 2.4rem;
79
+ font-weight: 900;
80
+ background: linear-gradient(90deg, #FF6A00, #EE0979);
81
+ -webkit-background-clip: text;
82
+ -webkit-text-fill-color: transparent;
83
+ margin-bottom: 1rem;
84
+ text-align: center;
85
  }
86
+ .gradient-button {
87
+ background: linear-gradient(90deg, #FF6A00, #EE0979);
88
+ border: none;
89
+ color: white;
90
+ font-weight: 700;
91
+ padding: 12px 25px;
92
+ border-radius: 10px;
93
+ cursor: pointer;
94
+ transition: background 0.5s ease;
95
+ }
96
+ .gradient-button:hover {
97
+ background: linear-gradient(90deg, #EE0979, #FF6A00);
98
+ }
99
+ .sidebar {
100
+ background: #f7f7f7;
101
+ padding: 20px;
102
+ border-radius: 12px;
103
+ box-shadow: 0 2px 7px rgb(0 0 0 / 0.08);
104
+ max-width: 280px;
105
+ }
106
+ .sidebar h3 {
107
+ margin-top: 0;
108
+ }
109
+ main-content {
110
  display: flex;
111
+ gap: 2rem;
112
+ margin-top: 1rem;
113
  }
114
+ .column {
115
+ flex: 1;
116
  }
117
+ .output-gallery {
118
+ min-height: 280px;
119
  }
120
  """
121
 
122
  with gr.Blocks(css=css_style) as demo:
123
+ with gr.Row(elem_classes="app-container", equal_height=True):
124
+ # Sidebar left
125
+ with gr.Column(scale=3, elem_classes="sidebar"):
126
  gr.Markdown(
127
  """
128
+ ### Usage Instructions
129
+ - Upload a PNG input image.
130
+ - Enter a prompt describing the edit.
131
+ - Optionally enter your Gemini API key.
132
+ - Click the Generate Edit button.
133
+
134
+ ### API Tips
135
+ - Use your own Gemini API key for best results.
136
+ - Do not use NSFW images.
137
+ - Outputs can include images or text messages.
138
+
139
+ ### Links
140
+ - [Duplicate this repo](https://huggingface.co/spaces/ameerazam08/Gemini-Image-Edit?duplicate=true)
141
+ - [Get API Key](https://aistudio.google.com/apikey)
142
+ - Follow the author on [Twitter](https://x.com/Ameerazam18)
143
  """
144
  )
145
+ # Main panel right
146
+ with gr.Column(scale=7):
147
+ gr.Markdown("<div class='header-text'>Gemini for Image Editing</div>")
148
+ with gr.Row():
149
+ with gr.Column():
150
+ image_input = gr.Image(type="pil", label="Upload PNG Image", image_mode="RGBA")
151
+ prompt_input = gr.Textbox(label="Edit Prompt", placeholder="Describe how to edit the image", lines=2)
152
+ api_key_input = gr.Textbox(label="Gemini API Key (optional)", placeholder="Enter your Gemini API key here", type="password")
153
+ submit_btn = gr.Button("Generate Edit", elem_classes="gradient-button")
154
+ with gr.Column():
155
+ gallery_output = gr.Gallery(label="Generated Image", elem_classes="output-gallery", height=280)
156
+ text_output = gr.Textbox(label="Generation Status or Text Output", interactive=False)
157
  submit_btn.click(
158
  fn=process_image_and_prompt,
159
  inputs=[image_input, prompt_input, api_key_input],