Hamed744 commited on
Commit
c0e2510
·
verified ·
1 Parent(s): 7356cac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -137
app.py CHANGED
@@ -1,144 +1,141 @@
1
  import json
2
  import os
 
 
3
  import tempfile
4
- from PIL import Image
5
  import gradio as gr
 
 
6
  from google import genai
7
  from google.genai import types
8
  import concurrent.futures
 
9
 
10
  def save_binary_file(file_name, data):
11
  with open(file_name, "wb") as f:
12
  f.write(data)
13
 
14
- def needs_translation(text):
15
- # Simple check for non-English characters (Persian, Arabic, Urdu, etc.)
16
- non_english_chars = set("ءآأؤإئابةتثجحخدذرزسشصضطظعغفقكلمنهوىيپچژکگی")
17
- return any(char in non_english_chars for char in text)
18
-
19
- def translate_prompt(text, api_key, model="gemini-2.0-flash-exp"):
20
  try:
21
- client = genai.Client(api_key=api_key.strip())
22
-
23
- pre_prompt = (
24
- "Translate the following text to English accurately and naturally. "
25
- "Keep the translation concise and clear. "
26
- "Do not include any additional explanations or context in the translation."
27
- )
28
- full_text = pre_prompt + "\n" + text
29
-
30
- contents = [
31
- types.Content(
32
- role="user",
33
- parts=[types.Part.from_text(text=full_text)],
34
- ),
35
- ]
36
-
37
- generate_content_config = types.GenerateContentConfig(
38
- temperature=0.5,
39
- top_p=0.9,
40
- top_k=40,
41
- max_output_tokens=8192,
42
- response_mime_type="text/plain",
43
- )
44
-
45
- text_response = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  for chunk in client.models.generate_content_stream(
47
  model=model,
48
  contents=contents,
49
  config=generate_content_config,
50
  ):
51
- if chunk.candidates and chunk.candidates[0].content and chunk.candidates[0].content.parts:
 
 
 
 
 
 
 
52
  text_response += chunk.text + "\n"
53
 
54
- return text_response.strip()
55
-
56
- except Exception as e:
57
- print(f"Translation error: {str(e)}")
58
- return text
59
-
60
- def generate_with_api(api_key, text, file_name, model="gemini-2.0-flash-exp"):
61
- try:
62
- client = genai.Client(api_key=api_key.strip())
63
- files = [client.files.upload(file=file_name)]
64
-
65
- pre_prompt = (
66
- "The following instruction is in English. Process it carefully. "
67
- "Your task is to edit the image based on the instruction. "
68
- "If the instruction asks to change text in the image, identify the existing text and replace it. "
69
- "Ensure the new text matches the style, font, and position of the original text."
70
- )
71
- full_text = pre_prompt + "\n" + text
72
-
73
- contents = [
74
- types.Content(
75
- role="user",
76
- parts=[
77
- types.Part.from_uri(
78
- file_uri=files[0].uri,
79
- mime_type=files[0].mime_type,
80
- ),
81
- types.Part.from_text(text=full_text),
82
- ],
83
- ),
84
- ]
85
-
86
- generate_content_config = types.GenerateContentConfig(
87
- temperature=1,
88
- top_p=0.95,
89
- top_k=40,
90
- max_output_tokens=8192,
91
- response_modalities=["image", "text"],
92
- response_mime_type="text/plain",
93
- )
94
-
95
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
96
- temp_path = tmp.name
97
- for chunk in client.models.generate_content_stream(
98
- model=model,
99
- contents=contents,
100
- config=generate_content_config,
101
- ):
102
- if chunk.candidates and chunk.candidates[0].content and chunk.candidates[0].content.parts:
103
- candidate = chunk.candidates[0].content.parts[0]
104
- if candidate.inline_data:
105
- save_binary_file(temp_path, candidate.inline_data.data)
106
- return temp_path, ""
107
- elif candidate.text:
108
- return None, candidate.text
109
-
110
- return None, "No response from API"
111
-
112
- except Exception as e:
113
- return None, f"API Error: {str(e)}"
114
- finally:
115
- if 'files' in locals():
116
- del files
117
 
118
  def process_single_api(api_key, prompt, file_name, model):
119
  if not api_key:
120
  return None, "API key not provided"
121
 
122
  try:
123
- # Check if translation is needed
124
- if needs_translation(prompt):
125
- processed_prompt = translate_prompt(prompt, api_key, model)
126
- else:
127
- processed_prompt = prompt
128
-
129
- # Generate image with dedicated API
130
- image_path, text_response = generate_with_api(api_key, processed_prompt, file_name, model)
131
 
132
  if image_path:
133
  result_img = Image.open(image_path)
134
  if result_img.mode == "RGBA":
135
  result_img = result_img.convert("RGB")
136
  return result_img, ""
137
-
138
  return None, text_response if text_response else "No image generated"
139
 
140
  except Exception as e:
141
- return None, f"Processing Error: {str(e)}"
142
 
143
  def process_image_and_prompt(composite_pil, prompt):
144
  try:
@@ -157,13 +154,13 @@ def process_image_and_prompt(composite_pil, prompt):
157
  result_images = []
158
  error_messages = []
159
 
160
- # Fully parallel and independent API execution
161
  with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
162
  futures = {
163
  executor.submit(
164
  process_single_api,
165
  api_key, prompt, composite_path, model
166
- ): api_key[-4:] for api_key in api_keys if api_key
167
  }
168
 
169
  for future in concurrent.futures.as_completed(futures):
@@ -171,18 +168,17 @@ def process_image_and_prompt(composite_pil, prompt):
171
  if image:
172
  result_images.append(image)
173
  if error:
174
- error_messages.append(f"API {futures[future]}: {error}")
175
 
176
  os.unlink(composite_path)
177
 
178
  if not result_images:
179
- error_msg = "\n".join(error_messages) if error_messages else "All APIs failed without specific errors"
180
- return None, f"{error_msg}\n\nPlease check your command and try again."
181
 
182
  return result_images, ""
183
 
184
  except Exception as e:
185
- return None, f"System Error: {str(e)}"
186
 
187
  css = """
188
  footer { visibility: hidden; }
@@ -192,45 +188,86 @@ display: none !important;
192
  }
193
  """
194
 
195
- with gr.Blocks(css=css) as demo:
196
- gr.HTML("""
 
197
  <div class="header-container">
198
- <div><img src="https://uploadkon.ir/uploads/4a3e22_25IMG-%DB%B2%DB%B0%DB%B2%DB%B5%DB%B0%DB%B3%DB%B2%DB%B2-%DB%B1%DB%B7%DB%B1%DB%B8%DB%B5%DB%B2.jpg" alt="Alfa AI logo"></div>
199
- <div><h1>ویرایش جادویی تصاویر با هوش مصنوعی آلفا</h1></div>
 
 
 
 
200
  </div>
201
- """)
 
202
 
203
- with gr.Accordion("⚠️ راهنمای استفاده", open=False):
204
  gr.Markdown("""
205
  ### راهنمای استفاده
206
  - تصویر خود را آپلود کرده و دستور ویرایش را وارد کنید
207
- - سیستم به طور خودکار زبان دستور شما را تشخیص می‌دهد
208
- - هر تصویر نتیجه از یک API مستقل تولید می‌شود
 
 
 
 
 
 
 
 
 
 
209
  """)
210
 
211
- with gr.Row():
212
- with gr.Column():
213
- image_input = gr.Image(type="pil", label="تصویر را آپلود کنید", image_mode="RGBA")
214
- prompt_input = gr.Textbox(lines=2, placeholder="دستور ویرایش (هر زبانی)...", label="دستور ویرایش")
215
- submit_btn = gr.Button("اعمال تغییرات")
 
 
 
 
 
 
 
 
 
 
 
216
 
217
- with gr.Column():
218
- output_gallery = gr.Gallery(label="تصاویر ویرایش شده")
219
- output_text = gr.Textbox(label="پیام سیستم")
 
 
 
 
220
 
221
  submit_btn.click(
222
- process_image_and_prompt,
223
  inputs=[image_input, prompt_input],
224
- outputs=[output_gallery, output_text]
225
  )
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  gr.Examples(
228
- examples=[
229
- ["examples/1.jpg", "متن را به 'سلام' تغییر بده"],
230
- ["examples/2.jpg", "Change the text to 'Hello'"],
231
- ["examples/3.jpg", "حذف شیء قرمز رنگ از تصویر"],
232
- ],
233
- inputs=[image_input, prompt_input]
234
  )
235
 
236
- demo.queue(concurrency_count=4).launch()
 
1
  import json
2
  import os
3
+ import time
4
+ import uuid
5
  import tempfile
6
+ from PIL import Image, ImageDraw, ImageFont
7
  import gradio as gr
8
+ import base64
9
+ import mimetypes
10
  from google import genai
11
  from google.genai import types
12
  import concurrent.futures
13
+ import langdetect
14
 
15
  def save_binary_file(file_name, data):
16
  with open(file_name, "wb") as f:
17
  f.write(data)
18
 
19
+ def translate_prompt_to_english(text, api_key, model="gemini-2.0-flash-exp"):
20
+ # Detect the language of the input text
 
 
 
 
21
  try:
22
+ detected_lang = langdetect.detect(text)
23
+ # If the language is English, return the text as is
24
+ if detected_lang == "en":
25
+ return text
26
+ except:
27
+ pass
28
+
29
+ client = genai.Client(api_key=api_key.strip())
30
+
31
+ pre_prompt = (
32
+ "Translate the following text to English accurately and naturally, as a native English speaker would phrase it. "
33
+ "Keep the translation concise and clear, avoiding unnecessary words or literal translations. "
34
+ "For example, if the text is 'متن را به \"امیر\" تغییر بده', translate it to 'Change the text to \"Amir\"'. "
35
+ "Do not include any additional explanations or context in the translation."
36
+ )
37
+ full_text = pre_prompt + "\n" + text
38
+
39
+ contents = [
40
+ types.Content(
41
+ role="user",
42
+ parts=[
43
+ types.Part.from_text(text=full_text),
44
+ ],
45
+ ),
46
+ ]
47
+ generate_content_config = types.GenerateContentConfig(
48
+ temperature=0.5,
49
+ top_p=0.9,
50
+ top_k=40,
51
+ max_output_tokens=8192,
52
+ response_mime_type="text/plain",
53
+ )
54
+
55
+ text_response = ""
56
+ for chunk in client.models.generate_content_stream(
57
+ model=model,
58
+ contents=contents,
59
+ config=generate_content_config,
60
+ ):
61
+ if not chunk.candidates or not chunk.candidates[0].content or not chunk.candidates[0].content.parts:
62
+ continue
63
+ text_response += chunk.text + "\n"
64
+
65
+ return text_response.strip()
66
+
67
+ def generate_with_api(api_key, text, file_name, model="gemini-2.0-flash-exp"):
68
+ client = genai.Client(api_key=api_key.strip())
69
+ files = [client.files.upload(file=file_name)]
70
+
71
+ pre_prompt = (
72
+ "The following instruction is in English. Process it carefully. "
73
+ "Your task is to edit the image based on the instruction. If the instruction asks to change the text in the image, identify the existing text in the image and replace it with the new text specified in the instruction. "
74
+ "For example, if the instruction says 'Change the text to \"Amir\"', find the text in the image (e.g., 'HONEY') and replace it with 'Amir'. Do not use the instruction text itself as the new text. "
75
+ "Ensure the new text matches the style, font, and position of the original text as closely as possible. Generate an edited image with the changes applied."
76
+ )
77
+ full_text = pre_prompt + "\n" + text
78
+
79
+ contents = [
80
+ types.Content(
81
+ role="user",
82
+ parts=[
83
+ types.Part.from_uri(
84
+ file_uri=files[0].uri,
85
+ mime_type=files[0].mime_type,
86
+ ),
87
+ types.Part.from_text(text=full_text),
88
+ ],
89
+ ),
90
+ ]
91
+ generate_content_config = types.GenerateContentConfig(
92
+ temperature=1,
93
+ top_p=0.95,
94
+ top_k=40,
95
+ max_output_tokens=8192,
96
+ response_modalities=["image", "text"],
97
+ response_mime_type="text/plain",
98
+ )
99
+
100
+ text_response = ""
101
+ image_path = None
102
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
103
+ temp_path = tmp.name
104
  for chunk in client.models.generate_content_stream(
105
  model=model,
106
  contents=contents,
107
  config=generate_content_config,
108
  ):
109
+ if not chunk.candidates or not chunk.candidates[0].content or not chunk.candidates[0].content.parts:
110
+ continue
111
+ candidate = chunk.candidates[0].content.parts[0]
112
+ if candidate.inline_data:
113
+ save_binary_file(temp_path, candidate.inline_data.data)
114
+ image_path = temp_path
115
+ break
116
+ else:
117
  text_response += chunk.text + "\n"
118
 
119
+ del files
120
+ return image_path, text_response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  def process_single_api(api_key, prompt, file_name, model):
123
  if not api_key:
124
  return None, "API key not provided"
125
 
126
  try:
127
+ translated_prompt = translate_prompt_to_english(prompt, api_key, model)
128
+ image_path, text_response = generate_with_api(api_key, translated_prompt, file_name, model)
 
 
 
 
 
 
129
 
130
  if image_path:
131
  result_img = Image.open(image_path)
132
  if result_img.mode == "RGBA":
133
  result_img = result_img.convert("RGB")
134
  return result_img, ""
 
135
  return None, text_response if text_response else "No image generated"
136
 
137
  except Exception as e:
138
+ return None, f"Error with API {api_key[-4:]}: {str(e)}"
139
 
140
  def process_image_and_prompt(composite_pil, prompt):
141
  try:
 
154
  result_images = []
155
  error_messages = []
156
 
157
+ # اجرای همزمان با 4 thread (هر API در یک thread جدا)
158
  with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
159
  futures = {
160
  executor.submit(
161
  process_single_api,
162
  api_key, prompt, composite_path, model
163
+ ): api_key for api_key in api_keys
164
  }
165
 
166
  for future in concurrent.futures.as_completed(futures):
 
168
  if image:
169
  result_images.append(image)
170
  if error:
171
+ error_messages.append(error)
172
 
173
  os.unlink(composite_path)
174
 
175
  if not result_images:
176
+ return None, "\n".join(error_messages) + "\n\n**توجه**: اگر تصویر تولید نشد، لطفاً دستور خود را واضح‌تر بنویسید یا دوباره امتحان کنید."
 
177
 
178
  return result_images, ""
179
 
180
  except Exception as e:
181
+ raise gr.Error(f"خطا در پردازش: {e}", duration=5)
182
 
183
  css = """
184
  footer { visibility: hidden; }
 
188
  }
189
  """
190
 
191
+ with gr.Blocks(css_paths="style.css", css=css) as demo:
192
+ gr.HTML(
193
+ """
194
  <div class="header-container">
195
+ <div>
196
+ <img src="https://uploadkon.ir/uploads/4a3e22_25IMG-%DB%B2%DB%B0%DB%B2%DB%B5%DB%B0%DB%B3%DB%B2%DB%B2-%DB%B1%DB%B7%DB%B1%DB%B8%DB%B5%DB%B2.jpg" alt="Alfa AI logo">
197
+ </div>
198
+ <div>
199
+ <h1>ویرایش جادویی تصاویر با هوش مصنوعی آلفا</h1>
200
+ </div>
201
  </div>
202
+ """
203
+ )
204
 
205
+ with gr.Accordion("⚠️ راهنمای استفاده", open=False, elem_classes="config-accordion"):
206
  gr.Markdown("""
207
  ### راهنمای استفاده
208
  - تصویر خود را آپلود کرده و دستور ویرایش را وارد کنید
209
+ - در صورت بروز خطا، پیام مربوطه نمایش داده خواهد شد
210
+ - فقط تصاویر با فرمت PNG آپلود کنید
211
+ - از آپلود تصاویر نامناسب خودداری کنید
212
+ """)
213
+
214
+ with gr.Accordion("📌 دستورالعمل‌های ویرایش", open=False, elem_classes="instructions-accordion"):
215
+ gr.Markdown("""
216
+ ### نمونه دستورات ویرایش
217
+ - متن تصویر را به \"متن جدید\" تغییر بده
218
+ - شیء خاصی را از تصویر حذف کن
219
+ - استایل خاصی به بخشی از تصویر اضافه کن
220
+ - تغییرات رنگی روی تصویر اعمال کن
221
  """)
222
 
223
+ with gr.Row(elem_classes="main-content"):
224
+ with gr.Column(elem_classes="input-column"):
225
+ image_input = gr.Image(
226
+ type="pil",
227
+ label="تصویر را آپلود کنید",
228
+ image_mode="RGBA",
229
+ elem_id="image-input",
230
+ elem_classes="upload-box"
231
+ )
232
+ prompt_input = gr.Textbox(
233
+ lines=2,
234
+ placeholder="تصویر چیکار بشه؟ اینجا بنویسید...",
235
+ label="دستور ویرایش",
236
+ elem_classes="prompt-input"
237
+ )
238
+ submit_btn = gr.Button("اعمال تغییرات", elem_classes="generate-btn")
239
 
240
+ with gr.Column(elem_classes="output-column"):
241
+ output_gallery = gr.Gallery(label="تصاویر ویرایش شده", elem_classes="output-gallery")
242
+ output_text = gr.Textbox(
243
+ label="پیام سیستم",
244
+ placeholder="در صورت بروز خطا، پیام مربوطه اینجا نمایش داده می‌شود.",
245
+ elem_classes="output-text"
246
+ )
247
 
248
  submit_btn.click(
249
+ fn=process_image_and_prompt,
250
  inputs=[image_input, prompt_input],
251
+ outputs=[output_gallery, output_text],
252
  )
253
 
254
+ gr.Markdown("## نمونه‌های آماده", elem_classes="gr-examples-header")
255
+
256
+ examples = [
257
+ ["data/1.webp", 'متن را به "امیر" تغییر بده', ""],
258
+ ["data/2.webp", "قاشق را از دست حذف کن", ""],
259
+ ["data/3.webp", 'متن را به "بساز" تغییر بده', ""],
260
+ ["data/1.jpg", "فقط روی صورت استایل جوکر اضافه کن", ""],
261
+ ["data/1777043.jpg", "فقط روی صورت استایل جوکر اضافه کن", ""],
262
+ ["data/2807615.jpg", "فقط روی لب‌ها رژ لب اضافه کن", ""],
263
+ ["data/76860.jpg", "فقط روی لب‌ها رژ لب اضافه کن", ""],
264
+ ["data/2807615.jpg", "فقط صورت را شادتر کن", ""],
265
+ ]
266
+
267
  gr.Examples(
268
+ examples=examples,
269
+ inputs=[image_input, prompt_input],
270
+ elem_id="examples-grid"
 
 
 
271
  )
272
 
273
+ demo.queue(max_size=50).launch()