File size: 7,981 Bytes
9ecbb13
b1f904b
6f5d954
c5d1c34
5a6a4b8
 
 
c5d1c34
 
 
 
9ecbb13
b1f904b
c5d1c34
 
 
 
f26a80f
b1f904b
 
5a6a4b8
b1f904b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6f5d954
5a6a4b8
b9401ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6f5d954
b9401ae
84b9aa2
6f5d954
 
5a6a4b8
b9401ae
 
6f5d954
b9401ae
 
b1f904b
b9401ae
 
 
 
 
 
 
 
 
 
b1f904b
 
5a6a4b8
 
 
 
b9401ae
5a6a4b8
 
b9401ae
5a6a4b8
 
 
 
 
 
b9401ae
5a6a4b8
 
 
 
 
 
b9401ae
5a6a4b8
 
 
b9401ae
5a6a4b8
 
 
 
 
 
 
 
 
b9401ae
 
 
 
5a6a4b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b9401ae
5a6a4b8
 
 
 
b9401ae
 
 
 
5a6a4b8
 
 
 
 
b9401ae
 
 
5a6a4b8
 
 
 
 
 
 
 
 
 
b9401ae
 
5a6a4b8
 
6f5d954
5a6a4b8
 
 
 
6f5d954
5a6a4b8
 
 
6f5d954
5a6a4b8
 
 
6f5d954
b9401ae
 
6f5d954
b9401ae
f26a80f
6f5d954
 
5a6a4b8
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
import streamlit as st
from groq import Groq
import json
import os
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Initialize Groq client
try:
    client = Groq(api_key=os.getenv("GROQ_API_KEY"))
except Exception as e:
    st.error(f"Failed to initialize Groq client: {e}")

# App title
st.title("🏠 AI Architect: Home Planner")
st.markdown("Get an easy-to-understand house plan with 2D/3D visualization!")

# --- USER INPUTS ---
st.header("πŸ“ Step 1: Plot Details")
col1, col2 = st.columns(2)
with col1:
    plot_length = st.number_input("Plot Length (ft)", min_value=20, max_value=500, value=50)
with col2:
    plot_width = st.number_input("Plot Width (ft)", min_value=20, max_value=500, value=40)

st.header("πŸšͺ Step 2: Room Requirements")
master_bed = st.number_input("Master Bedrooms (12x14 ft min)", min_value=0, max_value=5, value=1)
bedrooms = st.number_input("Standard Bedrooms (10x12 ft min)", min_value=0, max_value=10, value=2)
kitchens = st.number_input("Kitchens (8x10 ft min)", min_value=1, max_value=3, value=1)
study_rooms = st.number_input("Study Rooms (8x8 ft min)", min_value=0, max_value=3, value=0)
lounges = st.number_input("Lounges (12x16 ft min)", min_value=1, max_value=3, value=1)

st.header("🚽 Step 3: Washrooms")
attached_washrooms = st.number_input("Attached Washrooms (6x8 ft min)", min_value=0, max_value=5, value=1)
common_washrooms = st.number_input("Common Washrooms (5x7 ft min)", min_value=0, max_value=3, value=1)

st.header("🌳 Step 4: Extras")
parking = st.checkbox("Parking Space (12x20 ft min) πŸš—")
lawn = st.checkbox("Lawn/Garden 🌳")

# --- AI GENERATION ---
if st.button("Generate Professional Plan"):
    prompt = f"""
    Design a house plan for a {plot_length}x{plot_width} ft plot following architectural best practices.
    Return response in STRICT JSON format with these EXACT keys:
    {{
        "floor_plan": {{
            "rooms": [
                {{
                    "name": "string",
                    "x": number,
                    "y": number,
                    "width": number,
                    "height": number
                }}
            ],
            "washrooms": [
                {{
                    "name": "string",
                    "x": number,
                    "y": number,
                    "width": number,
                    "height": number
                }}
            ]
        }},
        "visualization_tips": ["string"],
        "material_suggestions": ["string"],
        "warnings": ["string"]
    }}

    Requirements:
    1. All dimensions must be numbers (not arrays)
    2. Positions must be x,y coordinates as separate numbers
    3. Room names should be clear (e.g., "Master Bedroom")
    4. Include at least {master_bed} master bedroom(s) and {bedrooms} standard bedroom(s)
    """

    try:
        response = client.chat.completions.create(
            messages=[{"role": "user", "content": prompt}],
            model="llama3-70b-8192",
            response_format={"type": "json_object"},
            temperature=0.3  # More deterministic output
        )
        
        # Parse and validate response
        plan = json.loads(response.choices[0].message.content)
        
        # Validate required fields
        required_keys = ["floor_plan", "visualization_tips", "material_suggestions", "warnings"]
        for key in required_keys:
            if key not in plan:
                raise ValueError(f"Missing required key: {key}")
        
        if "rooms" not in plan["floor_plan"]:
            raise ValueError("Missing rooms in floor plan")
        
        st.success("βœ… Professionally Designed Plan Generated!")
        
        # --- 2D Visualization ---
        st.header("πŸ“ 2D Floor Plan")
        
        fig, ax = plt.subplots(figsize=(10, 8))
        colors = plt.cm.tab20.colors
        
        # Plot rooms
        for i, room in enumerate(plan['floor_plan']['rooms']):
            rect = plt.Rectangle(
                (room['x'], room['y']), 
                room['width'], 
                room['height'],
                linewidth=2,
                edgecolor='black',
                facecolor=colors[i % len(colors)])
            ax.add_patch(rect)
            
            # Add room label
            center_x = room['x'] + room['width']/2
            center_y = room['y'] + room['height']/2
            ax.text(center_x, center_y, 
                   f"{room.get('name', 'Room')}\n{room['width']}x{room['height']}ft",
                   ha='center', va='center', fontsize=8)
        
        # Plot washrooms
        for washroom in plan['floor_plan'].get('washrooms', []):
            rect = plt.Rectangle(
                (washroom['x'], washroom['y']), 
                washroom['width'], 
                washroom['height'],
                linewidth=2,
                edgecolor='black',
                facecolor='lightblue',
                hatch='/')
            ax.add_patch(rect)
            ax.text(washroom['x'] + washroom['width']/2,
                   washroom['y'] + washroom['height']/2,
                   "Bath",
                   ha='center', va='center', fontsize=8)
        
        # Set plot limits and labels
        ax.set_xlim(0, plot_length)
        ax.set_ylim(0, plot_width)
        ax.set_aspect('equal')
        ax.set_xlabel('Length (ft)')
        ax.set_ylabel('Width (ft)')
        ax.set_title('2D Floor Plan')
        st.pyplot(fig)
        
        # --- 3D Visualization ---
        st.header("✨ 3D Visualization")
        
        fig_3d = go.Figure()
        
        # Add rooms as 3D boxes
        for i, room in enumerate(plan['floor_plan']['rooms']):
            fig_3d.add_trace(go.Mesh3d(
                x=[room['x'], room['x'], room['x']+room['width'], room['x']+room['width'], room['x']],
                y=[room['y'], room['y']+room['height'], room['y']+room['height'], room['y'], room['y']],
                z=[0, 0, 0, 0, 0],
                opacity=0.7,
                color=f'rgb({colors[i][0]*255},{colors[i][1]*255},{colors[i][2]*255})',
                name=room.get('name', 'Room'),
                showlegend=True
            ))
            fig_3d.add_trace(go.Mesh3d(
                x=[room['x'], room['x'], room['x']+room['width'], room['x']+room['width'], room['x']],
                y=[room['y'], room['y']+room['height'], room['y']+room['height'], room['y'], room['y']],
                z=[10, 10, 10, 10, 10],
                opacity=0.7,
                color=f'rgb({colors[i][0]*255},{colors[i][1]*255},{colors[i][2]*255})',
                showlegend=False
            ))
        
        fig_3d.update_layout(
            scene=dict(
                xaxis=dict(title='Length (ft)'),
                yaxis=dict(title='Width (ft)'),
                zaxis=dict(title='Height (ft)'),
                aspectmode='manual',
                aspectratio=dict(x=1, y=plot_width/plot_length, z=0.2)
            ),
            margin=dict(r=20, l=10, b=10, t=30),
            legend=dict(x=1, y=1)
        )
        st.plotly_chart(fig_3d)
        
        # --- Additional Information ---
        st.header("πŸ’‘ Visualization Tips")
        for tip in plan['visualization_tips']:
            st.markdown(f"- {tip}")
        
        st.header("πŸ—οΈ Material Suggestions")
        for material in plan['material_suggestions']:
            st.markdown(f"- {material}")
        
        st.header("⚠️ Warnings")
        for warning in plan['warnings']:
            st.markdown(f"- ⚠️ {warning}")
        
    except json.JSONDecodeError:
        st.error("Failed to parse the AI response. Please try again.")
    except Exception as e:
        st.error(f"Error: {str(e)}. Please adjust your inputs and try again.")

# Footer
st.markdown("---")
st.caption("βœ… Easy-to-understand visualizations | Powered by Groq API")