Nightfury16 commited on
Commit
345e4db
·
1 Parent(s): 7f231c2
Files changed (2) hide show
  1. app.py +51 -49
  2. requirements.txt +2 -1
app.py CHANGED
@@ -5,49 +5,44 @@ import os
5
  import base64
6
  import io
7
  from PIL import Image
 
 
8
 
9
  RUNPOD_API_KEY = os.getenv("RUNPOD_API_KEY")
10
  FAL_KEY = os.getenv("FAL_KEY")
 
11
  QWEN_ENDPOINT_ID = "jzpm1xin5cprff"
12
 
13
  os.environ["FAL_KEY"] = FAL_KEY if FAL_KEY else ""
 
14
 
15
  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."
16
 
17
  def b64_to_pil(b64_str):
18
- """Safely convert base64 string to PIL Image"""
19
- try:
20
- if not b64_str: return None
21
- if "base64," in b64_str:
22
- b64_str = b64_str.split("base64,")[1]
23
- img_data = base64.b64decode(b64_str)
24
- return Image.open(io.BytesIO(img_data))
25
- except:
26
- return None
27
 
28
- def url_to_pil(url):
29
- """Fetch URL and return PIL Image to ensure it displays in Gradio"""
30
- try:
31
- resp = requests.get(url, timeout=10)
32
- return Image.open(io.BytesIO(resp.content))
33
- except:
34
- return None
35
 
36
  def get_image_inputs(image_file, image_url):
37
- """Pre-processes inputs for all models"""
38
  if image_file:
39
  with open(image_file, "rb") as f:
40
  raw_bytes = f.read()
41
  raw_b64 = base64.b64encode(raw_bytes).decode('utf-8')
42
  fal_url = fal_client.upload_file(image_file)
43
- return raw_b64, fal_url
44
 
45
  elif image_url:
46
  resp = requests.get(image_url)
47
- raw_b64 = base64.b64encode(resp.content).decode('utf-8')
48
- return raw_b64, image_url
 
49
 
50
- return None, None
51
 
52
  def run_qwen(raw_b64, prompt):
53
  url = f"https://api.runpod.ai/v2/{QWEN_ENDPOINT_ID}/runsync"
@@ -63,7 +58,7 @@ def run_qwen(raw_b64, prompt):
63
  }
64
  }
65
  try:
66
- response = requests.post(url, headers=headers, json=payload, timeout=120)
67
  return b64_to_pil(response.json()["output"]["images"][0])
68
  except:
69
  return None
@@ -75,42 +70,49 @@ def run_fal_flux(image_url, prompt):
75
  arguments={"prompt": prompt, "image_urls": [image_url]}
76
  )
77
  result = handler.get()
78
- return url_to_pil(result['images'][0]['url'])
 
79
  except:
80
  return None
81
 
82
- def run_banana(image_url, prompt):
83
- url = "https://api.runpod.ai/v2/nano-banana-edit/runsync"
84
- headers = {"Authorization": f"Bearer {RUNPOD_API_KEY}", "Content-Type": "application/json"}
85
- payload = {"input": {"prompt": prompt, "images": [image_url], "enable_safety_checker": True}}
86
  try:
87
- response = requests.post(url, json=payload, headers=headers, timeout=120)
88
- res_data = response.json()
89
- output_val = res_data.get("output", [])
90
- img_src = output_val[0] if isinstance(output_val, list) else output_val
91
-
92
- if img_src.startswith("http"):
93
- return url_to_pil(img_src)
94
- return b64_to_pil(img_src)
95
- except:
 
 
 
 
 
 
 
 
96
  return None
97
 
98
  def compare_all(image_file, image_url, prompt):
99
- raw_b64, web_url = get_image_inputs(image_file, image_url)
100
- if not raw_b64:
101
  yield None, None, None
102
  return
103
 
104
- qwen_res, flux_res, banana_res = None, None, None
105
 
106
- qwen_res = run_qwen(raw_b64, prompt)
107
- yield qwen_res, flux_res, banana_res
108
 
109
- flux_res = run_fal_flux(web_url, prompt)
110
- yield qwen_res, flux_res, banana_res
111
 
112
- banana_res = run_banana(web_url, prompt)
113
- yield qwen_res, flux_res, banana_res
114
 
115
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
116
  gr.Markdown("# 🛋️ Interior Design Model Arena")
@@ -120,7 +122,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
120
  input_file = gr.Image(label="Upload Image", type="filepath")
121
  input_url = gr.Textbox(label="OR: Image URL")
122
  input_prompt = gr.Textbox(label="Prompt", value=DEFAULT_PROMPT, lines=4)
123
- run_btn = gr.Button("Generate Side-by-Side", variant="primary")
124
 
125
  with gr.Row():
126
  with gr.Column():
@@ -132,13 +134,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
132
  out_fal = gr.Image(label="Flux Result", type="pil")
133
 
134
  with gr.Column():
135
- gr.Markdown("### Nano-Banana\n**$0.039 /req**")
136
- out_banana = gr.Image(label="Banana Result", type="pil")
137
 
138
  run_btn.click(
139
  fn=compare_all,
140
  inputs=[input_file, input_url, input_prompt],
141
- outputs=[out_qwen, out_fal, out_banana]
142
  )
143
 
144
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
5
  import base64
6
  import io
7
  from PIL import Image
8
+ from google import genai
9
+ from google.genai.types import GenerateContentConfig, ImageConfig, Part
10
 
11
  RUNPOD_API_KEY = os.getenv("RUNPOD_API_KEY")
12
  FAL_KEY = os.getenv("FAL_KEY")
13
+ GEMINI_API_KEY = os.getenv("GEMINI_VLM_KEY")
14
  QWEN_ENDPOINT_ID = "jzpm1xin5cprff"
15
 
16
  os.environ["FAL_KEY"] = FAL_KEY if FAL_KEY else ""
17
+ 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):
28
+ return Image.open(io.BytesIO(img_bytes))
 
 
 
 
 
29
 
30
  def get_image_inputs(image_file, image_url):
31
+ """Returns (raw_bytes, raw_b64, fal_url)"""
32
  if image_file:
33
  with open(image_file, "rb") as f:
34
  raw_bytes = f.read()
35
  raw_b64 = base64.b64encode(raw_bytes).decode('utf-8')
36
  fal_url = fal_client.upload_file(image_file)
37
+ return raw_bytes, raw_b64, fal_url
38
 
39
  elif image_url:
40
  resp = requests.get(image_url)
41
+ raw_bytes = resp.content
42
+ raw_b64 = base64.b64encode(raw_bytes).decode('utf-8')
43
+ return raw_bytes, raw_b64, image_url
44
 
45
+ return None, None, None
46
 
47
  def run_qwen(raw_b64, prompt):
48
  url = f"https://api.runpod.ai/v2/{QWEN_ENDPOINT_ID}/runsync"
 
58
  }
59
  }
60
  try:
61
+ response = requests.post(url, headers=headers, json=payload, timeout=60)
62
  return b64_to_pil(response.json()["output"]["images"][0])
63
  except:
64
  return None
 
70
  arguments={"prompt": prompt, "image_urls": [image_url]}
71
  )
72
  result = handler.get()
73
+ resp = requests.get(result['images'][0]['url'])
74
+ return bytes_to_pil(resp.content)
75
  except:
76
  return None
77
 
78
+ def run_gemini(image_bytes, prompt):
79
+ if not gemini_client: return None
 
 
80
  try:
81
+ response = gemini_client.models.generate_content(
82
+ model="gemini-2.5-flash-image",
83
+ contents=[
84
+ Part.from_bytes(data=image_bytes, mime_type="image/jpeg"),
85
+ prompt
86
+ ],
87
+ config=GenerateContentConfig(
88
+ response_modalities=["IMAGE"],
89
+ image_config=ImageConfig(aspect_ratio="4:3"),
90
+ candidate_count=1,
91
+ ),
92
+ )
93
+ for part in response.candidates[0].content.parts:
94
+ if part.inline_data:
95
+ return bytes_to_pil(part.inline_data.data)
96
+ except Exception as e:
97
+ print(f"Gemini Error: {e}")
98
  return None
99
 
100
  def compare_all(image_file, image_url, prompt):
101
+ raw_bytes, raw_b64, web_url = get_image_inputs(image_file, image_url)
102
+ if not raw_bytes:
103
  yield None, None, None
104
  return
105
 
106
+ qwen_img, flux_img, gemini_img = None, None, None
107
 
108
+ qwen_img = run_qwen(raw_b64, prompt)
109
+ yield qwen_img, flux_img, gemini_img
110
 
111
+ flux_img = run_fal_flux(web_url, prompt)
112
+ yield qwen_img, flux_img, gemini_img
113
 
114
+ gemini_img = run_gemini(raw_bytes, prompt)
115
+ yield qwen_img, flux_img, gemini_img
116
 
117
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
118
  gr.Markdown("# 🛋️ Interior Design Model Arena")
 
122
  input_file = gr.Image(label="Upload Image", type="filepath")
123
  input_url = gr.Textbox(label="OR: Image URL")
124
  input_prompt = gr.Textbox(label="Prompt", value=DEFAULT_PROMPT, lines=4)
125
+ run_btn = gr.Button("Generate Comparison", variant="primary")
126
 
127
  with gr.Row():
128
  with gr.Column():
 
134
  out_fal = gr.Image(label="Flux Result", type="pil")
135
 
136
  with gr.Column():
137
+ gr.Markdown("### Gemini 2.5 Flash\n**$0.039 /req**")
138
+ out_gemini = gr.Image(label="Gemini Result", type="pil")
139
 
140
  run_btn.click(
141
  fn=compare_all,
142
  inputs=[input_file, input_url, input_prompt],
143
+ outputs=[out_qwen, out_fal, out_gemini]
144
  )
145
 
146
  demo.launch(server_name="0.0.0.0", server_port=7860)
requirements.txt CHANGED
@@ -2,4 +2,5 @@ gradio
2
  requests
3
  fal-client
4
  pillow
5
- runpod
 
 
2
  requests
3
  fal-client
4
  pillow
5
+ runpod
6
+ google-genai