network01's picture
Patch Gradio schema parsing on startup
f1c6a8d verified
import gradio as gr
from PIL import Image, ImageDraw
import tempfile
import json
import os
import requests
from gradio_client import utils as gradio_client_utils
_original_json_schema_to_python_type = gradio_client_utils._json_schema_to_python_type
def _safe_json_schema_to_python_type(schema, defs=None):
"""Compatibility patch for Gradio 4.44 / gradio_client 1.3 schema parsing.
Some component schemas contain additionalProperties as a boolean. Older
gradio_client assumes that value is always a dict and crashes while building
API info during Space startup.
"""
if isinstance(schema, bool):
return "Any"
if isinstance(schema, dict) and isinstance(schema.get("additionalProperties"), bool):
schema = dict(schema)
schema["additionalProperties"] = {}
return _original_json_schema_to_python_type(schema, defs)
gradio_client_utils._json_schema_to_python_type = _safe_json_schema_to_python_type
# Roboflow API configuration
ROBOFLOW_API_KEY = os.getenv("ROBOFLOW_API_KEY")
ROOM_MODEL = "room-segmentation-frntt/1"
DOOR_WINDOW_MODEL = "door-detection-model/2"
color_options = ["Red", "Green", "Blue", "Yellow"]
layer_options = ["Room Detection", "Doors and Windows Detection"]
def roboflow_infer(image_path, model_id, api_key):
"""Direct HTTP call to Roboflow inference API"""
if not api_key:
return {"predictions": [], "error": "Missing ROBOFLOW_API_KEY Space secret"}
url = f"https://detect.roboflow.com/{model_id}"
params = {"api_key": api_key}
with open(image_path, "rb") as f:
files = {"file": f}
response = requests.post(url, params=params, files=files)
if response.status_code == 200:
return response.json()
else:
print(f"API Error: {response.status_code} - {response.text}")
return {"predictions": []}
def apply_zoom(image, zoom_factor):
width, height = image.size
new_width = int(width * zoom_factor)
new_height = int(height * zoom_factor)
return image.resize((new_width, new_height))
def detect_and_draw(image_path, model_id, filter_classes=None, color_choice=None):
result = roboflow_infer(image_path, model_id, ROBOFLOW_API_KEY)
original_img = Image.open(image_path)
overlayed_img = original_img.copy()
draw = ImageDraw.Draw(overlayed_img)
counts = {}
for prediction in result.get('predictions', []):
pred_class = prediction.get('class', '').lower()
if filter_classes and pred_class not in filter_classes:
continue
counts[pred_class] = counts.get(pred_class, 0) + 1
x = int(prediction['x'] - prediction['width'] / 2)
y = int(prediction['y'] - prediction['height'] / 2)
width = int(prediction['width'])
height = int(prediction['height'])
draw.rectangle([x, y, x + width, y + height], outline=color_choice, width=2)
label = f"{pred_class}"
draw.text((x, y - 10), label, fill=color_choice)
return overlayed_img, counts
def process_floor_plan(image, zoom_factor, color_choice, selected_layers):
try:
if image is None:
return None, None, json.dumps({"error": "Please upload a floor plan image."}, indent=2)
selected_layers = selected_layers or []
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_file:
image.save(temp_file.name)
temp_file_path = temp_file.name
zoomed_image = apply_zoom(Image.open(temp_file_path), zoom_factor)
zoomed_image.save(temp_file_path)
room_overlay = None
dw_overlay = None
if "Room Detection" in selected_layers:
room_overlay, room_counts = detect_and_draw(
temp_file_path,
ROOM_MODEL,
filter_classes=["room"],
color_choice=color_choice
)
else:
room_counts = {}
if "Doors and Windows Detection" in selected_layers:
dw_overlay, dw_counts = detect_and_draw(
temp_file_path,
DOOR_WINDOW_MODEL,
filter_classes=["door", "window"],
color_choice=color_choice
)
else:
dw_counts = {}
combined_counts = {}
combined_counts.update(room_counts)
combined_counts.update(dw_counts)
return room_overlay, dw_overlay, json.dumps(combined_counts, indent=2)
except Exception as e:
return None, None, json.dumps({"error": str(e)}, indent=2)
# Gradio 5.x Interface
with gr.Blocks(title="Floor Plan Detection") as demo:
gr.Markdown("# 🏗️ Floor Plan Detection")
gr.Markdown("Upload a floor plan image to detect rooms, doors, and windows.")
with gr.Row():
with gr.Column():
input_image = gr.Image(type="pil", label="Upload Floor Plan")
zoom_factor = gr.Slider(minimum=0.5, maximum=3.0, value=1.0, step=0.1, label="Zoom Factor")
color_choice = gr.Dropdown(choices=color_options, value="Red", label="Annotation Color")
selected_layers = gr.CheckboxGroup(choices=layer_options, value=layer_options, label="Detection Layers")
process_btn = gr.Button("Process", variant="primary")
with gr.Column():
room_output = gr.Image(type="pil", label="Room Detection")
door_window_output = gr.Image(type="pil", label="Doors and Windows Detection")
output_json = gr.Textbox(label="Detection Results (JSON)", lines=10)
process_btn.click(
fn=process_floor_plan,
inputs=[input_image, zoom_factor, color_choice, selected_layers],
outputs=[room_output, door_window_output, output_json]
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, show_api=False)