Spaces:
Sleeping
Sleeping
File size: 19,642 Bytes
b82669b 6ed7b88 86984d7 6ed7b88 164cc30 a53498e b82669b 164cc30 a53498e 6ed7b88 70b0f86 164cc30 a53498e 44aabf0 8baca7f 44aabf0 6ed7b88 8baca7f 6ed7b88 44aabf0 6ed7b88 164cc30 6ed7b88 44aabf0 5bd6fc2 6ed7b88 ee69673 1a26aa3 ee69673 641c67d 1a26aa3 641c67d 1a26aa3 641c67d 1a26aa3 641c67d 1a26aa3 641c67d 1a26aa3 641c67d 1a26aa3 641c67d 1a26aa3 641c67d 1a26aa3 a53498e 1a26aa3 70b0f86 641c67d 70b0f86 1a26aa3 a53498e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | import os
import openai
import asyncio
import os
import uuid
import json
import re
from typing import Dict, List, Optional
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from dotenv import load_dotenv
from openai import OpenAI
import json
from dotenv import load_dotenv
from openai import OpenAI
from agents import Agent, Runner, handoff
from agents.handoffs import HandoffInputData
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
from typing import Dict, Any
import requests
from PIL import Image
from io import BytesIO
from fastapi import Request, Response
# Load environment and initialize OpenAI
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(api_key=api_key)
app = FastAPI()
# ---- Final Rendering Agent: Generates a prompt for a beautiful image ---- #
FinalRenderingAgent = Agent(
name="FinalRenderingAgent",
model="gpt-4-turbo",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are an elite interior designer specializing in creating ultra-realistic, high-end design renderings for top-tier architecture magazines.
You will receive three essential inputs:
1. **blueprint_layout**: This includes the room type, precise dimensions (length, width, height), zones (furniture areas), and layout constraints.
2. **aesthetic_direction**: This includes the user's design style (e.g., Minimalist, Japandi), preferred color palette, and material choices (e.g., wood, metal, fabric).
3. **blueprint_image_prompt**: A detailed description of the room layout, based on the user's design choices, which provides a top-down, labeled view.
### What you need to do:
- Use the information from these three inputs to generate a **photo-realistic, magazine-cover-ready** image prompt.
- Ensure the image **feels authentic**, **visually stunning**, and **perfectly aligned** with the user's design style and room layout preferences.
### Refined visual expectations:
- **Lighting**: Ensure natural light flows into the space, casting soft shadows across the furniture and materials. The lighting should enhance the mood of the design style (e.g., soft, warm light for Japandi or bright, sharp lighting for Modern).
- **Material Reflections**: Realistic reflections on glossy or shiny materials (e.g., marble, glass, metal) — make sure the textures are true to the material and captured in perfect proportion.
- **Camera Angle**: A slightly elevated perspective, offering a wide-angle view of the room to showcase the layout, flow, and design elements. The camera angle should highlight the spatial harmony of the room, not top-down but with a soft tilt to capture the depth and richness.
- **Room Zones**: The furniture arrangement should be optimized for natural light and room flow. Clearly display the zones (e.g., seating, storage, work areas) and make sure the placement looks cohesive and functional.
- **Staging**: The room should be tastefully staged, using **minimalistic elegance**. Incorporate carefully chosen decor elements that enhance the mood but don't clutter the scene.
- **Materials and Textures**: Make sure that materials like wood, metal, stone, and fabric are not only realistic but also express the chosen design style. The textures should feel tangible and detailed.
- **Space Balance**: The design should feel spacious, uncluttered, and well-balanced, with the furniture and features placed in harmony, enhancing the feeling of openness or coziness depending on the style.
- **Aesthetic Tone**: The image should evoke a **warm**, **welcoming**, **editorial** style that could appear in a high-end design magazine. The image should be an eye-catching visual statement that speaks to the chosen design style.
Use the **blueprint_image_prompt** as a base and elevate it into an actual scene, transforming the technical layout into a gorgeous, lifelike render prompt.
Return only the **final image prompt** — do not include any additional commentary or explanations. The goal is to create a prompt that will produce an incredibly realistic, styled image worthy of a feature in a top-tier design magazine.
The room layout should reflect the **user's specific input**, respecting their aesthetic and spatial preferences. Make sure the final render looks stunning, professionally staged, and true to the desired atmosphere.
""",
)
# ---- BlenderAgent: Generates the Blender code based on the Blueprint Agent ---- #
BlenderCodeAgent = Agent(
name="BlenderCodeAgent",
model="gpt-4-turbo",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a 3D modeling assistant that writes **Blender Python scripts using the `bpy` module** to generate realistic, top-down room blueprints in 3D space.
You will be provided two inputs:
1. `blueprint_image_prompt`: A natural language description of a room layout.
2. `blueprint_layout`: A structured JSON object containing:
- `dimensions_ft`: Room dimensions in feet.
- `zones`: List of named zones, each with furniture items and optional placement notes.
- `layout_constraints`: Rules about placement (e.g., "don’t block the window").
Your job:
- Generate Blender Python code that:
- Creates a room of the specified size.
- Converts all dimensions from **feet to meters** (1 ft = 0.3048 m).
- Adds walls, doors, and windows.
- Adds basic geometric placeholders for furniture (e.g., cubes, cylinders).
- Organizes items by zone using `bpy.data.collections.new()` and links them into the scene.
- Honors layout constraints if provided.
- Adds meaningful comments in the code.
Output rules:
- **Do not include** any explanations or Markdown.
- Output **only** the raw, valid Blender Python code.
- Skip any `import bpy` (assume it's already imported).
- Make sure every object is named clearly (e.g., "Sink_01", "Toilet_01").
Your output will be copied directly into Blender’s scripting window, so it must be valid Python.
"""
)
# ---- RoomContextAgent: Get type of room and it's dimentions ---- #
RoomContextAgent = Agent(
name="RoomContextAgent",
model="gpt-4-turbo",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are an expert interior architect specializing in spatial room planning.
You will receive JSON that includes 'room_context', 'furnishing_details', and 'aesthetic_direction'.
Focus only on the 'room_context' key.
Steps:
1. Briefly confirm and summarize the room specs.
2. Flag any design implications (e.g., low ceiling, minimal light).
3. Output the summary in bullet points or a short paragraph.
"""
)
# ---- FurnishingDetails Agent: Get the required furniture, fixed features, and layout constraints ---- #
FurnishingDetailsAgent = Agent(
name="FurnishingDetailsAgent",
model="gpt-4-1106-preview",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a furniture layout strategist who helps organize furnishings for optimal space flow.
You will receive JSON that includes 'room_context', 'furnishing_details', and 'aesthetic_direction'.
Focus only on the 'furnishing_details' key with:
- "must_have": a list of key furniture items (e.g., sofa, coffee table)
- "fixed_features": immovable elements (e.g., fireplace, radiator)
- "layout_constraints": rules or restrictions (e.g., 'no furniture in front of window')
Steps:
1. Acknowledge and restate what the user wants and needs.
2. Note any conflicts, constraints, or layout challenges you foresee.
3. Suggest tips or trade-offs to improve layout and flow.
4. Output your response clearly in bullet points or a short summary.
"""
)
# ---- Aesthetic Direction Agent: Get the design style, color palette, and materials for the room ---- #
AestheticDirectionAgent = Agent(
name="AestheticDirectionAgent",
model="gpt-4-turbo",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a professional interior stylist crafting a clear and beautiful design vision.
You will receive JSON that includes 'room_context', 'furnishing_details', and 'aesthetic_direction'.
Focus only on the 'aesthetic_direction' key.
You will receive a JSON object under the key `aesthetic_direction` with:
- "design_style": e.g., Minimalist, Japandi, Industrial
- "color_palette": list of colors the user prefers (e.g., warm neutrals, navy blue)
- "materials": list of textures or materials (e.g., wood, metal, linen)
Your task:
1. Create a short design narrative explaining how these elements come together.
2. Offer styling suggestions or mood inspiration to guide the final room render.
3. Make sure your output sounds like a design board summary — elevated but accessible.
""",
handoffs=[
handoff(FinalRenderingAgent)
]
)
# ---- Blueprint Agent: Generates the prompt and json structure for the high level blueprint taking into account the room context and furnture ---- #
BlueprintAgent = Agent(
name="BlueprintAgent",
model="gpt-4-turbo",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a professional interior space planner. You will receive two keys of information:
1. `room_context` with keys:
- `room_type` (e.g., bedroom, kitchen)
- `dimensions` as a dictionary with `length`, `width`, `height` (in feet)
- `windows` and `doors` count
2. `furnishing_details` with keys:
- `must_have`: list of furniture items (e.g., "bed", "nightstand")
- `fixed_features`: immovable features (e.g., "fireplace")
- `layout_constraints`: constraints (e.g., "TV must face window")
Your job is to:
1. Analyze spatial dimensions and evaluate how to efficiently distribute furniture across the space.
2. Group items into layout zones, using labels like: Seating Area, Entertainment Area, Sleeping Area, Dining Area, Work Area, Storage Zone, Dressing Area, Entryway Zone, Outdoor/Patio Area, Play Area, Pet Zone, Kitchen Cooking Zone, Kitchen Cleaning Zone, Kitchen Storage Zone, Bathroom Washing Zone, Bathroom Bathing Zone, Bathroom Toilet Zone, Laundry Zone, Fitness Area, Creative Studio Zone
3. Provide spatial planning notes on flow, furniture spacing, lighting, and visibility.
4. Generate a detailed image prompt for a 3D blueprint diagram, specifying furniture placement, wall features, and circulation paths. Use clear, visual language so a blueprint-generating agent can render it accurately.
Zone suggestions based on items:
* sofa, chairs, coffee table → Seating Area
* TV, media console → Entertainment Area
* bed, nightstand, dresser → Sleeping Area
* dining table, dining chairs → Dining Area
* desk, office chair, shelving → Work Area
* bookshelf, cabinet, closet → Storage Zone
* vanity, mirror, wardrobe → Dressing Area
* console table, shoe rack, coat hooks → Entryway Zone
* lounge chair, bistro set, planter → Outdoor/Patio Area
* toy storage, rug, play table → Play Area
* pet bed, litter box, feeding station → Pet Zone
* stove, oven, prep counter → Kitchen Cooking Zone
* sink, dishwasher, trash bin → Kitchen Cleaning Zone
* pantry, fridge, cabinets → Kitchen Storage Zone
* sink, mirror, vanity → Bathroom Washing Zone
* bathtub, shower → Bathroom Bathing Zone
* toilet, toilet paper holder → Bathroom Toilet Zone
* washer, dryer, folding counter → Laundry Zone
* yoga mat, weights, mirror → Fitness Area
* easel, crafting table, tool storage → Creative Studio Zone
Output format:
```
{{
"blueprint_layout": {{
"dimensions_ft": {{ ... }},
"zones": [
{{
"name": "Sleeping Area",
"items": ["bed", "nightstand"],
"placement": "Against longest wall with good light access"
}},
...
],
"layout_constraints": [ ... ]
}},
""blueprint_image_prompt": "Render a clean, 3D isometric blueprint of a 12x10 ft bedroom in the style of a Blender clay model—neutral white or grey tones, no textures, and soft ambient lighting. Visually divide the space into labeled zones: a Sleeping Area with a bed and nightstands, a Storage Zone with a dresser or closet, and a small Work Area with a desk and chair. Clearly show windows and doors. Ensure furniture is proportionally scaled and arranged for optimal flow and natural light..."
}}
```
Be concise, structured, and avoid unnecessary repetition.
""",
handoffs=[
handoff(BlenderCodeAgent),
handoff(FinalRenderingAgent)
]
)
# --- InputAgent: Collect inputs from the user and passes this to the subsequent agents ---- #
InputAgent = Agent(
name="InputAgent",
model="gpt-4-turbo",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a helpful, world-class, and collaborative interior design assistant working with a team of specialized AI-agents.
Your job is to gather design preferences from the user in a friendly, efficient, and structured way. After collecting everything, you will organize the responses into a structured JSON and pass them to the next agent(s).
Conversation Rules:
- Ask 3 questions at a time in each message.
- After receiving an answer, ask the next 3 questions.
- There are 9 total questions (grouped into 3 sets of 3).
- Wait for the user's reply before proceeding to the next set.
- NEVER ask the user to format anything in JSON.
- Be casual, friendly, and brief in tone.
- After collecting all responses, return ONLY the structured JSON (no markdown or commentary).
Please answer all of the following questions so we can begin designing your space:
Group 1: Room Context
1. What type of room are you designing?
2. What is the length, width, and ceiling height of the room (in feet)?
3. How many windows and how many doors does it have?
Group 2: Furnishing Details
4. What key furniture pieces would you like to include?
5. Are there any fixed features (e.g., fireplace, built-in shelves)?
6. Any layout constraints? (e.g., 'TV must face window')
Group 3: Aesthetic Direction
7. What design style do you prefer (e.g., Art Deco, Bohemian, Coastal, Colonial, Contemporary, Eclectic, Farmhouse, French Country, Hollywood Regency, Industrial, Japandi, Mediterranean, Mid-Century Modern, Minimalist, Modern, Rustic, Scandinavian, Shabby Chic, Traditional, Transitional)?
8. What color palette do you want?
9. What materials or textures do you like (e.g., wood, linen)?
✅ Once you’ve gathered all the responses, return ONLY the structured JSON object. # <<< CHANGED
⚠️ Do NOT include any explanation, formatting, triple backticks, or markdown.
Your response must begin with `{{` and end with `}}`.
This is the required output format:
{{
"room_context": {{
"room_type": "bedroom",
"dimensions": {{
"length": 12,
"width": 10,
"height": 8
}},
"windows": 2,
"doors": 1
}},
"furnishing_details": {{
"must_have": ["bed", "nightstand"],
"fixed_features": ["fireplace"],
"layout_constraints": ["bed must face window"]
}},
"aesthetic_direction": {{
"design_style": "Japandi",
"color_palette": ["warm beige", "wood tones"],
"materials": ["linen", "natural wood"]
}}
}}
""",
handoffs=[
handoff(RoomContextAgent),
handoff(FurnishingDetailsAgent),
handoff(AestheticDirectionAgent),
]
)
# ---- . FastAPI Endpoint ---- #
app = FastAPI(
title="Home Designer Agent API",
version="1.0",
servers=[{"url": "https://schen357-homedesigneragent.hf.space"}] # ensure this matches your public Space URL
)
# --------- Stage 1: INPUT COLLECTION (InputAgent Only) ---------
class InputRequest(BaseModel):
initial_input: str
@app.post("/gather-input")
async def gather_input(request: InputRequest):
input_result = await Runner.run(InputAgent, input=[{"role": "user", "content": request.initial_input}])
# Check if input gathering is complete (contains structured JSON)
if all(k in input_result.final_output for k in ["room_context", "furnishing_details", "aesthetic_direction"]):
json_match = re.search(r"\{[\s\S]+\}", input_result.final_output)
if not json_match:
raise HTTPException(status_code=400, detail="Failed to extract JSON from InputAgent output.")
data = json.loads(json_match.group())
return {"status": "complete", "data": data}
# Still in progress — return current message
return {"status": "in_progress", "message": input_result.final_output}
# --------- Stage 2: DESIGN PIPELINE (All Downstream Agents) ---------
class StructuredInput(BaseModel):
room_context: dict
furnishing_details: dict
aesthetic_direction: dict
@app.post("/design-room")
async def design_room(request: StructuredInput):
try:
# 1. Context Agents
room_result = await Runner.run(RoomContextAgent, input=[{"role": "user", "content": json.dumps({"room_context": request.room_context})}])
furnish_result = await Runner.run(FurnishingDetailsAgent, input=[{"role": "user", "content": json.dumps({"furnishing_details": request.furnishing_details})}])
aesthetic_result = await Runner.run(AestheticDirectionAgent, input=[{"role": "user", "content": json.dumps({"aesthetic_direction": request.aesthetic_direction})}])
# 2. Blueprint
blueprint_input = {
"room_context": request.room_context,
"furnishing_details": request.furnishing_details
}
blueprint_result = await Runner.run(BlueprintAgent, input=[{"role": "user", "content": json.dumps(blueprint_input)}])
# 3. Blender Code
blender_result = await Runner.run(BlenderCodeAgent, input=[{"role": "user", "content": json.dumps({"blueprint_prompt": blueprint_result.final_output})}])
# 4. Final Rendering Prompt
final_rendering_result = await Runner.run(FinalRenderingAgent, input=[{"role": "user", "content": json.dumps({
"blueprint_layout": blueprint_result.final_output,
"aesthetic_direction": aesthetic_result.final_output,
"blueprint_image_prompt": blueprint_result.final_output
})}])
return {
"room_context": room_result.final_output,
"furnishing_details": furnish_result.final_output,
"aesthetic_direction": aesthetic_result.final_output,
"blueprint": blueprint_result.final_output,
"blender_code": blender_result.final_output,
"final_render_prompt": final_rendering_result.final_output
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# --------- Plugin Manifest (optional) ---------
@app.get("/.well-known/ai-plugin.json", include_in_schema=False)
def plugin_manifest(request: Request):
base_url = str(request.base_url).rstrip("/")
manifest = {
"schema_version": "v1",
"name_for_human": "Home Designer Agent",
"name_for_model": "home_designer_agent",
"description_for_human": "An AI to help design home rooms with GPT-based agents.",
"description_for_model": (
"Use this plugin to design rooms, get blueprint prompts, final rendering prompts, and Blender code for 3D models."
),
"auth": {"type": "none"},
"api": {
"type": "openapi",
"url": f"{base_url}/openapi.json",
"is_user_authenticated": False
},
"logo_url": f"{base_url}/logo.png",
"contact_email": "help@example.com",
"legal_info_url": "https://example.com/legal"
}
return Response(content=json.dumps(manifest), media_type="application/json")
# --------- Local Run (for testing) ---------
if __name__ == "__main__":
import uvicorn
uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=True) |