Spaces:
Sleeping
Sleeping
Download src/lib/scoring.ts from build-small-hackathon/6ixPulse: direct link, hf CLI and curl.
- Browser
- Download file 9.55 kB
-
https://huggingface.co/spaces/build-small-hackathon/6ixPulse/resolve/refs%2Fpr%2F2/src/lib/scoring.ts
- Command line
-
hf download hf://spaces/build-small-hackathon/6ixPulse@refs/pr/2/src/lib/scoring.ts
-
curl -L -o scoring.ts https://huggingface.co/spaces/build-small-hackathon/6ixPulse/resolve/refs%2Fpr%2F2/src/lib/scoring.ts
9.55 kB
| import { | |
| type AgentId, | |
| type DimensionKey, | |
| type LayerKey, | |
| type Neighborhood, | |
| neighborhoods, | |
| } from "../data/neighborhoods"; | |
| export interface ParsedPrompt { | |
| weights: Record<DimensionKey, number>; | |
| budget: number; | |
| cap: number; | |
| } | |
| export interface RankedNeighborhood extends Neighborhood { | |
| dims: Record<DimensionKey, number>; | |
| overall: number; | |
| rank: number; | |
| } | |
| export interface CityAgent { | |
| id: AgentId; | |
| name: string; | |
| color: string; | |
| tag: string; | |
| } | |
| export interface AgentState extends CityAgent { | |
| status: "queued" | "scanning" | "scoring" | "done"; | |
| lines: string[]; | |
| score: number | null; | |
| finding?: string; | |
| } | |
| const palette = { | |
| ink: "#243a5c", | |
| deep: "#304b78", | |
| strong: "#46648d", | |
| mid: "#5f7faa", | |
| soft: "#7f99ba", | |
| mist: "#9fb5ce", | |
| }; | |
| export const defaultPrompt = | |
| "I make $70k, work near Union, want under 45 min commute, safe area, near cafes, max rent $2,200."; | |
| export const cityAgents: CityAgent[] = [ | |
| { id: "affordability", name: "Affordability", color: palette.mid, tag: "Budget" }, | |
| { id: "commute", name: "Commute", color: palette.strong, tag: "Routes" }, | |
| { id: "safety", name: "Safety Signals", color: palette.deep, tag: "Signals" }, | |
| { id: "lifestyle", name: "Lifestyle", color: palette.soft, tag: "Amenities" }, | |
| { id: "growth", name: "Future Growth", color: palette.mist, tag: "Momentum" }, | |
| { id: "recommendation", name: "Recommendation", color: palette.ink, tag: "Consensus" }, | |
| ]; | |
| export function initialAgentStates(top: RankedNeighborhood): AgentState[] { | |
| return cityAgents.map((agent) => ({ | |
| ...agent, | |
| status: "done", | |
| lines: [], | |
| score: agent.id === "recommendation" ? top.overall : top.dims[agentDimension(agent.id)], | |
| })); | |
| } | |
| export function queuedAgentStates(): AgentState[] { | |
| return cityAgents.map((agent) => ({ | |
| ...agent, | |
| status: "queued", | |
| lines: [], | |
| score: null, | |
| })); | |
| } | |
| export function parsePrompt(prompt: string): ParsedPrompt { | |
| const source = prompt.toLowerCase(); | |
| const weights: Record<DimensionKey, number> = { | |
| affordability: 1, | |
| safety: 1, | |
| commute: 1, | |
| transit: 1, | |
| amenities: 1, | |
| lifestyle: 1, | |
| growth: 1, | |
| }; | |
| if (/safe|safety|secur|crime/.test(source)) weights.safety += 1.5; | |
| if (/afford|cheap|budget|max rent|under|\brent\b|\$\s?\d/.test(source)) { | |
| weights.affordability += 1.4; | |
| } | |
| if (/union|downtown|commut|\bmin\b|transit|ttc|subway|go train|\bgo\b/.test(source)) { | |
| weights.commute += 1.2; | |
| weights.transit += 0.6; | |
| } | |
| if (/caf|coffee|park|night|grocer|restaurant|amenit|walk|lifestyle|\bbar\b|food/.test(source)) { | |
| weights.lifestyle += 1; | |
| weights.amenities += 0.9; | |
| } | |
| if (/growth|invest|future|appreciat|up.?and.?coming|value|momentum|emerging/.test(source)) { | |
| weights.growth += 1.2; | |
| } | |
| let budget: number | null = null; | |
| const moneyMatches = source.match(/\$\s?([\d,]{3,6})/g); | |
| if (moneyMatches) { | |
| const values = moneyMatches | |
| .map((match) => Number.parseInt(match.replace(/[^\d]/g, ""), 10)) | |
| .filter((value) => value >= 1100 && value <= 6000); | |
| if (values.length) budget = Math.max(...values); | |
| } | |
| const commuteMatch = source.match(/(\d{2,3})\s*min/); | |
| return { | |
| weights, | |
| budget: budget ?? 2200, | |
| cap: commuteMatch ? Number.parseInt(commuteMatch[1], 10) : 45, | |
| }; | |
| } | |
| export function rankNeighborhoods( | |
| parsed: ParsedPrompt, | |
| rows: Neighborhood[] = neighborhoods, | |
| ): RankedNeighborhood[] { | |
| const weightSum = Object.values(parsed.weights).reduce((sum, value) => sum + value, 0); | |
| const ranked = rows.map((neighborhood) => { | |
| const dims = neighborhood.scores; | |
| let base = 0; | |
| for (const dimension of Object.keys(parsed.weights) as DimensionKey[]) { | |
| base += dims[dimension] * parsed.weights[dimension]; | |
| } | |
| base /= weightSum; | |
| let adjustment = 0; | |
| if (neighborhood.rentHi <= parsed.budget) adjustment += 4; | |
| else if (neighborhood.rentLo > parsed.budget) adjustment -= 11; | |
| else adjustment -= 2; | |
| const commuteMidpoint = (neighborhood.comLo + neighborhood.comHi) / 2; | |
| if (commuteMidpoint > parsed.cap) adjustment -= (commuteMidpoint - parsed.cap) * 0.6; | |
| return { | |
| ...neighborhood, | |
| dims, | |
| overall: clamp(Math.round(base + adjustment), 34, 99), | |
| rank: 0, | |
| }; | |
| }); | |
| ranked.sort((a, b) => b.overall - a.overall || b.scores.affordability - a.scores.affordability); | |
| return ranked.map((row, index) => ({ ...row, rank: index + 1 })); | |
| } | |
| export function agentDimension(id: AgentId): DimensionKey { | |
| if (id === "recommendation") return "growth"; | |
| if (id === "affordability") return "affordability"; | |
| if (id === "commute") return "commute"; | |
| if (id === "safety") return "safety"; | |
| if (id === "lifestyle") return "lifestyle"; | |
| return "growth"; | |
| } | |
| export function layerScore(neighborhood: RankedNeighborhood, layer: LayerKey): number { | |
| if (layer === "overall") return neighborhood.overall; | |
| if (layer === "rent") return neighborhood.dims.affordability; | |
| return neighborhood.dims[layer]; | |
| } | |
| export function consensus(overall: number) { | |
| if (overall >= 88) return { label: "Strong fit", color: palette.ink }; | |
| if (overall >= 80) return { label: "Solid fit", color: palette.deep }; | |
| if (overall >= 72) return { label: "Fair fit", color: palette.strong }; | |
| return { label: "Limited fit", color: palette.soft }; | |
| } | |
| export function tagFor(neighborhood: RankedNeighborhood) { | |
| const scores = Object.values(neighborhood.dims); | |
| const spread = Math.max(...scores) - Math.min(...scores); | |
| if ( | |
| neighborhood.dims.growth >= 84 && | |
| neighborhood.dims.growth >= neighborhood.dims.affordability | |
| ) { | |
| return { label: "Up and coming", color: palette.strong }; | |
| } | |
| if (neighborhood.dims.affordability >= 84) { | |
| return { | |
| label: neighborhood.overall >= 82 ? "Great value" : "Good value", | |
| color: palette.mid, | |
| }; | |
| } | |
| if (spread <= 16) { | |
| return { | |
| label: neighborhood.overall >= 82 ? "Great balance" : "Balanced", | |
| color: palette.deep, | |
| }; | |
| } | |
| if (neighborhood.dims.lifestyle >= 86) return { label: "Vibrant", color: palette.soft }; | |
| if (neighborhood.dims.commute >= 86) return { label: "Well connected", color: palette.strong }; | |
| return { label: "Solid pick", color: palette.ink }; | |
| } | |
| export function formatRentRange(neighborhood: Neighborhood): string { | |
| return `$${neighborhood.rentLo.toLocaleString()}-${neighborhood.rentHi.toLocaleString()}`; | |
| } | |
| export function getAgentThinking(id: AgentId, parsed: ParsedPrompt): string[] { | |
| const budget = parsed.budget.toLocaleString(); | |
| const cap = parsed.cap; | |
| const lines: Record<AgentId, string[]> = { | |
| affordability: [ | |
| "Scanning one-bedroom rent across 14 areas", | |
| `Comparing medians to your $${budget} cap`, | |
| "Scoring budget fit and flagging overpriced zones", | |
| ], | |
| commute: [ | |
| "Routing every area to Union Station", | |
| `Weighing GO, subway and streetcar vs ${cap} min`, | |
| "Scoring commute burden and transfers", | |
| ], | |
| safety: [ | |
| "Aggregating reported incident density", | |
| "Normalising by population and time of day", | |
| "Setting relative safety signals with data limits", | |
| ], | |
| lifestyle: [ | |
| "Mapping cafes, parks, groceries and nightlife", | |
| "Gauging walkability and local character", | |
| "Scoring lifestyle fit", | |
| ], | |
| growth: [ | |
| "Reading rent trajectories and permits", | |
| "Tracking transit expansion and development", | |
| "Projecting 12-month momentum", | |
| ], | |
| recommendation: [ | |
| "Gathering every agent finding", | |
| "Weighting by your stated priorities", | |
| "Forming consensus and ranking neighborhoods", | |
| ], | |
| }; | |
| return lines[id]; | |
| } | |
| export function getAgentFinding(id: AgentId, neighborhood: RankedNeighborhood, parsed: ParsedPrompt) { | |
| const tier = (score: number) => { | |
| if (score >= 85) return "excellent"; | |
| if (score >= 78) return "strong"; | |
| if (score >= 70) return "fair"; | |
| return "limited"; | |
| }; | |
| const commuteMidpoint = Math.round((neighborhood.comLo + neighborhood.comHi) / 2); | |
| if (id === "affordability") { | |
| const relation = | |
| neighborhood.rentHi <= parsed.budget | |
| ? "fits under" | |
| : neighborhood.rentLo > parsed.budget | |
| ? "runs above" | |
| : "brushes"; | |
| return `One-bed rent ${formatRentRange(neighborhood)} ${relation} your $${parsed.budget.toLocaleString()} cap. Budget fit is ${tier(neighborhood.dims.affordability)}.`; | |
| } | |
| if (id === "commute") { | |
| return `About ${commuteMidpoint} min to Union via ${neighborhood.comMode}; ${ | |
| commuteMidpoint <= parsed.cap ? "under" : "around" | |
| } your ${parsed.cap}-min target.`; | |
| } | |
| if (id === "safety") { | |
| return `Relative safety signals read ${tier(neighborhood.dims.safety)} here from reported incident density. Confidence is limited by public data quality.`; | |
| } | |
| if (id === "lifestyle") { | |
| return `${neighborhood.lifeHi}. Cafe, park and grocery density is ${tier(neighborhood.dims.amenities)}.`; | |
| } | |
| if (id === "growth") { | |
| return `${neighborhood.growthNote}. Rent is projected ${ | |
| neighborhood.trend > 0 ? "+" : "" | |
| }${neighborhood.trend}% over the next 12 months.`; | |
| } | |
| return `Agents converge on ${neighborhood.name}: ${consensus(neighborhood.overall).label}. ${neighborhood.short}`; | |
| } | |
| export function colorForScore(score: number): string { | |
| const t = clamp((score - 36) / 63, 0, 1); | |
| const lightness = 57 - t * 26; | |
| return `hsl(214 42% ${lightness.toFixed(0)}%)`; | |
| } | |
| export function clamp(value: number, min: number, max: number): number { | |
| return Math.max(min, Math.min(max, value)); | |
| } | |