|
import os |
|
import logging |
|
import replicate |
|
import gradio as gr |
|
from PIL import Image |
|
import tempfile |
|
import uuid |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
REPLICATE_API_TOKEN = os.environ.get("REPLICATE_API_TOKEN", "") |
|
APP_PASSWORD = os.environ.get("APP_PASSWORD", "") |
|
REPLICATE_MODEL = os.environ.get("REPLICATE_MODEL", "") |
|
|
|
|
|
if not REPLICATE_API_TOKEN: |
|
logger.warning("REPLICATE_API_TOKEN์ด ์ค์ ๋์ง ์์์ต๋๋ค. ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํด์ฃผ์ธ์.") |
|
|
|
if not APP_PASSWORD: |
|
logger.warning("APP_PASSWORD๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค. ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํด์ฃผ์ธ์.") |
|
|
|
if not REPLICATE_MODEL: |
|
logger.warning("REPLICATE_MODEL์ด ์ค์ ๋์ง ์์์ต๋๋ค. ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํด์ฃผ์ธ์.") |
|
|
|
|
|
TEMP_DIR = os.path.join(tempfile.gettempdir(), "image_processor") |
|
os.makedirs(TEMP_DIR, exist_ok=True) |
|
logger.info(f"์์ ๋๋ ํ ๋ฆฌ ์์ฑ: {TEMP_DIR}") |
|
|
|
def upscale_image( |
|
image, |
|
scale_factor=2, |
|
output_format="jpg", |
|
sd_model="juggernaut_reborn.safetensors [338b85bc4f]", |
|
resemblance=0.6, |
|
creativity=0.35, |
|
prompt="masterpiece, best quality, highres, <lora:more_details:0.5> <lora:SDXLrender_v2.0:1>", |
|
negative_prompt="(worst quality, low quality, normal quality:2) JuggernautNegative-neg", |
|
seed=1337, |
|
dynamic=6, |
|
sharpen=0 |
|
): |
|
""" |
|
Clarity Upscaler๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง ํ์ง์ ๊ฐ์ ํฉ๋๋ค. |
|
|
|
Args: |
|
image: ์
๋ ฅ ์ด๋ฏธ์ง |
|
scale_factor: ํ๋ ๋น์จ (๊ธฐ๋ณธ๊ฐ: 2) |
|
output_format: ์ถ๋ ฅ ํ์ (๊ธฐ๋ณธ๊ฐ: jpg) |
|
sd_model: ์ฌ์ฉํ SD ๋ชจ๋ธ |
|
resemblance: ์๋ณธ๊ณผ์ ์ ์ฌ๋ (0.0-1.0) |
|
creativity: ์ฐฝ์์ฑ ์์ค (0.0-1.0) |
|
prompt: ์
์ค์ผ์ผ๋ง ๊ฐ์ด๋ ํ๋กฌํํธ |
|
negative_prompt: ๋ค๊ฑฐํฐ๋ธ ํ๋กฌํํธ |
|
seed: ๋๋ค ์๋ |
|
dynamic: ๋ค์ด๋๋ฏน ์๊ณ๊ฐ (1-10) |
|
sharpen: ์ ๋ช
๋ (0-2) |
|
|
|
Returns: |
|
๊ฐ์ ๋ ์ด๋ฏธ์ง |
|
""" |
|
if not REPLICATE_API_TOKEN: |
|
raise ValueError("REPLICATE_API_TOKEN์ด ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
|
|
if not REPLICATE_MODEL: |
|
raise ValueError("REPLICATE_MODEL์ด ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
|
|
try: |
|
|
|
temp_input_path = os.path.join(TEMP_DIR, f"input_{uuid.uuid4()}.png") |
|
image.save(temp_input_path) |
|
logger.info(f"์
๋ ฅ ์ด๋ฏธ์ง ์ ์ฅ: {temp_input_path}") |
|
|
|
|
|
replicate.client.Client(api_token=REPLICATE_API_TOKEN) |
|
|
|
|
|
logger.info(f"SD ๋ชจ๋ธ: {sd_model}") |
|
logger.info(f"์ค์ผ์ผ ํฉํฐ: {scale_factor}") |
|
logger.info(f"์ถ๋ ฅ ํ์: {output_format}") |
|
logger.info(f"์ ์ฌ๋: {resemblance}") |
|
logger.info(f"์ฐฝ์์ฑ: {creativity}") |
|
logger.info(f"๋ค์ด๋๋ฏน: {dynamic}") |
|
logger.info(f"์ ๋ช
๋: {sharpen}") |
|
logger.info(f"์๋: {seed}") |
|
|
|
|
|
output = replicate.run( |
|
REPLICATE_MODEL, |
|
input={ |
|
"seed": seed, |
|
"image": open(temp_input_path, "rb"), |
|
"prompt": prompt, |
|
"dynamic": dynamic, |
|
"handfix": "disabled", |
|
"pattern": False, |
|
"sharpen": sharpen, |
|
"sd_model": sd_model, |
|
"scheduler": "DPM++ 3M SDE Karras", |
|
"creativity": creativity, |
|
"lora_links": "", |
|
"downscaling": False, |
|
"resemblance": resemblance, |
|
"scale_factor": scale_factor, |
|
"tiling_width": 112, |
|
"output_format": output_format, |
|
"tiling_height": 144, |
|
"custom_sd_model": "", |
|
"negative_prompt": negative_prompt, |
|
"num_inference_steps": 18, |
|
"downscaling_resolution": 768 |
|
} |
|
) |
|
|
|
logger.info(f"Replicate API ์๋ต: {output}") |
|
|
|
|
|
if output and isinstance(output, list) and len(output) > 0: |
|
import requests |
|
from io import BytesIO |
|
|
|
response = requests.get(output[0]) |
|
if response.status_code == 200: |
|
result_image = Image.open(BytesIO(response.content)) |
|
|
|
|
|
if output_format.lower() == "jpg": |
|
temp_output = BytesIO() |
|
if result_image.mode == 'RGBA': |
|
result_image = result_image.convert('RGB') |
|
result_image.save(temp_output, format='JPEG', quality=95) |
|
temp_output.seek(0) |
|
result_image = Image.open(temp_output) |
|
|
|
logger.info("์ด๋ฏธ์ง ํ์ง ๊ฐ์ ์๋ฃ!") |
|
return result_image |
|
else: |
|
logger.error(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ๋ค์ด๋ก๋ ์คํจ: {response.status_code}") |
|
return None |
|
else: |
|
logger.error("API ์๋ต์์ ์ด๋ฏธ์ง๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.") |
|
return None |
|
|
|
except Exception as e: |
|
logger.error(f"ํ์ง ๊ฐ์ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") |
|
raise |
|
finally: |
|
|
|
if os.path.exists(temp_input_path): |
|
os.remove(temp_input_path) |
|
|
|
def process_and_download( |
|
password, image, scale_factor, output_format, sd_model, |
|
resemblance, creativity, dynamic, sharpen, seed |
|
): |
|
|
|
if not APP_PASSWORD: |
|
raise ValueError("์๋ฒ ์ค์ ์ค๋ฅ์
๋๋ค. APP_PASSWORD๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
|
|
if password != APP_PASSWORD: |
|
raise ValueError("์๋ชป๋ ๋น๋ฐ๋ฒํธ์
๋๋ค.") |
|
|
|
if image is None: |
|
return None, None |
|
|
|
|
|
result_img = upscale_image( |
|
image=image, |
|
scale_factor=scale_factor, |
|
output_format=output_format, |
|
sd_model=sd_model, |
|
resemblance=resemblance, |
|
creativity=creativity, |
|
dynamic=dynamic, |
|
sharpen=sharpen, |
|
seed=int(seed) |
|
) |
|
if result_img is None: |
|
return None, None |
|
|
|
|
|
ext = "jpg" if output_format.lower() == "jpg" else "png" |
|
|
|
if ext == "jpg" and result_img.mode == "RGBA": |
|
result_img = result_img.convert("RGB") |
|
|
|
filename = f"upscaled_{uuid.uuid4()}.{ext}" |
|
filepath = os.path.join(TEMP_DIR, filename) |
|
result_img.save(filepath, format="JPEG" if ext=="jpg" else "PNG") |
|
|
|
|
|
return result_img, filepath |
|
|
|
def create_interface(): |
|
with gr.Blocks(title="Clarity Upscaler") as demo: |
|
with gr.Row(): |
|
with gr.Column(): |
|
password_input = gr.Textbox( |
|
label="๋น๋ฐ๋ฒํธ", type="password", placeholder="๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์" |
|
) |
|
input_image = gr.Image(label="์๋ณธ ์ด๋ฏธ์ง", type="pil") |
|
|
|
with gr.Accordion("๊ณ ๊ธ ์ค์ ", open=False): |
|
scale_factor = gr.Slider(1, 4, value=2, step=0.5, label="ํ๋ ๋น์จ") |
|
output_format = gr.Radio(["jpg","png"], value="jpg", label="์ถ๋ ฅ ํ์") |
|
sd_model = gr.Dropdown( |
|
choices=[ |
|
"juggernaut_reborn.safetensors [338b85bc4f]", |
|
"sd_xl_base_1.0.safetensors [39d4e625d]", |
|
"sdxl_base_v0.9-9961.safetensors [3048045c]", |
|
"realisticVisionV51_v51VAE.safetensors [5ecbfa0ac]", |
|
], |
|
value="juggernaut_reborn.safetensors [338b85bc4f]", |
|
label="SD ๋ชจ๋ธ" |
|
) |
|
resemblance = gr.Slider(0.0,1.0, value=0.6, step=0.05, label="์๋ณธ ์ ์ฌ๋") |
|
creativity = gr.Slider(0.0,1.0, value=0.35,step=0.05, label="์ฐฝ์์ฑ") |
|
dynamic = gr.Slider(1,10, value=6, step=1, label="๋ค์ด๋๋ฏน ์๊ณ๊ฐ") |
|
sharpen = gr.Slider(0,2, value=0, step=0.1, label="์ ๋ช
๋") |
|
seed = gr.Number(value=1337, label="์๋", precision=0) |
|
|
|
submit_btn = gr.Button("์คํ", variant="primary") |
|
|
|
with gr.Column(): |
|
output_image = gr.Image(label="๊ฐ์ ๋ ์ด๋ฏธ์ง") |
|
download_btn = gr.DownloadButton(label="์ด๋ฏธ์ง ๋ค์ด๋ก๋") |
|
|
|
|
|
submit_btn.click( |
|
fn=process_and_download, |
|
inputs=[ |
|
password_input, |
|
input_image, scale_factor, output_format, sd_model, |
|
resemblance, creativity, dynamic, sharpen, seed |
|
], |
|
outputs=[output_image, download_btn] |
|
) |
|
|
|
return demo |
|
|
|
if __name__ == "__main__": |
|
demo = create_interface() |
|
demo.launch(share=True) |