HomePilot Deploy Bot
chore(hf): sync HomePilot to HF Space
921d377
Raw
History Blame Contribute Delete
2.95 kB
"""
Audience resolution for the interactive planner.
An ``Audience`` is the viewer profile the planner targets. Today
it's resolved from free-text hints in the prompt plus optional
explicit fields (``role``, ``level``, ``language``). Tomorrow the
same signature will accept CRM / profile lookups.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, Optional
@dataclass(frozen=True)
class Audience:
"""Resolved audience profile.
``level`` is coarse: 'beginner' / 'intermediate' / 'advanced' —
the downstream planner maps that to CEFR tiers or XP ranges as
appropriate.
"""
role: str = "viewer" # viewer | learner | customer | trainee | lead | unknown
level: str = "beginner" # beginner | intermediate | advanced
language: str = "en" # BCP-47
locale_hint: str = "" # e.g. 'italy', 'us-west'
interests: list = field(default_factory=list)
raw: Dict[str, Any] = field(default_factory=dict)
# Ordered most-specific first so 'advanced' wins over 'first time'
# in prompts like "advanced user trying this for the first time".
_LEVEL_KEYWORDS = {
"advanced": ("advanced", "expert", "pro", "fluent", "senior"),
"intermediate": ("some experience", "intermediate", "mid", "practicing"),
"beginner": ("new", "beginner", "intro", "novice", "first time", "fresh"),
}
_ROLE_KEYWORDS = {
"learner": ("student", "learner", "studying", "class", "school"),
"customer": ("customer", "buyer", "shopper", "prospect"),
"trainee": ("employee", "onboarding", "new hire", "staff"),
"lead": ("lead", "sales", "demo", "prospect"),
}
def _scan_level(text: str) -> Optional[str]:
low = text.lower()
for lvl, kws in _LEVEL_KEYWORDS.items():
for kw in kws:
if kw in low:
return lvl
return None
def _scan_role(text: str) -> Optional[str]:
low = text.lower()
for role, kws in _ROLE_KEYWORDS.items():
for kw in kws:
if kw in low:
return role
return None
def resolve_audience(
prompt: str = "",
*,
explicit: Optional[Dict[str, Any]] = None,
default_language: str = "en",
) -> Audience:
"""Best-effort audience resolution.
Precedence: ``explicit`` fields beat prompt-scanned hints beat
built-in defaults. Returns a frozen Audience so callers can
safely share instances across threads.
"""
ex = dict(explicit or {})
role = ex.get("role") or _scan_role(prompt) or "viewer"
level = ex.get("level") or _scan_level(prompt) or "beginner"
language = ex.get("language") or default_language
locale_hint = ex.get("locale_hint") or ""
interests = list(ex.get("interests") or [])
return Audience(
role=str(role),
level=str(level),
language=str(language),
locale_hint=str(locale_hint),
interests=interests,
raw=ex,
)