Nightfury16 commited on
Commit
359875a
ยท
1 Parent(s): fd7e20d
Files changed (1) hide show
  1. app.py +41 -62
app.py CHANGED
@@ -18,10 +18,19 @@ gemini_client = genai.Client(api_key=GEMINI_API_KEY) if GEMINI_API_KEY else None
18
 
19
  DEFAULT_PROMPT = "Add furnishings and accessories to this room as an interior designer would do for a real estate staging. The generated image shall have the exact same dimensions as the original image and architectural details. Respect doorways and windows and make sure they are consistent with the source image and not blocked by furniture. Use cute accessories and with appropriate wall space, add smart simple graphic paintings. Use neutral colors with light colored accents to match the colors of the room. Give the area an attractive glow."
20
 
 
 
 
 
 
 
 
 
 
 
21
  def b64_to_pil(b64_str):
22
  if not b64_str: return None
23
- if "base64," in b64_str:
24
- b64_str = b64_str.split("base64,")[1]
25
  return Image.open(io.BytesIO(base64.b64decode(b64_str)))
26
 
27
  def bytes_to_pil(img_bytes):
@@ -29,8 +38,7 @@ def bytes_to_pil(img_bytes):
29
 
30
  def get_image_inputs(image_file, image_url):
31
  if image_file:
32
- with open(image_file, "rb") as f:
33
- raw_bytes = f.read()
34
  raw_b64 = base64.b64encode(raw_bytes).decode('utf-8')
35
  fal_url = fal_client.upload_file(image_file)
36
  return raw_bytes, raw_b64, fal_url
@@ -44,44 +52,30 @@ def get_image_inputs(image_file, image_url):
44
  def run_qwen(raw_b64, prompt):
45
  url = f"https://api.runpod.ai/v2/{QWEN_ENDPOINT_ID}/runsync"
46
  headers = {"Content-Type": "application/json", "Authorization": f"Bearer {RUNPOD_API_KEY}"}
47
- payload = {
48
- "input": {
49
- "image": raw_b64, "prompt": prompt, "seed": 42,
50
- "use_lightning": True, "true_guidance_scale": 2.5, "num_inference_steps": 4
51
- }
52
- }
53
  try:
54
  response = requests.post(url, headers=headers, json=payload, timeout=60)
55
  return b64_to_pil(response.json()["output"]["images"][0])
56
- except:
57
- return None
58
 
59
  def run_fal_flux(image_url, prompt):
60
  try:
61
  handler = fal_client.submit("fal-ai/flux-2/edit", arguments={"prompt": prompt, "image_urls": [image_url]})
62
  result = handler.get()
63
- resp = requests.get(result['images'][0]['url'])
64
- return bytes_to_pil(resp.content)
65
- except:
66
- return None
67
 
68
- def run_gemini(image_bytes, prompt):
69
  if not gemini_client: return None
70
  try:
71
  response = gemini_client.models.generate_content(
72
  model="gemini-2.5-flash-image",
73
  contents=[Part.from_bytes(data=image_bytes, mime_type="image/jpeg"), prompt],
74
- config=GenerateContentConfig(
75
- response_modalities=["IMAGE"],
76
- image_config=ImageConfig(aspect_ratio="16:9"),
77
- candidate_count=1,
78
- ),
79
  )
80
  for part in response.candidates[0].content.parts:
81
- if part.inline_data:
82
- return bytes_to_pil(part.inline_data.data)
83
- except:
84
- return None
85
 
86
  def compare_all(image_file, image_url, prompt):
87
  raw_bytes, raw_b64, web_url = get_image_inputs(image_file, image_url)
@@ -90,66 +84,51 @@ def compare_all(image_file, image_url, prompt):
90
  return
91
 
92
  og_pil = bytes_to_pil(raw_bytes)
 
93
  qwen_img, flux_img, gemini_img = None, None, None
94
 
95
- # Step 0: Show Original
96
  yield og_pil, qwen_img, flux_img, gemini_img
97
-
98
- # Step 1: Qwen
99
  qwen_img = run_qwen(raw_b64, prompt)
100
  yield og_pil, qwen_img, flux_img, gemini_img
101
-
102
- # Step 2: Flux
103
  flux_img = run_fal_flux(web_url, prompt)
104
  yield og_pil, qwen_img, flux_img, gemini_img
105
-
106
- # Step 3: Gemini
107
- gemini_img = run_gemini(raw_bytes, prompt)
108
  yield og_pil, qwen_img, flux_img, gemini_img
109
 
110
  with gr.Blocks() as demo:
111
- gr.HTML("<h2 style='text-align: center; margin-bottom: 10px;'>๐Ÿ›‹๏ธ Interior Design Model Arena</h2>")
112
 
113
  with gr.Row():
114
- with gr.Column(scale=2):
115
- input_prompt = gr.Textbox(label="Edit Prompt", value=DEFAULT_PROMPT, lines=4)
116
  with gr.Column(scale=1):
117
- input_file = gr.Image(label="Upload Source Image", type="filepath", height=130)
118
- input_url = gr.Textbox(label="OR: Image URL", placeholder="Paste URL...")
119
- run_btn = gr.Button("๐Ÿš€ Generate All Models", variant="primary")
120
-
121
- gr.HTML("<div style='margin: 10px 0; border-bottom: 1px solid #ddd;'></div>")
122
-
123
- # TOP: Original Image
124
- with gr.Row():
125
- with gr.Column():
126
- gr.HTML("<center><b>SOURCE ORIGINAL</b></center>")
127
- out_og = gr.Image(show_label=False, type="pil", height=280)
128
 
129
- # BOTTOM: Three Models
130
  with gr.Row():
131
  with gr.Column():
132
- gr.HTML("<center><b>QWEN-EDIT</b><br><small>$0.004-$0.008</small></center>")
133
- out_qwen = gr.Image(show_label=False, type="pil", height=280)
134
 
135
  with gr.Column():
136
  gr.HTML("<center><b>FLUX-2 EDIT</b><br><small>$0.03</small></center>")
137
- out_fal = gr.Image(show_label=False, type="pil", height=280)
138
 
139
  with gr.Column():
140
  gr.HTML("<center><b>GEMINI 2.5 FLASH</b><br><small>$0.039</small></center>")
141
- out_gemini = gr.Image(show_label=False, type="pil", height=280)
142
 
143
- run_btn.click(
144
- fn=compare_all,
145
- inputs=[input_file, input_url, input_prompt],
146
- outputs=[out_og, out_qwen, out_fal, out_gemini]
147
- )
148
 
149
  if __name__ == "__main__":
150
  demo.launch(
151
- server_name="0.0.0.0",
152
- server_port=7860,
153
- theme=gr.themes.Soft(),
154
- css=".gradio-container {max-width: 95% !important} img {object-fit: contain !important;}"
155
  )
 
18
 
19
  DEFAULT_PROMPT = "Add furnishings and accessories to this room as an interior designer would do for a real estate staging. The generated image shall have the exact same dimensions as the original image and architectural details. Respect doorways and windows and make sure they are consistent with the source image and not blocked by furniture. Use cute accessories and with appropriate wall space, add smart simple graphic paintings. Use neutral colors with light colored accents to match the colors of the room. Give the area an attractive glow."
20
 
21
+ def get_closest_ratio(pil_img):
22
+ w, h = pil_img.size
23
+ ratio = w / h
24
+ ratios = {
25
+ "9:16": 0.56, "2:3": 0.66, "3:4": 0.75, "4:5": 0.8,
26
+ "1:1": 1.0, "5:4": 1.25, "4:3": 1.33, "3:2": 1.5,
27
+ "16:9": 1.77, "21:9": 2.33
28
+ }
29
+ return min(ratios, key=lambda x: abs(ratios[x] - ratio))
30
+
31
  def b64_to_pil(b64_str):
32
  if not b64_str: return None
33
+ if "base64," in b64_str: b64_str = b64_str.split("base64,")[1]
 
34
  return Image.open(io.BytesIO(base64.b64decode(b64_str)))
35
 
36
  def bytes_to_pil(img_bytes):
 
38
 
39
  def get_image_inputs(image_file, image_url):
40
  if image_file:
41
+ with open(image_file, "rb") as f: raw_bytes = f.read()
 
42
  raw_b64 = base64.b64encode(raw_bytes).decode('utf-8')
43
  fal_url = fal_client.upload_file(image_file)
44
  return raw_bytes, raw_b64, fal_url
 
52
  def run_qwen(raw_b64, prompt):
53
  url = f"https://api.runpod.ai/v2/{QWEN_ENDPOINT_ID}/runsync"
54
  headers = {"Content-Type": "application/json", "Authorization": f"Bearer {RUNPOD_API_KEY}"}
55
+ payload = {"input": {"image": raw_b64, "prompt": prompt, "seed": 42, "use_lightning": True, "true_guidance_scale": 2.5, "num_inference_steps": 4}}
 
 
 
 
 
56
  try:
57
  response = requests.post(url, headers=headers, json=payload, timeout=60)
58
  return b64_to_pil(response.json()["output"]["images"][0])
59
+ except: return None
 
60
 
61
  def run_fal_flux(image_url, prompt):
62
  try:
63
  handler = fal_client.submit("fal-ai/flux-2/edit", arguments={"prompt": prompt, "image_urls": [image_url]})
64
  result = handler.get()
65
+ return bytes_to_pil(requests.get(result['images'][0]['url']).content)
66
+ except: return None
 
 
67
 
68
+ def run_gemini(image_bytes, prompt, ratio_str):
69
  if not gemini_client: return None
70
  try:
71
  response = gemini_client.models.generate_content(
72
  model="gemini-2.5-flash-image",
73
  contents=[Part.from_bytes(data=image_bytes, mime_type="image/jpeg"), prompt],
74
+ config=GenerateContentConfig(response_modalities=["IMAGE"], image_config=ImageConfig(aspect_ratio=ratio_str), candidate_count=1)
 
 
 
 
75
  )
76
  for part in response.candidates[0].content.parts:
77
+ if part.inline_data: return bytes_to_pil(part.inline_data.data)
78
+ except: return None
 
 
79
 
80
  def compare_all(image_file, image_url, prompt):
81
  raw_bytes, raw_b64, web_url = get_image_inputs(image_file, image_url)
 
84
  return
85
 
86
  og_pil = bytes_to_pil(raw_bytes)
87
+ ratio_str = get_closest_ratio(og_pil)
88
  qwen_img, flux_img, gemini_img = None, None, None
89
 
 
90
  yield og_pil, qwen_img, flux_img, gemini_img
 
 
91
  qwen_img = run_qwen(raw_b64, prompt)
92
  yield og_pil, qwen_img, flux_img, gemini_img
 
 
93
  flux_img = run_fal_flux(web_url, prompt)
94
  yield og_pil, qwen_img, flux_img, gemini_img
95
+ gemini_img = run_gemini(raw_bytes, prompt, ratio_str)
 
 
96
  yield og_pil, qwen_img, flux_img, gemini_img
97
 
98
  with gr.Blocks() as demo:
99
+ gr.HTML("<h2 style='text-align: center; margin: 10px 0;'>๐Ÿ›‹๏ธ Interior Design Model Arena</h2>")
100
 
101
  with gr.Row():
 
 
102
  with gr.Column(scale=1):
103
+ gr.HTML("<center><b>ORIGINAL REFERENCE</b></center>")
104
+ out_og = gr.Image(show_label=False, type="pil", height=320)
105
+
106
+ with gr.Column(scale=1):
107
+ input_prompt = gr.Textbox(label="Edit Prompt", value=DEFAULT_PROMPT, lines=4)
108
+ with gr.Row():
109
+ input_file = gr.Image(label="Upload", type="filepath", height=100)
110
+ input_url = gr.Textbox(label="OR: Image URL", placeholder="Paste URL...")
111
+ run_btn = gr.Button("๐Ÿš€ Generate Comparison", variant="primary")
112
+
113
+ gr.HTML("<hr style='margin: 15px 0;'>")
114
 
 
115
  with gr.Row():
116
  with gr.Column():
117
+ gr.HTML("<center><b>QWEN-EDIT</b><br><small>$0.004 - $0.008</small></center>")
118
+ out_qwen = gr.Image(show_label=False, type="pil", height=350)
119
 
120
  with gr.Column():
121
  gr.HTML("<center><b>FLUX-2 EDIT</b><br><small>$0.03</small></center>")
122
+ out_fal = gr.Image(show_label=False, type="pil", height=350)
123
 
124
  with gr.Column():
125
  gr.HTML("<center><b>GEMINI 2.5 FLASH</b><br><small>$0.039</small></center>")
126
+ out_gemini = gr.Image(show_label=False, type="pil", height=350)
127
 
128
+ run_btn.click(fn=compare_all, inputs=[input_file, input_url, input_prompt], outputs=[out_og, out_qwen, out_fal, out_gemini])
 
 
 
 
129
 
130
  if __name__ == "__main__":
131
  demo.launch(
132
+ server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft(),
133
+ css=".gradio-container {max-width: 98% !important} img {object-fit: contain !important;}"
 
 
134
  )