Vitalis-DevCore / devcore /parser.py
FerrellSyntheticIntelligence
Add GitHub Sponsors + Buy Me A Coffee
d26d55f
Raw
History Blame Contribute Delete
8.75 kB
import re
STYLES = {
"ranch": "ranch", "rambler": "ranch",
"colonial": "colonial", "cape": "colonial",
"modern": "modern", "contemporary": "modern",
"victorian": "victorian",
"craftsman": "craftsman",
"cabin": "cabin", "cottage": "cabin",
"tudor": "tudor",
"farmhouse": "farmhouse",
}
ROOF_STYLES = {
"ranch": "hip", "rambler": "hip",
"colonial": "gable", "cape": "gable",
"modern": "flat", "contemporary": "flat",
"victorian": "steep-gable",
"craftsman": "low-gable",
"cabin": "gable", "cottage": "gable",
"tudor": "steep-gable",
"farmhouse": "gable",
}
ROOM_COLORS = {
"living": "#e8dcc8", "family": "#e8dcc8",
"kitchen": "#d4e8d0", "dining": "#e0d0c0",
"bedroom": "#d0d8e8", "master": "#c8d0e8",
"bath": "#d8e8e8", "bathroom": "#d8e8e8",
"office": "#e0d0d8", "den": "#e0d0d8",
"garage": "#d0d0d0",
"hall": "#f0ece8", "hallway": "#f0ece8",
"laundry": "#e8e0d8",
"closet": "#ece8e0",
"loft": "#e8e0d0",
"basement": "#c8c0b8",
"porch": "#d8d0c8", "deck": "#c8b8a8",
"patio": "#c8b8a8",
}
def parse_description(text):
text = text.lower().strip()
sqft = _extract_sqft(text)
width, depth = _extract_dimensions(text, sqft)
style = _extract_style(text)
stories = _extract_stories(text)
bedrooms = _extract_bedrooms(text)
bathrooms = _extract_bathrooms(text)
garage = _has_garage(text)
extra_rooms = _extract_extra_rooms(text)
rooms = _generate_rooms(width, depth, stories, bedrooms, bathrooms, garage, extra_rooms, style)
roof_style = ROOF_STYLES.get(style, "gable")
return {
"structure": {
"width": width,
"depth": depth,
"stories": stories,
"style": style,
"roof_style": roof_style,
"sqft": sqft or (width * depth * stories),
},
"rooms": rooms,
"features": {
"bedrooms": int(bedrooms),
"bathrooms": float(bathrooms),
"garage": garage,
"stories": int(stories),
},
"summary": _generate_summary(width, depth, stories, style, bedrooms, bathrooms),
}
def _extract_sqft(text):
m = re.search(r'(\d+[,.]?\d*)\s*(sq\s*ft|square\s*feet|sqft)', text)
if m:
return int(float(m.group(1).replace(",", "")))
m = re.search(r'(\d+[,.]?\d*)\s*x\s*(\d+[,.]?\d*)\s*(?:feet|ft|foot)', text)
if m:
w = float(m.group(1).replace(",", ""))
d = float(m.group(2).replace(",", ""))
return int(w * d)
return None
def _extract_dimensions(text, sqft):
m = re.search(r'(\d+)\s*(?:feet|ft|foot)\s*(?:x|by|and)?\s*(\d+)\s*(?:feet|ft|foot)', text)
if m:
return int(m.group(1)), int(m.group(2))
m = re.search(r'(\d+)\s*x\s*(\d+)', text)
if m:
return int(m.group(1)), int(m.group(2))
m = re.search(r'(\d+)\s*(?:feet|ft|foot)\s*(?:wide|width)?', text)
if m:
w = int(m.group(1))
if sqft:
d = max(1, sqft // w)
else:
d = int(w * 0.75)
return w, d
m = re.search(r'(\d+)\s*(?:by|wide|width)\s*(\d+)', text)
if m:
return int(m.group(1)), int(m.group(2))
if sqft:
w = int(sqft ** 0.5)
d = max(1, sqft // w)
return w, d
return 40, 30
def _extract_style(text):
for style, normalized in STYLES.items():
if style in text:
return normalized
if "2 story" in text or "two story" in text or "two-story" in text:
return "colonial"
return "modern"
def _extract_stories(text):
m = re.search(r'(\d+)\s*[-]?\s*(?:story|floor|level|storey)', text)
if m:
return min(int(m.group(1)), 3)
if "single story" in text or "ranch" in text or "rambler" in text:
return 1
return 1
def _extract_bedrooms(text):
m = re.search(r'(\d+)\s*(?:bedroom|bed\b)', text)
if m:
return int(m.group(1))
m = re.search(r'(\d+)\s*br\b', text)
if m:
return int(m.group(1))
return 3
def _extract_bathrooms(text):
m = re.search(r'(\d+)\s*(?:bathroom|bath\b)', text)
if m:
return int(m.group(1))
m = re.search(r'(\d+)\s*ba\b', text)
if m:
return int(m.group(1))
m = re.search(r'(\d+\.?\d*)\s*-?\s*bath', text)
if m:
return float(m.group(1))
return 2
def _has_garage(text):
if re.search(r'\bgarage\b', text):
return True
if re.search(r'\bcar\s*(?:garage|port)\b', text):
return True
return False
def _extract_extra_rooms(text):
extras = []
room_keywords = ["office", "den", "library", "gym", "theater", "workshop",
"laundry", "mudroom", "sunroom", "conservatory", "studio",
"loft", "basement", "attic", "porch", "deck", "patio",
"wine cellar", "pantry", "playroom", "nursery"]
for kw in room_keywords:
if kw in text:
extras.append(kw)
return extras
def _generate_rooms(width, depth, stories, bedrooms, bathrooms, garage, extras, style):
rooms = []
color = lambda name: ROOM_COLORS.get(name, "#e8e0d8")
w3 = width / 3.0
d2 = depth / 2.0
rooms.append({"name": "Living Room", "x": 0, "z": 0, "w": w3 * 1.5, "d": d2, "color": color("living"), "floor": 0})
rooms.append({"name": "Kitchen", "x": w3 * 1.5, "z": 0, "w": w3 * 0.8, "d": d2, "color": color("kitchen"), "floor": 0})
rooms.append({"name": "Dining", "x": w3 * 1.5 + w3 * 0.8, "z": 0, "w": w3 * 0.7, "d": d2, "color": color("dining"), "floor": 0})
bed_colors = ["#d0d8e8", "#c8d0e8", "#d8d0e0", "#d0d0e0", "#d8d8e8"]
bed_w = min(w3 * 0.7, 14)
bed_d = min(d2 * 0.6, 14)
for i in range(bedrooms):
bx = (i % 3) * w3
bz = d2 + (i // 3) * bed_d
if bx + bed_w > width:
bx = width - bed_w
name = "Master Bedroom" if i == 0 else f"Bedroom {i+1}"
rooms.append({"name": name, "x": bx, "z": bz, "w": bed_w, "d": bed_d, "color": bed_colors[i % len(bed_colors)], "floor": 0})
bath_w = 6
bath_d = 6
for i in range(int(bathrooms)):
bx = width - bath_w - (i * bath_w) % (width / 3)
bz = 0 if i % 2 == 0 else d2 - bath_d
if bx < 0:
bx = width - bath_w
rooms.append({"name": f"{'Master ' if i == 0 and bedrooms > 0 else ''}Bathroom" if i == 0 else f"Bathroom {i+1}",
"x": bx, "z": bz, "w": bath_w, "d": bath_d, "color": color("bathroom"), "floor": 0})
if garage:
gw = min(width * 0.35, 24)
gd = min(depth * 0.4, 24)
rooms.append({"name": "Garage", "x": 0, "z": depth - gd, "w": gw, "d": gd, "color": color("garage"), "floor": 0})
hall_w = 4
rooms.append({"name": "Hallway", "x": 0, "z": d2, "w": hall_w, "d": bed_d if bedrooms > 0 else d2 * 0.5, "color": color("hallway"), "floor": 0})
for extra in extras:
ex = width * 0.6
ez = depth * 0.3
ew = min(w3 * 0.6, 12)
ed = min(d2 * 0.5, 10)
if extra in ("deck", "patio", "porch"):
rooms.append({"name": extra.capitalize(), "x": width * 0.3, "z": -8, "w": width * 0.4, "d": 8, "color": color(extra), "floor": 0, "exterior": True})
else:
rooms.append({"name": extra.capitalize(), "x": ex, "z": ez, "w": ew, "d": ed, "color": color(extra), "floor": 0})
if stories > 1:
for room in rooms:
if room["floor"] == 0 and room["name"] not in ("Garage",):
upper = room.copy()
upper["name"] = f"Upper {room['name']}"
upper["floor"] = 1
upper["color"] = "#e0dcd8"
rooms.append(upper)
return rooms
def _generate_summary(width, depth, stories, style, bedrooms, bathrooms):
sqft = width * depth * stories
return f"A {style} {stories}-story home, {width}ft x {depth}ft — approximately {sqft} sqft. {bedrooms} bedrooms, {bathrooms} bathrooms."
if __name__ == "__main__":
tests = [
"2000 sq ft ranch house with 3 bedrooms and 2 baths",
"modern 2-story house 30x40 with 4 bedrooms 3 bathrooms and a 2 car garage",
"small cabin 800 sq ft with 1 bedroom",
"victorian 3500 sq ft 5 bedroom 3 bath with office and library",
"colonial with 4 bedrooms and 2.5 baths",
]
for t in tests:
r = parse_description(t)
print(f"\n{'='*60}")
print(f"Input: {t}")
print(f"Structure: {r['structure']}")
print(f"Rooms: {len(r['rooms'])}")
for room in r['rooms'][:5]:
print(f" {room['name']}: {room['w']:.0f}x{room['d']:.0f} @ ({room['x']:.0f},{room['z']:.0f}) floor={room.get('floor',0)}")
print(f"Summary: {r['summary']}")