Kims12 commited on
Commit
e0e8bcb
ยท
verified ยท
1 Parent(s): 3614ed9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -73
app.py CHANGED
@@ -12,41 +12,45 @@ import logging
12
  from google import genai
13
  from google.genai import types
14
 
15
- # Configure logging
 
 
 
 
16
  logging.basicConfig(level=logging.DEBUG,
17
  format='%(asctime)s - %(levelname)s - %(message)s')
18
  logger = logging.getLogger(__name__)
19
 
20
 
21
  def save_binary_file(file_name, data):
22
- logger.debug(f"Saving binary data to file: {file_name}")
23
  with open(file_name, "wb") as f:
24
  f.write(data)
25
- logger.debug(f"File saved successfully: {file_name}")
26
 
27
 
28
- def generate(text, file_name, api_key, model="gemini-2.0-flash-exp-image-generation"):
29
- logger.debug(f"Starting generate function with text: '{text}', file_name: '{file_name}', model: '{model}'")
30
 
31
  try:
32
- # Initialize client
33
- effective_api_key = api_key.strip() if api_key and api_key.strip() != "" else os.environ.get("GEMINI_API_KEY")
34
- logger.debug(f"Using API Key: {'Provided' if api_key.strip() else 'From Environment Variable'}")
35
-
36
- if not effective_api_key:
37
- logger.error("No API key provided or found in environment variable.")
38
- raise ValueError("API key is required.")
39
 
40
  client = genai.Client(api_key=effective_api_key)
41
- logger.debug("Gemini client initialized.")
42
-
43
 
 
44
  files = [
45
  client.files.upload(file=file_name),
46
  ]
47
- logger.debug(f"File uploaded. URI: {files[0].uri}, MIME Type: {files[0].mime_type}")
48
-
49
 
 
50
  contents = [
51
  types.Content(
52
  role="user",
@@ -59,7 +63,7 @@ def generate(text, file_name, api_key, model="gemini-2.0-flash-exp-image-generat
59
  ],
60
  ),
61
  ]
62
- logger.debug(f"Content object created: {contents}")
63
 
64
  generate_content_config = types.GenerateContentConfig(
65
  temperature=1,
@@ -72,11 +76,11 @@ def generate(text, file_name, api_key, model="gemini-2.0-flash-exp-image-generat
72
  ],
73
  response_mime_type="text/plain",
74
  )
75
- logger.debug(f"Generate content config: {generate_content_config}")
76
 
77
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
78
  temp_path = tmp.name
79
- logger.debug(f"Temporary file created: {temp_path}")
80
 
81
  response_stream = client.models.generate_content_stream(
82
  model=model,
@@ -84,117 +88,106 @@ def generate(text, file_name, api_key, model="gemini-2.0-flash-exp-image-generat
84
  config=generate_content_config,
85
  )
86
 
87
- logger.debug("Starting to process response stream...")
88
  for chunk in response_stream:
89
  if not chunk.candidates or not chunk.candidates[0].content or not chunk.candidates[0].content.parts:
90
- logger.warning("Chunk has no candidates, content, or parts. Skipping.")
91
  continue
92
 
93
  inline_data = chunk.candidates[0].content.parts[0].inline_data
94
  if inline_data:
95
  save_binary_file(temp_path, inline_data.data)
96
- logger.info(f"File of mime type {inline_data.mime_type} saved to: {temp_path} and prompt input :{text}")
97
  else:
98
- logger.info(f"Received text: {chunk.text}")
99
- print(chunk.text) # Keep the print for immediate console output
100
 
101
- # Log the raw chunk for deeper inspection
102
  logger.debug(f"Raw chunk: {chunk}")
103
 
104
  del files
105
- logger.debug("Uploaded files deleted.")
106
  return temp_path
107
 
108
  except Exception as e:
109
- logger.exception("An error occurred during generation:") # This will log the full traceback
110
- return None # Return None when error happens
111
 
112
 
113
- def process_image_and_prompt(composite_pil, prompt, gemini_api_key):
114
- logger.debug(f"Starting process_image_and_prompt with prompt: '{prompt}'")
115
  try:
116
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
117
  composite_path = tmp.name
118
  composite_pil.save(composite_path)
119
- logger.debug(f"Composite image saved to: {composite_path}")
120
 
121
  file_name = composite_path
122
  input_text = prompt
123
- model = "gemini-2.0-flash-exp-image-generation" # Consider changing this to "gemini-pro-vision"
124
 
125
- gemma_edited_image_path = generate(text=input_text, file_name=file_name, api_key=gemini_api_key, model=model)
126
 
127
- if gemma_edited_image_path: # Check none or not
128
- logger.debug(f"Image generated at path: {gemma_edited_image_path}")
129
  result_img = Image.open(gemma_edited_image_path)
130
  if result_img.mode == "RGBA":
131
  result_img = result_img.convert("RGB")
132
  return [result_img]
133
  else:
134
- logger.error("generate function returned None.")
135
- return [] # Return empty when error
136
 
137
  except Exception as e:
138
- logger.exception("Error occurred in process_image_and_prompt")
139
- return [] # Return empty when error
140
 
141
 
142
- # --- Gradio Interface ---
143
  with gr.Blocks() as demo:
144
  gr.HTML(
145
  """
146
  <div style='display: flex; align-items: center; justify-content: center; gap: 20px'>
147
- <div style="background-color: var(--block-background-fill); border-radius: 8px">
148
- <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
149
- </div>
150
- <div>
151
- <h1></h1>
152
- <p>แ€•แ€ฏแ€ถแ€›แ€ญแ€•แ€บแ€แ€Šแ€บแ€ธแ€–แ€ผแ€แ€บแ€›แ€”แ€บ Gemini</p>
153
- <p>API Key แ€€แ€ญแ€ฏ <a href="https://aistudio.google.com/apikey">แ€คแ€”แ€ฑแ€›แ€ฌ</a> แ€แ€ฝแ€„แ€บ แ€–แ€”แ€บแ€แ€ฎแ€ธแ€•แ€ซ</p>
154
- </div>
155
  </div>
156
  """
157
  )
158
- gr.Markdown("แ€•แ€ฏแ€ถแ€แ€…แ€บแ€•แ€ฏแ€ถ แ€แ€„แ€บแ€•แ€ผแ€ฎแ€ธ แ€•แ€ฏแ€ถแ€€แ€ญแ€ฏแ€แ€Šแ€บแ€ธแ€–แ€ผแ€แ€บแ€›แ€”แ€บ แ€žแ€„แ€บแ€œแ€ญแ€ฏแ€แ€ปแ€„แ€บแ€แ€ฌแ€€แ€ญแ€ฏ แ€›แ€ญแ€ฏแ€€แ€บแ€‘แ€Šแ€ทแ€บแ€•แ€ซแ‹")
159
 
160
  with gr.Row():
161
  with gr.Column():
162
- image_input = gr.Image(type="pil", label="แ€•แ€ฏแ€ถแ€แ€„แ€บแ€›แ€”แ€บ", image_mode="RGBA")
163
- gemini_api_key = gr.Textbox(
164
- lines=1,
165
- placeholder="Gemini API Key แ€‘แ€Šแ€ทแ€บแ€•แ€ซ",
166
- label="Gemini API Key",
167
- type="password"
168
- )
169
  prompt_input = gr.Textbox(
170
  lines=2,
171
- placeholder="แ€žแ€„แ€บแ€œแ€ญแ€ฏแ€แ€ปแ€„แ€บแ€แ€ฌแ€€แ€ญแ€ฏ แ€คแ€”แ€ฑแ€›แ€ฌแ€แ€ฝแ€„แ€บ แ€›แ€ญแ€ฏแ€€แ€บแ€‘แ€Šแ€ทแ€บแ€•แ€ซ...",
172
- label="แ€žแ€„แ€บแ€œแ€ญแ€ฏแ€แ€ปแ€„แ€บแ€แ€ฌ"
173
  )
174
- submit_btn = gr.Button("แ€‘แ€ฏแ€แ€บแ€œแ€ฏแ€•แ€บแ€•แ€ซ")
175
  with gr.Column():
176
- output_gallery = gr.Gallery(label="แ€‘แ€ฏแ€แ€บแ€œแ€ฏแ€•แ€บแ€•แ€ผแ€ฎแ€ธแ€›แ€œแ€’แ€บแ€™แ€ปแ€ฌแ€ธ")
177
 
178
  submit_btn.click(
179
  fn=process_image_and_prompt,
180
- inputs=[image_input, prompt_input, gemini_api_key],
181
  outputs=output_gallery,
182
  )
183
-
184
- # --- Test Code ---
185
- # Create a dummy image (replace with your actual image if needed)
186
  dummy_image = Image.new("RGBA", (100, 100), color="red")
187
- dummy_prompt = "Make the image blue"
188
- dummy_api_key = os.environ.get("GEMINI_API_KEY") # Or put a placeholder key here for testing
189
 
190
- # Call the function directly
191
- logger.info("Calling process_image_and_prompt directly...")
192
- result = process_image_and_prompt(dummy_image, dummy_prompt, dummy_api_key)
193
 
194
  if result:
195
- logger.info(f"Direct call successful. Result: {result}")
196
- # result[0].show() # Uncomment to display image if running locally
197
  else:
198
- logger.error("Direct call failed.")
199
 
200
- demo.launch(share=True) # gradio launch last
 
12
  from google import genai
13
  from google.genai import types
14
 
15
+ # .env ํŒŒ์ผ์— ์ €์žฅ๋œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋กœ๋“œ (python-dotenv ์„ค์น˜ ํ•„์š”: pip install python-dotenv)
16
+ from dotenv import load_dotenv
17
+ load_dotenv()
18
+
19
+ # ๋กœ๊น… ์„ค์ • (๋กœ๊ทธ ๋ ˆ๋ฒจ: DEBUG)
20
  logging.basicConfig(level=logging.DEBUG,
21
  format='%(asctime)s - %(levelname)s - %(message)s')
22
  logger = logging.getLogger(__name__)
23
 
24
 
25
  def save_binary_file(file_name, data):
26
+ logger.debug(f"ํŒŒ์ผ์— ์ด์ง„ ๋ฐ์ดํ„ฐ ์ €์žฅ ์ค‘: {file_name}")
27
  with open(file_name, "wb") as f:
28
  f.write(data)
29
+ logger.debug(f"ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {file_name}")
30
 
31
 
32
+ def generate(text, file_name, model="gemini-2.0-flash-exp-image-generation"):
33
+ logger.debug(f"generate ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ…์ŠคํŠธ: '{text}', ํŒŒ์ผ๋ช…: '{file_name}', ๋ชจ๋ธ: '{model}'")
34
 
35
  try:
36
+ # API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ถˆ๋Ÿฌ์˜ด
37
+ effective_api_key = os.environ.get("GEMINI_API_KEY")
38
+ if effective_api_key:
39
+ logger.debug("ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ API ํ‚ค ๋ถˆ๋Ÿฌ์˜ด")
40
+ else:
41
+ logger.error("API ํ‚ค๊ฐ€ ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
42
+ raise ValueError("API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
43
 
44
  client = genai.Client(api_key=effective_api_key)
45
+ logger.debug("Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ.")
 
46
 
47
+ # ํŒŒ์ผ ์—…๋กœ๋“œ
48
  files = [
49
  client.files.upload(file=file_name),
50
  ]
51
+ logger.debug(f"ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ. URI: {files[0].uri}, MIME ํƒ€์ž…: {files[0].mime_type}")
 
52
 
53
+ # ์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ: ํŒŒ์ผ URI์™€ ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ•จ๊ป˜ ํฌํ•จ
54
  contents = [
55
  types.Content(
56
  role="user",
 
63
  ],
64
  ),
65
  ]
66
+ logger.debug(f"์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ ์™„๋ฃŒ: {contents}")
67
 
68
  generate_content_config = types.GenerateContentConfig(
69
  temperature=1,
 
76
  ],
77
  response_mime_type="text/plain",
78
  )
79
+ logger.debug(f"์ƒ์„ฑ ์„ค์ •: {generate_content_config}")
80
 
81
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
82
  temp_path = tmp.name
83
+ logger.debug(f"์ž„์‹œ ํŒŒ์ผ ์ƒ์„ฑ๋จ: {temp_path}")
84
 
85
  response_stream = client.models.generate_content_stream(
86
  model=model,
 
88
  config=generate_content_config,
89
  )
90
 
91
+ logger.debug("์‘๋‹ต ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ ์‹œ์ž‘...")
92
  for chunk in response_stream:
93
  if not chunk.candidates or not chunk.candidates[0].content or not chunk.candidates[0].content.parts:
94
+ logger.warning("chunk์— ํ›„๋ณด, ์ปจํ…์ธ , ๋˜๋Š” ํŒŒํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.")
95
  continue
96
 
97
  inline_data = chunk.candidates[0].content.parts[0].inline_data
98
  if inline_data:
99
  save_binary_file(temp_path, inline_data.data)
100
+ logger.info(f"MIME ํƒ€์ž… {inline_data.mime_type}์˜ ํŒŒ์ผ์ด ์ €์žฅ๋จ: {temp_path} (ํ”„๋กฌํ”„ํŠธ: {text})")
101
  else:
102
+ logger.info(f"์ˆ˜์‹ ๋œ ํ…์ŠคํŠธ: {chunk.text}")
103
+ print(chunk.text)
104
 
 
105
  logger.debug(f"Raw chunk: {chunk}")
106
 
107
  del files
108
+ logger.debug("์—…๋กœ๋“œ๋œ ํŒŒ์ผ ์ •๋ณด ์‚ญ์ œ ์™„๋ฃŒ.")
109
  return temp_path
110
 
111
  except Exception as e:
112
+ logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
113
+ return None # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None ๋ฐ˜ํ™˜
114
 
115
 
116
+ def process_image_and_prompt(composite_pil, prompt):
117
+ logger.debug(f"process_image_and_prompt ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
118
  try:
119
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
120
  composite_path = tmp.name
121
  composite_pil.save(composite_path)
122
+ logger.debug(f"ํ•ฉ์„ฑ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {composite_path}")
123
 
124
  file_name = composite_path
125
  input_text = prompt
126
+ model = "gemini-2.0-flash-exp-image-generation"
127
 
128
+ gemma_edited_image_path = generate(text=input_text, file_name=file_name, model=model)
129
 
130
+ if gemma_edited_image_path:
131
+ logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {gemma_edited_image_path}")
132
  result_img = Image.open(gemma_edited_image_path)
133
  if result_img.mode == "RGBA":
134
  result_img = result_img.convert("RGB")
135
  return [result_img]
136
  else:
137
+ logger.error("generate ํ•จ์ˆ˜์—์„œ None ๋ฐ˜ํ™˜๋จ.")
138
+ return [] # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
139
 
140
  except Exception as e:
141
+ logger.exception("process_image_and_prompt ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
142
+ return [] # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
143
 
144
 
145
+ # --- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ ---
146
  with gr.Blocks() as demo:
147
  gr.HTML(
148
  """
149
  <div style='display: flex; align-items: center; justify-content: center; gap: 20px'>
150
+ <div style="background-color: var(--block-background-fill); border-radius: 8px">
151
+ <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
152
+ </div>
153
+ <div>
154
+ <h1>Gemini๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ํŽธ์ง‘</h1>
155
+ <p>Gemini API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜(GEMINI_API_KEY)๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.</p>
156
+ </div>
 
157
  </div>
158
  """
159
  )
160
+ gr.Markdown("์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ , ํŽธ์ง‘ํ•  ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”.")
161
 
162
  with gr.Row():
163
  with gr.Column():
164
+ image_input = gr.Image(type="pil", label="์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", image_mode="RGBA")
 
 
 
 
 
 
165
  prompt_input = gr.Textbox(
166
  lines=2,
167
+ placeholder="ํŽธ์ง‘ํ•  ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”...",
168
+ label="ํŽธ์ง‘ ํ”„๋กฌํ”„ํŠธ"
169
  )
170
+ submit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ์‹คํ–‰")
171
  with gr.Column():
172
+ output_gallery = gr.Gallery(label="ํŽธ์ง‘ ๊ฒฐ๊ณผ")
173
 
174
  submit_btn.click(
175
  fn=process_image_and_prompt,
176
+ inputs=[image_input, prompt_input],
177
  outputs=output_gallery,
178
  )
179
+
180
+ # --- ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ---
181
+ # ํ…Œ์ŠคํŠธ์šฉ ๋”๋ฏธ ์ด๋ฏธ์ง€ (์‹ค์ œ ์ด๋ฏธ์ง€๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅ)
182
  dummy_image = Image.new("RGBA", (100, 100), color="red")
183
+ dummy_prompt = "์ด๋ฏธ์ง€๋ฅผ ํŒŒ๋ž€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ค˜"
 
184
 
185
+ logger.info("process_image_and_prompt ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค...")
186
+ result = process_image_and_prompt(dummy_image, dummy_prompt)
 
187
 
188
  if result:
189
+ logger.info(f"์ง์ ‘ ํ˜ธ์ถœ ์„ฑ๊ณต. ๊ฒฐ๊ณผ: {result}")
 
190
  else:
191
+ logger.error("์ง์ ‘ ํ˜ธ์ถœ ์‹คํŒจ.")
192
 
193
+ demo.launch(share=True)