Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -35,16 +35,15 @@ os.environ["TRANSFORMERS_CACHE"] = CACHE_PATH
|
|
| 35 |
os.environ["HF_HUB_CACHE"] = CACHE_PATH
|
| 36 |
os.environ["HF_HOME"] = CACHE_PATH
|
| 37 |
|
| 38 |
-
# ํ์ด๋จธ ํด๋์ค
|
| 39 |
class timer:
|
| 40 |
def __init__(self, method_name="timed process"):
|
| 41 |
self.method = method_name
|
| 42 |
def __enter__(self):
|
| 43 |
self.start = time.time()
|
| 44 |
-
print(f"{self.method} starts")
|
| 45 |
def __exit__(self, exc_type, exc_val, exc_tb):
|
| 46 |
end = time.time()
|
| 47 |
-
print(f"{self.method} took {
|
| 48 |
|
| 49 |
#######################################
|
| 50 |
# 1. FLUX ํ์ดํ๋ผ์ธ ๋ก๋
|
|
@@ -61,30 +60,23 @@ pipe = FluxPipeline.from_pretrained(
|
|
| 61 |
lora_path = hf_hub_download("ByteDance/Hyper-SD", "Hyper-FLUX.1-dev-8steps-lora.safetensors")
|
| 62 |
pipe.load_lora_weights(lora_path)
|
| 63 |
pipe.fuse_lora(lora_scale=0.125)
|
| 64 |
-
|
| 65 |
pipe.to(device="cuda", dtype=torch.bfloat16)
|
| 66 |
|
| 67 |
#######################################
|
| 68 |
-
# 2. Google GenAI
|
| 69 |
#######################################
|
| 70 |
|
| 71 |
def save_binary_file(file_name, data):
|
| 72 |
-
"""Google GenAI์์ ์๋ต๋ฐ์ ์ด์ง ๋ฐ์ดํฐ๋ฅผ ์ด๋ฏธ์ง ํ์ผ๋ก ์ ์ฅ"""
|
| 73 |
with open(file_name, "wb") as f:
|
| 74 |
f.write(data)
|
| 75 |
|
| 76 |
def generate_by_google_genai(text, file_name, model="gemini-2.0-flash-exp"):
|
| 77 |
-
"""
|
| 78 |
-
Google GenAI(gemini) ๋ชจ๋ธ์ ํตํด ์ด๋ฏธ์ง/ํ
์คํธ๋ฅผ ์์ฑํ๊ฑฐ๋ ๋ณํ.
|
| 79 |
-
- text: ๋ณ๊ฒฝํ ํ
์คํธ๋ ๋ช
๋ น์ด ๋ฑ ํ๋กฌํํธ
|
| 80 |
-
- file_name: ์๋ณธ ์ด๋ฏธ์ง(์: .png) ๊ฒฝ๋ก
|
| 81 |
-
- model: ์ฌ์ฉํ gemini ๋ชจ๋ธ ์ด๋ฆ
|
| 82 |
-
"""
|
| 83 |
api_key = os.getenv("GAPI_TOKEN", None)
|
| 84 |
if not api_key:
|
| 85 |
raise ValueError(
|
| 86 |
"GAPI_TOKEN ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค. "
|
| 87 |
-
"Google GenAI API
|
| 88 |
)
|
| 89 |
|
| 90 |
client = genai.Client(api_key=api_key)
|
|
@@ -122,13 +114,13 @@ def generate_by_google_genai(text, file_name, model="gemini-2.0-flash-exp"):
|
|
| 122 |
contents=contents,
|
| 123 |
config=generate_content_config,
|
| 124 |
):
|
| 125 |
-
if not chunk.candidates or not chunk.candidates[0].content
|
| 126 |
continue
|
| 127 |
-
candidate = chunk.candidates[0].content.parts[0]
|
| 128 |
|
|
|
|
| 129 |
if candidate.inline_data:
|
| 130 |
save_binary_file(temp_path, candidate.inline_data.data)
|
| 131 |
-
print(f"
|
| 132 |
image_path = temp_path
|
| 133 |
break
|
| 134 |
else:
|
|
@@ -138,24 +130,43 @@ def generate_by_google_genai(text, file_name, model="gemini-2.0-flash-exp"):
|
|
| 138 |
return image_path, text_response
|
| 139 |
|
| 140 |
#######################################
|
| 141 |
-
# 3. Diffusion
|
| 142 |
#######################################
|
| 143 |
|
| 144 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
"""
|
| 146 |
-
|
| 147 |
-
|
|
|
|
|
|
|
| 148 |
"""
|
| 149 |
-
|
| 150 |
-
|
|
|
|
| 151 |
else:
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
result = pipe(
|
| 158 |
-
prompt=[
|
| 159 |
generator=torch.Generator().manual_seed(int(seed)),
|
| 160 |
num_inference_steps=int(steps),
|
| 161 |
guidance_scale=float(scale),
|
|
@@ -163,108 +174,163 @@ def generate_initial_image(prompt, text, height, width, steps, scale, seed):
|
|
| 163 |
width=int(width),
|
| 164 |
max_sequence_length=256
|
| 165 |
).images[0]
|
| 166 |
-
|
| 167 |
return result
|
| 168 |
|
| 169 |
-
|
|
|
|
| 170 |
"""
|
| 171 |
-
|
| 172 |
-
|
| 173 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
try:
|
|
|
|
| 175 |
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
|
| 176 |
original_path = tmp.name
|
| 177 |
original_image.save(original_path)
|
| 178 |
|
| 179 |
image_path, text_response = generate_by_google_genai(
|
| 180 |
-
text=
|
| 181 |
file_name=original_path
|
| 182 |
)
|
| 183 |
-
|
| 184 |
if image_path:
|
| 185 |
with open(image_path, "rb") as f:
|
| 186 |
image_data = f.read()
|
| 187 |
-
|
| 188 |
-
return
|
| 189 |
else:
|
| 190 |
-
#
|
| 191 |
-
|
| 192 |
-
|
| 193 |
except Exception as e:
|
| 194 |
raise gr.Error(f"Error: {e}")
|
| 195 |
|
| 196 |
#######################################
|
| 197 |
-
# 4.
|
| 198 |
-
#######################################
|
| 199 |
-
|
| 200 |
-
def generate_random_letters(length: int) -> str:
|
| 201 |
-
"""
|
| 202 |
-
length ๊ธธ์ด์ ์์ ์ํ๋ฒณ(๋์๋ฌธ์) ๋ฌธ์์ด ์์ฑ
|
| 203 |
-
"""
|
| 204 |
-
letters = string.ascii_lowercase + string.ascii_uppercase
|
| 205 |
-
return "".join(random.choice(letters) for _ in range(length))
|
| 206 |
-
|
| 207 |
-
#######################################
|
| 208 |
-
# 5. ์ต์ข
ํจ์: ๋ฒํผ ํ ๋ฒ์ผ๋ก
|
| 209 |
-
# (1) ๋ฌด์์ ์ํ๋ฒณ์ผ๋ก 1์ฐจ ์ด๋ฏธ์ง ์์ฑ
|
| 210 |
-
# (2) ์ง์ง "์๋ก ๋ฐ๊ฟ ํ
์คํธ"๋ก 2์ฐจ ์ด๋ฏธ์ง ์์ฑ
|
| 211 |
#######################################
|
| 212 |
|
| 213 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
"""
|
| 215 |
-
|
| 216 |
-
|
|
|
|
| 217 |
"""
|
| 218 |
-
# (A)
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
# (B)
|
| 224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
|
| 226 |
-
# (C) 2์ฐจ ์ด๋ฏธ์ง: ์ค์ final_text๋ก ๊ต์ฒด
|
| 227 |
-
final_image = change_text_in_image(random_image, final_text)
|
| 228 |
-
|
| 229 |
return [random_image, final_image]
|
| 230 |
|
| 231 |
#######################################
|
| 232 |
-
#
|
| 233 |
#######################################
|
| 234 |
|
| 235 |
-
with gr.Blocks(title="Flux + Google GenAI (
|
| 236 |
gr.Markdown(
|
| 237 |
"""
|
| 238 |
-
# Flux + Google GenAI:
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
1
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
|
|
|
| 252 |
"""
|
| 253 |
)
|
| 254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
with gr.Row():
|
| 256 |
with gr.Column():
|
| 257 |
prompt_input = gr.Textbox(
|
| 258 |
lines=3,
|
| 259 |
-
label="Prompt (use `<
|
| 260 |
-
placeholder="
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
)
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
placeholder="์) ์๋
ํ์ธ์"
|
| 266 |
)
|
| 267 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
height = gr.Slider(label="Height", minimum=256, maximum=1152, step=64, value=512)
|
| 269 |
width = gr.Slider(label="Width", minimum=256, maximum=1152, step=64, value=512)
|
| 270 |
steps = gr.Slider(label="Inference Steps", minimum=6, maximum=25, step=1, value=8)
|
|
@@ -273,14 +339,30 @@ with gr.Blocks(title="Flux + Google GenAI (Random & Then Real Text)") as demo:
|
|
| 273 |
|
| 274 |
run_btn = gr.Button("Generate Images", variant="primary")
|
| 275 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
with gr.Column():
|
| 277 |
random_image_output = gr.Image(label="1) Random Text Image", type="pil")
|
| 278 |
final_image_output = gr.Image(label="2) Final Text Image", type="pil")
|
| 279 |
|
| 280 |
-
# ๋ฒํผ
|
| 281 |
run_btn.click(
|
| 282 |
-
fn=
|
| 283 |
-
inputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
outputs=[random_image_output, final_image_output]
|
| 285 |
)
|
| 286 |
|
|
|
|
| 35 |
os.environ["HF_HUB_CACHE"] = CACHE_PATH
|
| 36 |
os.environ["HF_HOME"] = CACHE_PATH
|
| 37 |
|
|
|
|
| 38 |
class timer:
|
| 39 |
def __init__(self, method_name="timed process"):
|
| 40 |
self.method = method_name
|
| 41 |
def __enter__(self):
|
| 42 |
self.start = time.time()
|
| 43 |
+
print(f"[TIMER] {self.method} starts")
|
| 44 |
def __exit__(self, exc_type, exc_val, exc_tb):
|
| 45 |
end = time.time()
|
| 46 |
+
print(f"[TIMER] {self.method} took {round(end - self.start, 2)}s")
|
| 47 |
|
| 48 |
#######################################
|
| 49 |
# 1. FLUX ํ์ดํ๋ผ์ธ ๋ก๋
|
|
|
|
| 60 |
lora_path = hf_hub_download("ByteDance/Hyper-SD", "Hyper-FLUX.1-dev-8steps-lora.safetensors")
|
| 61 |
pipe.load_lora_weights(lora_path)
|
| 62 |
pipe.fuse_lora(lora_scale=0.125)
|
|
|
|
| 63 |
pipe.to(device="cuda", dtype=torch.bfloat16)
|
| 64 |
|
| 65 |
#######################################
|
| 66 |
+
# 2. Google GenAI (Gemini) - ์ด๋ฏธ์ง ๋ณํ ํจ์
|
| 67 |
#######################################
|
| 68 |
|
| 69 |
def save_binary_file(file_name, data):
|
|
|
|
| 70 |
with open(file_name, "wb") as f:
|
| 71 |
f.write(data)
|
| 72 |
|
| 73 |
def generate_by_google_genai(text, file_name, model="gemini-2.0-flash-exp"):
|
| 74 |
+
"""Gemini ๋ชจ๋ธ์ ํตํด ์ด๋ฏธ์ง ๋ด๋ถ ํ
์คํธ๋ฅผ ๋ณ๊ฒฝ."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
api_key = os.getenv("GAPI_TOKEN", None)
|
| 76 |
if not api_key:
|
| 77 |
raise ValueError(
|
| 78 |
"GAPI_TOKEN ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค. "
|
| 79 |
+
"Google GenAI API๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ GAPI_TOKEN์ด ํ์ํฉ๋๋ค."
|
| 80 |
)
|
| 81 |
|
| 82 |
client = genai.Client(api_key=api_key)
|
|
|
|
| 114 |
contents=contents,
|
| 115 |
config=generate_content_config,
|
| 116 |
):
|
| 117 |
+
if not chunk.candidates or not chunk.candidates[0].content:
|
| 118 |
continue
|
|
|
|
| 119 |
|
| 120 |
+
candidate = chunk.candidates[0].content.parts[0]
|
| 121 |
if candidate.inline_data:
|
| 122 |
save_binary_file(temp_path, candidate.inline_data.data)
|
| 123 |
+
print(f"[DEBUG] Gemini returned image -> {temp_path}")
|
| 124 |
image_path = temp_path
|
| 125 |
break
|
| 126 |
else:
|
|
|
|
| 130 |
return image_path, text_response
|
| 131 |
|
| 132 |
#######################################
|
| 133 |
+
# 3. Diffusion (Flux)์ฉ ํจ์
|
| 134 |
#######################################
|
| 135 |
|
| 136 |
+
def generate_random_letters(length: int) -> str:
|
| 137 |
+
"""length ๊ธธ์ด๋งํผ ๋์๋ฌธ์ ์ํ๋ฒณ์ ๋ฌด์์๋ก ์์ฑ."""
|
| 138 |
+
letters = string.ascii_lowercase + string.ascii_uppercase
|
| 139 |
+
return "".join(random.choice(letters) for _ in range(length))
|
| 140 |
+
|
| 141 |
+
def fill_prompt_with_random_texts(prompt: str, r1: str, r2: str, r3: str) -> str:
|
| 142 |
"""
|
| 143 |
+
ํ๋กฌํํธ ๋ด <text1>, <text2>, <text3>๋ฅผ
|
| 144 |
+
๊ฐ๊ฐ r1, r2, r3๋ก ์นํ.
|
| 145 |
+
- <text1>์ ํ์ (์์ผ๋ฉด ์๋์ผ๋ก ๋ค์ ๋ถ์).
|
| 146 |
+
- <text2>, <text3>๋ ์์ผ๋ฉด ์นํ, ์์ผ๋ฉด ๋ฌด์.
|
| 147 |
"""
|
| 148 |
+
# 1) <text1>์ ํ์
|
| 149 |
+
if "<text1>" in prompt:
|
| 150 |
+
prompt = prompt.replace("<text1>", r1)
|
| 151 |
else:
|
| 152 |
+
# ์๋ ๋ง๋ถ์
|
| 153 |
+
prompt = f"{prompt} with clear readable text that says '{r1}'"
|
| 154 |
+
|
| 155 |
+
# 2) <text2>, <text3>๋ ์ ํ
|
| 156 |
+
if "<text2>" in prompt:
|
| 157 |
+
prompt = prompt.replace("<text2>", r2)
|
| 158 |
+
if "<text3>" in prompt:
|
| 159 |
+
prompt = prompt.replace("<text3>", r3)
|
| 160 |
+
|
| 161 |
+
return prompt
|
| 162 |
|
| 163 |
+
def generate_initial_image(prompt, random1, random2, random3, height, width, steps, scale, seed):
|
| 164 |
+
"""
|
| 165 |
+
Flux ํ์ดํ๋ผ์ธ์ ์ด์ฉํด (r1, r2, r3)๊ฐ ๋ค์ด๊ฐ ์ด๋ฏธ์ง๋ฅผ ์์ฑ.
|
| 166 |
+
"""
|
| 167 |
+
with torch.inference_mode(), torch.autocast("cuda", dtype=torch.bfloat16), timer("Flux Generation"):
|
| 168 |
result = pipe(
|
| 169 |
+
prompt=[prompt],
|
| 170 |
generator=torch.Generator().manual_seed(int(seed)),
|
| 171 |
num_inference_steps=int(steps),
|
| 172 |
guidance_scale=float(scale),
|
|
|
|
| 174 |
width=int(width),
|
| 175 |
max_sequence_length=256
|
| 176 |
).images[0]
|
|
|
|
| 177 |
return result
|
| 178 |
|
| 179 |
+
|
| 180 |
+
def change_multi_text_in_image(original_image, random1, final1, random2, final2, random3, final3):
|
| 181 |
"""
|
| 182 |
+
Gemini๋ฅผ ํตํด, ์ด๋ฏธ์ง ์์ r1->final1, r2->final2, r3->final3 ์์ผ๋ก ํ
์คํธ ๊ต์ฒด.
|
| 183 |
+
- r2, final2 (๋๋ r3, final3)๊ฐ ๋น ๋ฌธ์์ด์ด๋ฉด ํด๋น ๊ต์ฒด๋ ๊ฑด๋๋.
|
| 184 |
"""
|
| 185 |
+
# ๊ต์ฒด ์ง์๋ฌธ ๋ง๋ค๊ธฐ
|
| 186 |
+
instructions = []
|
| 187 |
+
if random1 and final1:
|
| 188 |
+
instructions.append(f"Change any text reading '{random1}' in this image to '{final1}'.")
|
| 189 |
+
if random2 and final2:
|
| 190 |
+
instructions.append(f"Change any text reading '{random2}' in this image to '{final2}'.")
|
| 191 |
+
if random3 and final3:
|
| 192 |
+
instructions.append(f"Change any text reading '{random3}' in this image to '{final3}'.")
|
| 193 |
+
|
| 194 |
+
# ๋ง์ฝ ๊ต์ฒด ์ง์๋ฌธ์ด ์๋ค๋ฉด ๊ทธ๋ฅ return original_image
|
| 195 |
+
if not instructions:
|
| 196 |
+
print("[WARN] No text changes requested!")
|
| 197 |
+
return original_image
|
| 198 |
+
|
| 199 |
+
full_instruction = " ".join(instructions)
|
| 200 |
try:
|
| 201 |
+
# ์์ ํ์ผ์ original_image ์ ์ฅ
|
| 202 |
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
|
| 203 |
original_path = tmp.name
|
| 204 |
original_image.save(original_path)
|
| 205 |
|
| 206 |
image_path, text_response = generate_by_google_genai(
|
| 207 |
+
text=full_instruction,
|
| 208 |
file_name=original_path
|
| 209 |
)
|
|
|
|
| 210 |
if image_path:
|
| 211 |
with open(image_path, "rb") as f:
|
| 212 |
image_data = f.read()
|
| 213 |
+
new_img = Image.open(io.BytesIO(image_data))
|
| 214 |
+
return new_img
|
| 215 |
else:
|
| 216 |
+
# ์ด๋ฏธ์ง ์์ด ํ
์คํธ๋ง ์จ ๊ฒฝ์ฐ
|
| 217 |
+
print("[WARN] Gemini returned only text:", text_response)
|
| 218 |
+
return original_image
|
| 219 |
except Exception as e:
|
| 220 |
raise gr.Error(f"Error: {e}")
|
| 221 |
|
| 222 |
#######################################
|
| 223 |
+
# 4. ๋ฉ์ธ ํ๋ก์ธ์ค ํจ์
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
#######################################
|
| 225 |
|
| 226 |
+
def run_process(
|
| 227 |
+
prompt,
|
| 228 |
+
final_text1,
|
| 229 |
+
final_text2,
|
| 230 |
+
final_text3,
|
| 231 |
+
height,
|
| 232 |
+
width,
|
| 233 |
+
steps,
|
| 234 |
+
scale,
|
| 235 |
+
seed
|
| 236 |
+
):
|
| 237 |
"""
|
| 238 |
+
1) final_text1(ํ์), final_text2, final_text3(์ต์
) ๊ฐ๊ฐ ๊ธธ์ด์ ๋ง์ถฐ ๋ฌด์์ ์ํ๋ฒณ ๋ง๋ค๊ธฐ.
|
| 239 |
+
2) prompt ๋ด <text1>, <text2>, <text3> ์นํ -> Flux๋ก 1์ฐจ(๋๋ค) ์ด๋ฏธ์ง.
|
| 240 |
+
3) Gemini ํธ์ถ -> r1->final_text1, r2->final_text2, r3->final_text3 ๊ต์ฒด -> ์ต์ข
์ด๋ฏธ์ง.
|
| 241 |
"""
|
| 242 |
+
# (A) ๋ฌด์์ ์ํ๋ฒณ
|
| 243 |
+
r1 = generate_random_letters(len(final_text1)) if final_text1 else ""
|
| 244 |
+
r2 = generate_random_letters(len(final_text2)) if final_text2 else ""
|
| 245 |
+
r3 = generate_random_letters(len(final_text3)) if final_text3 else ""
|
| 246 |
+
|
| 247 |
+
# (B) ํ๋กฌํํธ ์นํ
|
| 248 |
+
final_prompt = fill_prompt_with_random_texts(prompt, r1, r2, r3)
|
| 249 |
+
print(f"[DEBUG] final_prompt = {final_prompt}")
|
| 250 |
+
|
| 251 |
+
# (C) 1์ฐจ ์ด๋ฏธ์ง (๋๋ค ํ
์คํธ)
|
| 252 |
+
random_image = generate_initial_image(final_prompt, r1, r2, r3, height, width, steps, scale, seed)
|
| 253 |
+
|
| 254 |
+
# (D) 2์ฐจ ์ด๋ฏธ์ง (์ค์ ํ
์คํธ)
|
| 255 |
+
final_image = change_multi_text_in_image(
|
| 256 |
+
random_image,
|
| 257 |
+
r1, final_text1,
|
| 258 |
+
r2, final_text2,
|
| 259 |
+
r3, final_text3
|
| 260 |
+
)
|
| 261 |
|
|
|
|
|
|
|
|
|
|
| 262 |
return [random_image, final_image]
|
| 263 |
|
| 264 |
#######################################
|
| 265 |
+
# 5. Gradio UI
|
| 266 |
#######################################
|
| 267 |
|
| 268 |
+
with gr.Blocks(title="Flux + Google GenAI (Up to 3 Text placeholders)") as demo:
|
| 269 |
gr.Markdown(
|
| 270 |
"""
|
| 271 |
+
# Flux + Google GenAI: ์ต๋ 3๊ฐ์ `<text>` ๊ต์ฒด
|
| 272 |
+
|
| 273 |
+
## ์ฌ์ฉ ๋ฐฉ๋ฒ
|
| 274 |
+
1. ์๋ Prompt์ `<text1>`, `<text2>`, `<text3>`๋ฅผ ์ต๋ 3๊ฐ๊น์ง ๋ฐฐ์น ๊ฐ๋ฅ.
|
| 275 |
+
- ์) "A poster with <text1> in large letters, also <text2> in the corner"
|
| 276 |
+
- **<text1>์ ํ์**(์์ผ๋ฉด ์๋์ผ๋ก ๋ฌธ๊ตฌ๊ฐ ๋ค์ ๋ถ์)
|
| 277 |
+
- <text2>, <text3>๋ ๋ฃ์ด๋ ๋๊ณ , ์ ๋ฃ์ด๋ ๋จ.
|
| 278 |
+
2. "New Text #1" (ํ์), "New Text #2", "New Text #3"๋ฅผ ์
๋ ฅ.
|
| 279 |
+
- #2, #3๋ ๋น์ ๋๋ฉด ํด๋น ์๋ฆฌ ๊ต์ฒด ์์.
|
| 280 |
+
3. "Generate Images" ๋ฒํผ โ
|
| 281 |
+
(1) `<text1>`, `<text2>`, `<text3>` ์๋ฆฌ์ (๋๋ ์๋์ผ๋ก) **๋ฌด์์ ์ํ๋ฒณ** ๋ฃ์ 1์ฐจ ์ด๋ฏธ์ง ์์ฑ
|
| 282 |
+
(2) ์ด์ด Gemini ๋ชจ๋ธ์ ํตํด ๋ฌด์์ ์ํ๋ฒณ โ ์ค์ "New Text #1/2/3" ๋ณ๊ฒฝํ 2์ฐจ ์ด๋ฏธ์ง
|
| 283 |
+
- **๋ ์ด๋ฏธ์ง**(๋๋ค ํ
์คํธ โ ์ต์ข
ํ
์คํธ)๊ฐ ์์๋๋ก ์ถ๋ ฅ๋ฉ๋๋ค.
|
| 284 |
+
|
| 285 |
+
---
|
| 286 |
"""
|
| 287 |
)
|
| 288 |
|
| 289 |
+
# ์์ 5๊ฐ
|
| 290 |
+
examples = [
|
| 291 |
+
[
|
| 292 |
+
"A futuristic billboard shows <text1> and a small sign <text2> on the left side. <text3> is a hidden watermark.",
|
| 293 |
+
"HELLO", "WELCOME", "2025"
|
| 294 |
+
],
|
| 295 |
+
[
|
| 296 |
+
"A fantasy poster with <text1> and <text2> in stylized letters, plus a tiny note <text3> at the bottom.",
|
| 297 |
+
"Dragons", "MagicRealm", "Beware!"
|
| 298 |
+
],
|
| 299 |
+
[
|
| 300 |
+
"A neon sign reading <text1>, with a secondary text <text2> below. <text3> might appear in the corner.",
|
| 301 |
+
"OPEN", "24HOUR", "NoSmoking"
|
| 302 |
+
],
|
| 303 |
+
[
|
| 304 |
+
"A big invitation card with main text <text1>, subtitle <text2>, signature <text3> in cursive.",
|
| 305 |
+
"Birthday Party", "Today Only", "From Your Friend"
|
| 306 |
+
],
|
| 307 |
+
[
|
| 308 |
+
"A large graffiti wall with <text1> in bold letters, plus <text2> and <text3> near the edges.",
|
| 309 |
+
"FREEDOM", "HOPE", "LOVE"
|
| 310 |
+
]
|
| 311 |
+
]
|
| 312 |
+
|
| 313 |
with gr.Row():
|
| 314 |
with gr.Column():
|
| 315 |
prompt_input = gr.Textbox(
|
| 316 |
lines=3,
|
| 317 |
+
label="Prompt (use `<text1>`, `<text2>`, `<text3>` as needed)",
|
| 318 |
+
placeholder="Ex) A poster with <text1>, plus a line <text2>, etc."
|
| 319 |
+
)
|
| 320 |
+
final_text1 = gr.Textbox(
|
| 321 |
+
label="New Text #1 (Required)",
|
| 322 |
+
placeholder="Ex) HELLO"
|
| 323 |
)
|
| 324 |
+
final_text2 = gr.Textbox(
|
| 325 |
+
label="New Text #2 (Optional)",
|
| 326 |
+
placeholder="Ex) WELCOME"
|
|
|
|
| 327 |
)
|
| 328 |
+
final_text3 = gr.Textbox(
|
| 329 |
+
label="New Text #3 (Optional)",
|
| 330 |
+
placeholder="Ex) 2025 or anything"
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
with gr.Accordion("Advanced Settings", open=False):
|
| 334 |
height = gr.Slider(label="Height", minimum=256, maximum=1152, step=64, value=512)
|
| 335 |
width = gr.Slider(label="Width", minimum=256, maximum=1152, step=64, value=512)
|
| 336 |
steps = gr.Slider(label="Inference Steps", minimum=6, maximum=25, step=1, value=8)
|
|
|
|
| 339 |
|
| 340 |
run_btn = gr.Button("Generate Images", variant="primary")
|
| 341 |
|
| 342 |
+
gr.Examples(
|
| 343 |
+
examples=examples,
|
| 344 |
+
inputs=[prompt_input, final_text1, final_text2, final_text3],
|
| 345 |
+
label="Click to load example"
|
| 346 |
+
)
|
| 347 |
+
|
| 348 |
with gr.Column():
|
| 349 |
random_image_output = gr.Image(label="1) Random Text Image", type="pil")
|
| 350 |
final_image_output = gr.Image(label="2) Final Text Image", type="pil")
|
| 351 |
|
| 352 |
+
# ๋ฒํผ ์ก์
|
| 353 |
run_btn.click(
|
| 354 |
+
fn=run_process,
|
| 355 |
+
inputs=[
|
| 356 |
+
prompt_input,
|
| 357 |
+
final_text1,
|
| 358 |
+
final_text2,
|
| 359 |
+
final_text3,
|
| 360 |
+
height,
|
| 361 |
+
width,
|
| 362 |
+
steps,
|
| 363 |
+
scale,
|
| 364 |
+
seed
|
| 365 |
+
],
|
| 366 |
outputs=[random_image_output, final_image_output]
|
| 367 |
)
|
| 368 |
|