nemocity / mind /mock_scripts.py
AndresCarreon's picture
NEMOCITY v0 — mock backend, gradio 6.16.0 (pre-SSR)
d72231c verified
Raw
History Blame Contribute Delete
12 kB
"""Deterministic scripted BUILD/FIX JSON for the MockBackend.
Each petition maps to a category by keyword; each category emits a complete
BUILD JSON string (parsed by mind/validate.py exactly like real backend
output), with names and blurbs varied by a crc32 seed of the petition — same
petition in, same permit out, so demos replay exactly. The category library
exercises every building kind.
fix_script reads the candidate ids and report numbers back out of the
rendered fix prompt (the "- F1: desc (predicted index 41)" lines from
mind/prompts.py — keep the two in lockstep) and picks the best predicted
index, so mock fixes cite real numbers too.
"""
from __future__ import annotations
import json
import random
import re
import zlib
NAME_MAX = 24
BLURB_MAX = 140
def _seed_for(petition: str) -> int:
return zlib.crc32(" ".join(petition.lower().split()).encode("utf-8")) & 0x7FFFFFFF
def _entry(kind: str, name: str, near=None, floors=None, hue=None) -> dict:
return {"kind": kind, "name": name[:NAME_MAX], "near": near, "floors": floors, "hue": hue}
def _plan(blurb: str, buildings: list[dict]) -> dict:
return {
"intent": "build",
"blurb": blurb[:BLURB_MAX],
"buildings": buildings[:3],
"decline_reason": None,
}
_STOP_WORDS = {
"a", "an", "the", "please", "build", "make", "made", "add", "want",
"wants", "need", "needs", "near", "for", "with", "of", "in", "on", "to",
"and", "my", "me", "us", "we", "i", "new", "some", "little", "big",
}
def _petition_name(petition: str, suffix: str = "House") -> str:
words = [w for w in re.findall(r"[A-Za-z]+", petition) if w.lower() not in _STOP_WORDS]
base = " ".join(w.capitalize() for w in words[:2])
name = f"{base} {suffix}".strip()
return (name[:NAME_MAX].rstrip() or f"Petition {suffix}")[:NAME_MAX]
_CAFES = ("Cafe Luna", "The Brass Kettle", "Marigold Coffee", "The Daily Grind", "Cafe Fig")
_HOUSES = ("Wren Cottage", "Maple End", "The Little Blue", "Juniper House", "Quince Cottage")
_APTS = ("Linden Court", "The Beacon Flats", "Harbor House", "The Gables", "Rookery Flats")
_TOWERS = ("Meridian Tower", "The Spindle", "Apex Tower", "Cobalt Point", "The Needle")
_PARKS = ("Dapple Green", "Whistle Park", "Petal Commons", "Old Elm Green")
_STADIUMS = ("The Civic Bowl", "Tin Cup Stadium", "The Roaring Yard")
_CHURCHES = ("The Quiet Spire", "St. Alder's", "Lantern Chapel")
_SCHOOLS = ("Alder Primary", "Hilltop School", "The Brightwork School")
_HOSPITALS = ("Riverside General", "St. Junia Hospital", "Bluebell General")
_FACTORIES = ("The Tin Works", "Cobalt Works", "The Bottling Hall")
_MARKETS = ("Penny Market", "The Mercantile", "Six Crows Market")
_BANKS = ("The Counting House", "First Acorn Bank", "The Strongbox")
_SHOPS = ("The Odd Shelf", "Tortoise & Finch", "The Blue Awning")
_NEARS = ("downtown", "the park", "Main St", "1st Ave")
def _district(petition: str, rng: random.Random) -> dict:
flats, cafe, shop = rng.choice(_APTS), rng.choice(_CAFES), rng.choice(_SHOPS)
buildings = [
_entry("apartments", flats, "downtown", rng.randint(4, 7), rng.choice((25, 35, 200))),
_entry("cafe", cafe, "downtown", 1, rng.choice((30, 40, 50))),
]
if rng.random() < 0.7:
buildings.append(_entry("shop", shop, "downtown", 1, rng.choice((10, 180, 320))))
blurb = rng.choice((
f"Zoning approved: a new block downtown — {flats} rising with {cafe} on the corner.",
f"A whole block takes shape: {flats}, {cafe}, and room for more.",
))
return _plan(blurb, buildings)
def _river(petition: str, rng: random.Random) -> dict:
park, cafe = rng.choice(_PARKS), rng.choice(("The Ferry Light", "Pier Nine Cafe", "The Eddy"))
blurb = rng.choice((
f"The waterfront gets its due: {park} on the bank, {cafe} watching the water.",
f"Permits issued by the river — {park}, and {cafe} for the crossing crowd.",
))
return _plan(blurb, [
_entry("park", park, "the river"),
_entry("cafe", cafe, "the river", 1, rng.choice((35, 45))),
])
def _cafe(petition: str, rng: random.Random) -> dict:
name = rng.choice(_CAFES)
near = rng.choice(_NEARS)
blurb = rng.choice((
f"{name} opens near {near} — pastries at dawn, lamplight at dusk.",
f"Permit granted: {name}, sidewalk tables facing the street.",
))
return _plan(blurb, [_entry("cafe", name, near, 1, rng.choice((30, 40, 50)))])
def _house(petition: str, rng: random.Random) -> dict:
name = rng.choice(_HOUSES)
blurb = rng.choice((
f"{name} gets its lot — a porch, a chimney, a light in the window.",
f"A home is granted: {name}, keys cut while the paint dries.",
))
return _plan(blurb, [_entry("house", name, rng.choice(_NEARS), rng.randint(1, 2), rng.choice((20, 35, 200, 350)))])
def _apartments(petition: str, rng: random.Random) -> dict:
name = rng.choice(_APTS)
blurb = rng.choice((
f"{name} approved — {rng.randint(4, 7)} floors of new neighbors.",
f"Housing first: {name} will fill with families by the weekend.",
))
return _plan(blurb, [_entry("apartments", name, rng.choice(_NEARS), rng.randint(4, 7), rng.choice((25, 200, 160)))])
def _tower(petition: str, rng: random.Random) -> dict:
name = rng.choice(_TOWERS)
blurb = rng.choice((
f"{name} cleared for the skyline — cranes by morning.",
f"Downtown grows up: {name}, {rng.randint(8, 16)} floors against the horizon.",
))
return _plan(blurb, [_entry("tower", name, "downtown", rng.randint(8, 16), rng.choice((210, 220, 35)))])
def _park(petition: str, rng: random.Random) -> dict:
name = rng.choice(_PARKS)
blurb = rng.choice((
f"Green space wins: {name}, benches and old trees included.",
f"{name} is set aside — the city keeps a place to breathe.",
))
return _plan(blurb, [_entry("park", name, rng.choice(_NEARS))])
def _stadium(petition: str, rng: random.Random) -> dict:
name = rng.choice(_STADIUMS)
blurb = rng.choice((
f"{name} approved — floodlights, roar, and a home team to be named.",
f"Game on: {name} takes the big lot.",
))
return _plan(blurb, [_entry("stadium", name, "downtown", 1, rng.choice((10, 210)))])
def _church(petition: str, rng: random.Random) -> dict:
name = rng.choice(_CHURCHES)
blurb = f"{name} is granted its steeple — bells on the hour."
return _plan(blurb, [_entry("church", name, rng.choice(_NEARS), 1, rng.choice((40, 350)))])
def _school(petition: str, rng: random.Random) -> dict:
name = rng.choice(_SCHOOLS)
blurb = rng.choice((
f"{name} chartered — chalk dust and a morning bell.",
f"The city invests in small citizens: {name} opens soon.",
))
return _plan(blurb, [_entry("school", name, rng.choice(_NEARS), rng.randint(1, 2), 200)])
def _hospital(petition: str, rng: random.Random) -> dict:
name = rng.choice(_HOSPITALS)
blurb = f"{name} approved — the city will be looked after."
return _plan(blurb, [_entry("hospital", name, rng.choice(_NEARS), rng.randint(3, 6), 200)])
def _bank(petition: str, rng: random.Random) -> dict:
name = rng.choice(_BANKS)
blurb = f"{name} chartered downtown — marble face, careful ledgers."
return _plan(blurb, [_entry("bank", name, "downtown", rng.randint(2, 4), 210)])
def _factory(petition: str, rng: random.Random) -> dict:
name = rng.choice(_FACTORIES)
blurb = rng.choice((
f"{name} zoned for the edge of town — jobs by the shift.",
f"Industry arrives: {name}, smokestack and all.",
))
return _plan(blurb, [_entry("factory", name, "the river", rng.randint(1, 2), 30)])
def _market(petition: str, rng: random.Random) -> dict:
name = rng.choice(_MARKETS)
blurb = rng.choice((
f"{name} licensed — stalls up by Saturday.",
f"Permit granted: {name}, the street will smell of bread.",
))
return _plan(blurb, [_entry("market", name, rng.choice(_NEARS), 1, rng.choice((35, 15)))])
def _default(petition: str, rng: random.Random) -> dict:
name = _petition_name(petition)
blurb = f"City hall reads the petition twice, nods, and grants {name}."
return _plan(blurb, [_entry("house", name, rng.choice(_NEARS), rng.randint(1, 2), rng.choice((20, 200, 320)))])
# Order matters: most specific first; "house" is the safety net before default.
_CATEGORIES: tuple[tuple[re.Pattern[str], object], ...] = (
(re.compile(r"\b(districts?|downtown|neighbou?rhoods?|blocks?|quarters?|villages?|towns?|suburbs?|expand|grow)\b", re.I), _district),
(re.compile(r"\b(rivers?|riverside|waterfront|bridges?|docks?|harbou?rs?|piers?|ferry)\b", re.I), _river),
(re.compile(r"\b(caf[eé]s?|coffee|espresso|diners?|restaurants?|baker(?:y|ies)|bistros?|tea|ramen|pizz\w*|brunch|noodles?)\b", re.I), _cafe),
(re.compile(r"\b(apartments?|condos?|flats?|hotels?|housing|lofts?)\b", re.I), _apartments),
(re.compile(r"\b(towers?|offices?|skyscrapers?|high-?rises?|headquarters|startups?)\b", re.I), _tower),
(re.compile(r"\b(stadiums?|arenas?|sports?|football|soccer|baseball|matches?)\b", re.I), _stadium),
(re.compile(r"\b(church(?:es)?|temples?|chapels?|mosques?|cathedrals?|shrines?)\b", re.I), _church),
(re.compile(r"\b(schools?|librar(?:y|ies)|universit(?:y|ies)|colleges?|academ(?:y|ies)|kids|children)\b", re.I), _school),
(re.compile(r"\b(hospitals?|clinics?|doctors?|medical|health)\b", re.I), _hospital),
(re.compile(r"\b(banks?|finance|credit|vaults?)\b", re.I), _bank),
(re.compile(r"\b(factor(?:y|ies)|industr\w*|plants?|warehouses?|mills?|workshops?)\b", re.I), _factory),
(re.compile(r"\b(markets?|malls?|grocer\w*|supermarkets?|shops?|stores?|boutiques?|bazaars?|pharmac\w*)\b", re.I), _market),
(re.compile(r"\b(parks?|gardens?|greens?|trees?|playgrounds?|plazas?|squares?|fountains?)\b", re.I), _park),
(re.compile(r"\b(houses?|homes?|cottages?|bungalows?|cabins?|townhouses?)\b", re.I), _house),
)
def build_script(petition: str) -> str:
"""The full BUILD JSON string for a petition. Deterministic: same
petition (modulo case/whitespace) always yields the same permit."""
petition = (petition or "").strip() or "a small building"
rng = random.Random(_seed_for(petition))
for pattern, builder in _CATEGORIES:
if pattern.search(petition):
return json.dumps(builder(petition, rng), ensure_ascii=False) # type: ignore[operator]
return json.dumps(_default(petition, rng), ensure_ascii=False)
_CANDIDATE_LINE_RE = re.compile(r"-\s*(F\d+):\s*([^\n(]*)\(predicted index (\d+)\)")
_TRAFFIC_INDEX_RE = re.compile(r'"traffic_index"\s*:\s*(\d+)')
_WORST_RE = re.compile(r'"worst"\s*:\s*"([^"]{1,48})"')
def fix_script(prompt: str) -> str:
"""The FIX JSON string, built from the candidates/numbers rendered into
the fix prompt by mind/prompts.py. Picks the lowest predicted index."""
text = str(prompt or "")
m = _WORST_RE.search(text)
worst = m.group(1) if m else "the worst crossing"
ti = _TRAFFIC_INDEX_RE.search(text)
pairs = _CANDIDATE_LINE_RE.findall(text)
if pairs:
cid, desc, pred = min(pairs, key=lambda p: int(p[2]))
desc = " ".join(desc.split()).rstrip(" ,") or "the engine's bypass"
if ti:
diagnosis = (
f"Index {ti.group(1)} with {worst} over capacity; "
f"{cid} ({desc}) brings the predicted index to {pred}."
)
else:
diagnosis = f"{worst} is over capacity; {cid} ({desc}) brings the predicted index to {pred}."
else:
m = re.search(r"\b(F\d+)\b", text)
cid = m.group(1) if m else "F1"
diagnosis = f"{worst} runs over capacity; applying {cid}."
blurb = f"CITY ENGINEER: relief ordered for {worst}."
return json.dumps(
{"diagnosis": diagnosis[:160], "choice": cid, "blurb": blurb[:120]},
ensure_ascii=False,
)