Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import replicate | |
| import os | |
| import requests | |
| from PIL import Image | |
| import io | |
| # Replicate API ์ค์ | |
| REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN") | |
| if not REPLICATE_API_TOKEN: | |
| raise ValueError("REPLICATE_API_TOKEN์ด ์ค์ ๋์ง ์์์ต๋๋ค. Spaces Settings์์ Secret์ ์ถ๊ฐํด์ฃผ์ธ์.") | |
| client = replicate.Client() | |
| def upload_file_to_replicate(file_path): | |
| """ํ์ผ์ ์์ URL๋ก ๋ณํ (base64 data URL ์ฌ์ฉ)""" | |
| if file_path is None: | |
| return None | |
| try: | |
| import base64 | |
| with open(file_path, "rb") as file: | |
| file_data = file.read() | |
| file_base64 = base64.b64encode(file_data).decode() | |
| # ํ์ผ ํ์ฅ์ ํ์ธ | |
| if file_path.lower().endswith('.png'): | |
| mime_type = "image/png" | |
| elif file_path.lower().endswith('.jpg') or file_path.lower().endswith('.jpeg'): | |
| mime_type = "image/jpeg" | |
| elif file_path.lower().endswith('.webp'): | |
| mime_type = "image/webp" | |
| elif file_path.lower().endswith('.gif'): | |
| mime_type = "image/gif" | |
| else: | |
| mime_type = "image/png" # ๊ธฐ๋ณธ๊ฐ | |
| data_url = f"data:{mime_type};base64,{file_base64}" | |
| return data_url | |
| except Exception as e: | |
| print(f"ํ์ผ ๋ณํ ์ค๋ฅ: {e}") | |
| return None | |
| def generate_pattern(prompt, reference_image=None): | |
| """๋ณด๋๋ธ๋ก ํจํด ์์ฑ (2์ฅ)""" | |
| try: | |
| # ๋ณด๋๋ธ๋ก ํจํด ์์ฑ์ ์ํ ํ๋กฌํํธ ๊ฐํ | |
| enhanced_prompt = f"sidewalk block pattern, paving stone design, {prompt}, top-down view, seamless tile pattern, architectural blueprint style" | |
| results = [] | |
| # ์ฐธ๊ณ ์ด๋ฏธ์ง๊ฐ ์์ ๊ฒฝ์ฐ URL๋ก ๋ณํ | |
| reference_url = None | |
| if reference_image is not None: | |
| reference_url = upload_file_to_replicate(reference_image) | |
| if reference_url is None: | |
| return None, None, "์ฐธ๊ณ ์ด๋ฏธ์ง ์ ๋ก๋์ ์คํจํ์ต๋๋ค." | |
| for i in range(2): # 2์ฅ ์์ฑ | |
| if reference_url is not None: | |
| # ์ฐธ๊ณ ์ด๋ฏธ์ง๊ฐ ์์ ๊ฒฝ์ฐ | |
| output = client.run( | |
| "black-forest-labs/flux-kontext-dev", | |
| input={ | |
| "prompt": f"{enhanced_prompt}, variation {i+1}", | |
| "input_image": reference_url, | |
| "aspect_ratio": "1:1", | |
| "num_inference_steps": 25, | |
| "guidance": 3.0, | |
| "output_format": "png", | |
| "go_fast": True | |
| } | |
| ) | |
| # FileOutput์ URL ๋ฌธ์์ด๋ก ๋ณํ | |
| result_url = str(output) | |
| else: | |
| # ํ ์คํธ๋ง์ผ๋ก ์์ฑ (SDXL ์ฌ์ฉ) | |
| output = client.run( | |
| "stability-ai/sdxl:7762fd07cf82c948538e41f63f77d685e02b063e37e496e96eefd46c929f9bdc", | |
| input={ | |
| "prompt": f"{enhanced_prompt}, variation {i+1}", | |
| "negative_prompt": "blurry, low quality, distorted, people, cars, buildings", | |
| "width": 512, | |
| "height": 512, | |
| "num_inference_steps": 20, | |
| "guidance_scale": 7.5 | |
| } | |
| ) | |
| # SDXL์ ๋ฆฌ์คํธ๋ก ๋ฆฌํด๋๋ฏ๋ก ์ฒซ ๋ฒ์งธ ์์ ์ ํ | |
| if isinstance(output, list): | |
| result_url = str(output[0]) | |
| else: | |
| result_url = str(output) | |
| results.append(result_url) | |
| return results[0], results[1], "ํจํด ์์ฑ ์๋ฃ! ๋ง์์ ๋๋ ํจํด์ ๋ค์ด๋ก๋ํ์ธ์." | |
| except Exception as e: | |
| return None, None, f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}" | |
| def apply_pattern_to_road(road_image, pattern_image): | |
| """๋๋ก์ ํจํด ์ ์ฉ""" | |
| try: | |
| # ์ด๋ฏธ์ง๋ค์ URL๋ก ๋ณํ | |
| road_url = upload_file_to_replicate(road_image) | |
| pattern_url = upload_file_to_replicate(pattern_image) | |
| if road_url is None: | |
| return None, "๋๋ก ์ด๋ฏธ์ง ์ ๋ก๋์ ์คํจํ์ต๋๋ค." | |
| if pattern_url is None: | |
| return None, "ํจํด ์ด๋ฏธ์ง ์ ๋ก๋์ ์คํจํ์ต๋๋ค." | |
| # ์์ ์คํ์ผ๋ก ๋ช ํํ ํ๋กฌํํธ | |
| # preset_prompt = "Transform the whole sidewalk pavement in the first image to have the exact same decorative pattern as shown in the second image. Replace the whole existing pavement with the new pattern. Combine these photos into one fluid scene." | |
| preset_prompt = "Combine these photos into one fluid scene. Transform the sidewalk pavement in the first image to have the exact same sidewalk block pattern as shown in the second image. Replace the existing pavement with the new sidewalk block pattern." | |
| # Multi-image list FLUX Kontext๋ก ํจํด ์ ์ฉ | |
| output = client.run( | |
| "flux-kontext-apps/multi-image-list", | |
| input={ | |
| "prompt": preset_prompt, | |
| "input_images": [road_url, pattern_url], # ๋ฆฌ์คํธ๋ก ์ ๋ฌ | |
| "aspect_ratio": "4:3", | |
| "output_format": "png", | |
| "safety_tolerance": 2 | |
| } | |
| ) | |
| # FileOutput์ URL ๋ฌธ์์ด๋ก ๋ณํ | |
| result_url = str(output) | |
| return result_url, "ํจํด ์ ์ฉ ์๋ฃ! Before/After ๋น๊ตํด๋ณด์ธ์." | |
| except Exception as e: | |
| return None, f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}" | |
| # CSS ์คํ์ผ๋ง | |
| css = """ | |
| #col-container { | |
| margin: 0 auto; | |
| max-width: 900px; | |
| } | |
| .pattern-gallery { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 10px; | |
| } | |
| .header-text { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| padding: 20px; | |
| border-radius: 15px; | |
| border: 2px solid #e0e0e0; | |
| } | |
| .logo-container { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 15px; | |
| margin-bottom: 15px; | |
| } | |
| .logo-img { | |
| width: 60px; | |
| height: 60px; | |
| border-radius: 10px; | |
| } | |
| """ | |
| with gr.Blocks(css=css, title="GoBlocks - ๋ณด๋๋ธ๋ก ๋ฆฌ๋์์ธ ์๋น์ค") as demo: | |
| with gr.Column(elem_id="col-container"): | |
| gr.Markdown(""" | |
| <h2 style="margin: 10px 0;">๋ณด๋๋ธ๋ญ ์กฐ๊ฐ๋ & ์์ธ๋ ์ ์ ์๋น์ค</h2> | |
| <p style="margin: 5px 0; font-size: 1.1em;"><strong>ํ๊ฒ</strong>: ์ง์์ฒด ํ์ ์๋น์ค ์ ๊ณต์ (๊ตฌ์ฒญ, ์์ฒญ) ๋ฐ ๊ฑด๋ฌผ์ฃผ</p> | |
| """, elem_classes="header-text") | |
| with gr.Tabs(): | |
| # ํญ 1: ํจํด ๋ง๋ค๊ธฐ | |
| with gr.TabItem("๐จ ๋ณด๋๋ธ๋ก ํจํด ๋ง๋ค๊ธฐ"): | |
| gr.Markdown("### ์ํ๋ ๋ณด๋๋ธ๋ก ํจํด์ ํ ์คํธ๋ก ์ค๋ช ํด์ฃผ์ธ์") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| pattern_prompt = gr.Textbox( | |
| label="ํจํด ์ค๋ช (์๊น, ๋ชจ์, ์ง๊ฐ ๋ฑ์ ์์ธํ ์ค๋ช ํด์ฃผ์ธ์)", | |
| placeholder="์: ๋ถ์์, ์ญ์๊ฐ ๋ชจ์, ๊ตด๊ณก์ด ์๋, ํ๋์ ์ธ", | |
| lines=3 | |
| ) | |
| reference_image = gr.Image( | |
| label="์ฐธ๊ณ ์ด๋ฏธ์ง (์ ํ์ฌํญ) - ์ฐธ๊ณ ํ ํจํด์ด๋ ๋์์ธ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ์ธ์", | |
| type="filepath" | |
| ) | |
| generate_btn = gr.Button("ํจํด ์์ฑํ๊ธฐ", variant="primary", size="lg") | |
| with gr.Row(): | |
| pattern1 = gr.Image(label="ํจํด 1", show_download_button=True) | |
| pattern2 = gr.Image(label="ํจํด 2", show_download_button=True) | |
| pattern_status = gr.Textbox(label="์ํ", interactive=False) | |
| # ์์ ํ๋กฌํํธ | |
| gr.Examples( | |
| examples=[ | |
| ["๋นจ๊ฐ์๊ณผ ํ์์ด ๊ต์ฐจํ๋ ์ฒดํฌ๋ฌด๋ฌ ํจํด"], | |
| ["์ก๊ฐํ ๋ชจ์์ ํ๋์ ์ธ ๋์์ธ, ๊ทธ๋ ์ด ํค"], | |
| ["์ ํต์ ์ธ ๋ฒฝ๋ ํจํด, ๋ฐ๋ปํ ๊ฐ์"], | |
| ["๋ฌผ๊ฒฐ ๋ฌด๋ฌ๊ฐ ์๋ ๋ธ๋ฃจ ํค์ ๋ฏธ๋๋ผ ๋ฐฉ์ง ๋ธ๋ก"] | |
| ], | |
| inputs=[pattern_prompt] | |
| ) | |
| # ํญ 2: ํจํด ์ ์ฉํ๊ธฐ | |
| with gr.TabItem("๐ฃ๏ธ ๋ณด๋๋ธ๋ก ํจํด ์ ์ฉํ๊ธฐ"): | |
| gr.Markdown("### ๋๋ก ์ฌ์ง์ ์๋ก์ด ๋ณด๋๋ธ๋ก ํจํด์ ์ ์ฉํด๋ณด์ธ์") | |
| with gr.Row(): | |
| with gr.Column(): | |
| road_image = gr.Image( | |
| label="๋๋ก/์ธ๋ ์ฌ์ง - ๋ณด๋๋ธ๋ก์ด ๋ณด์ด๋ ๋๋ก๋ ์ธ๋ ์ฌ์ง์ ์ ๋ก๋ํ์ธ์", | |
| type="filepath" | |
| ) | |
| pattern_ref = gr.Image( | |
| label="์ ์ฉํ ํจํด - ์์์ ์์ฑํ ํจํด์ด๋ ๋ค๋ฅธ ํจํด ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ์ธ์", | |
| type="filepath" | |
| ) | |
| apply_btn = gr.Button("ํจํด ์ ์ฉํ๊ธฐ", variant="primary", size="lg") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("#### Before (์๋ณธ)") | |
| original_display = gr.Image(label="์๋ณธ ๋๋ก", interactive=False) | |
| with gr.Column(): | |
| gr.Markdown("#### After (ํจํด ์ ์ฉ)") | |
| result_image = gr.Image(label="๊ฒฐ๊ณผ", show_download_button=True) | |
| apply_status = gr.Textbox(label="์ํ (before์ after๊ฐ ๊ฐ์ ๊ฒฝ์ฐ ๋ค์ ์คํํด์ฃผ์ธ์)", interactive=False) | |
| # ์ด๋ฒคํธ ํธ๋ค๋ฌ | |
| generate_btn.click( | |
| fn=generate_pattern, | |
| inputs=[pattern_prompt, reference_image], | |
| outputs=[pattern1, pattern2, pattern_status] | |
| ) | |
| apply_btn.click( | |
| fn=apply_pattern_to_road, | |
| inputs=[road_image, pattern_ref], | |
| outputs=[result_image, apply_status] | |
| ) | |
| # ์๋ณธ ์ด๋ฏธ์ง ๋ฏธ๋ฆฌ๋ณด๊ธฐ | |
| road_image.change( | |
| fn=lambda x: x, | |
| inputs=[road_image], | |
| outputs=[original_display] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |