coreprinciple's picture
v2 with model changed and using gradio server func
10cf611
Raw
History Blame Contribute Delete
3.03 kB
"""Bridge the LLM/keyword "brief keys" to the taxonomy's category affinity.
Call 1 (vibe→weights) and the keyword fallback both speak a small, human set of
keys — ``cafe, park, bookshop, museum, bakery, restaurant, bar, viewpoint,
market, historic`` (category keys) plus ``quiet, green, busy`` (modifiers). The
routing engine, however, scores over the 17-category :mod:`taxonomy` vocabulary
via the ``Weights.category_affinity`` dict. This module is the single, dependency
-light translator between the two, so both producers stay consistent.
"""
from __future__ import annotations
from discoverroute import config
from discoverroute.data import taxonomy
# brief category-key -> taxonomy categories it directly expresses interest in.
CATEGORY_KEYS: dict[str, list[str]] = {
"cafe": ["cafe"],
"park": ["park_garden"],
"bookshop": ["bookshop", "library"],
"museum": ["museum_gallery", "theatre_cinema", "artwork"],
"bakery": ["bakery_food_shop"],
"restaurant": ["restaurant"],
"bar": ["bar_pub"],
"viewpoint": ["viewpoint", "attraction"],
"market": ["market", "specialty_shop"],
"historic": ["monument_historic", "place_of_worship"],
}
# Modifier keys shape every category via its intrinsic priors (not 1:1 to a
# category): green→greenness, quiet→quietness, busy→liveliness (1−quietness).
MODIFIER_KEYS = ("green", "quiet", "busy")
# Inverted: taxonomy category -> the brief category-keys that target it.
_KEYS_FOR_CATEGORY: dict[str, list[str]] = {}
for _key, _cats in CATEGORY_KEYS.items():
for _c in _cats:
_KEYS_FOR_CATEGORY.setdefault(_c, []).append(_key)
# All keys a producer is expected to emit (category keys + modifiers).
BRIEF_KEYS: tuple[str, ...] = tuple(CATEGORY_KEYS) + MODIFIER_KEYS
def brief_scores_to_affinity(scores: dict[str, float]) -> dict[str, float]:
"""Map brief-key scores → a floored affinity over every taxonomy category.
Each category takes the strongest signal among: its direct category-key
score, and the modifier contributions (green·greenness, quiet·quietness,
busy·liveliness). The top category is scaled to 1.0 and the rest floored to
``AFFINITY_FLOOR`` — the same shape :func:`embed.vibe_to_affinity` returns,
so the routing engine cannot tell which producer ran.
"""
green = float(scores.get("green", 0.0) or 0.0)
quiet = float(scores.get("quiet", 0.0) or 0.0)
busy = float(scores.get("busy", 0.0) or 0.0)
raw: dict[str, float] = {}
for cat in taxonomy.CATEGORIES:
contribs = [0.0]
for key in _KEYS_FOR_CATEGORY.get(cat, []):
contribs.append(float(scores.get(key, 0.0) or 0.0))
contribs.append(green * taxonomy.greenness(cat))
contribs.append(quiet * taxonomy.quietness(cat))
contribs.append(busy * (1.0 - taxonomy.quietness(cat)))
raw[cat] = max(contribs)
hi = max(raw.values()) or 1.0
floor = config.AFFINITY_FLOOR
return {c: floor + (1.0 - floor) * (v / hi) for c, v in raw.items()}