Kims12 commited on
Commit
8d852cf
Β·
verified Β·
1 Parent(s): 2de5d8c

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -7
  2. app.py +193 -0
  3. requirements .txt +6 -0
README.md CHANGED
@@ -1,13 +1,13 @@
1
  ---
2
- title: Test 22
3
- emoji: πŸ‘€
4
- colorFrom: red
5
- colorTo: green
6
  sdk: gradio
7
  sdk_version: 5.21.0
8
  app_file: app.py
9
- pinned: false
10
- license: apache-2.0
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Gemini Multi Ai
3
+ emoji: πŸ“ˆ
4
+ colorFrom: green
5
+ colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 5.21.0
8
  app_file: app.py
9
+ pinned: true
10
+ license: mit
11
  ---
12
 
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import time
4
+ import uuid
5
+ import tempfile
6
+ from PIL import Image
7
+ import gradio as gr
8
+ import base64
9
+ import mimetypes
10
+ import logging
11
+
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",
57
+ parts=[
58
+ types.Part.from_uri(
59
+ file_uri=files[0].uri,
60
+ mime_type=files[0].mime_type,
61
+ ),
62
+ types.Part.from_text(text=text),
63
+ ],
64
+ ),
65
+ ]
66
+ logger.debug(f"컨텐츠 객체 생성 μ™„λ£Œ: {contents}")
67
+
68
+ generate_content_config = types.GenerateContentConfig(
69
+ temperature=1,
70
+ top_p=0.95,
71
+ top_k=40,
72
+ max_output_tokens=8192,
73
+ response_modalities=[
74
+ "image",
75
+ "text",
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,
87
+ contents=contents,
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)
requirements .txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ google-genai==1.5.0
2
+ gradio
3
+ pydantic==2.10.6
4
+ google-generativeai
5
+ pillow
6
+ dotenv