interaction-intelligence / product_language.py
mcqueenmater's picture
Deploy Fusion Lab: mobile-friendly UI + bug fixes
2b21f2d verified
Raw History Blame Contribute Delete
2.78 kB
"""Plain-language vocabulary for the Executive Dynamics workspace/landing/company
tabs — the "analyst workspace" side of the app. Everything imports from here
instead of hardcoding strings, so "no ML jargon in the product surface" is enforced
structurally (one file to review) rather than by convention.
The Research side (Benchmarks/Methodology tabs) keeps its existing technical
language and is NOT governed by this module.
"""
from theme import SIG_NEGATIVE, SIG_NEUTRAL, SIG_POSITIVE
DIMENSION_LABELS = {
"confidence": "Confidence",
"stress": "Stress",
"specificity": "Specificity",
"alignment": "Alignment",
"alignment_drift": "Alignment",
}
# Backend risk_tier values are lowercase ("low"|"medium"|"high"); this module is
# solely responsible for mapping those onto the display strings/colors below.
RISK_TIER_DISPLAY = {"low": "Low", "medium": "Elevated", "high": "High"}
RISK_TIER_COLORS = {"low": SIG_POSITIVE, "medium": SIG_NEUTRAL, "high": SIG_NEGATIVE}
def risk_tier_label(risk_tier: str | None) -> str:
return RISK_TIER_DISPLAY.get(risk_tier, "Unknown")
def risk_tier_color(risk_tier: str | None) -> str:
return RISK_TIER_COLORS.get(risk_tier, SIG_NEUTRAL)
def largest_friction_label(dimension: str | None) -> str:
return DIMENSION_LABELS.get(dimension, "—")
def company_name(ticker: str, ticker_names: dict[str, str]) -> str:
"""Full company name for a ticker, falling back to the raw ticker if unmapped."""
return ticker_names.get(ticker, ticker)
def company_dropdown_choices(tickers: list[str], ticker_names: dict[str, str]) -> list[tuple[str, str]]:
"""(label, value) pairs for gr.Dropdown — label is 'Company Name (TICKER)', value stays
the raw ticker so filtering/lookup logic downstream is unchanged. Sorted by company name."""
pairs = [(f"{company_name(t, ticker_names)} ({t})", t) for t in tickers]
return sorted(pairs, key=lambda p: p[0])
def risk_driver_bullets(turn: dict) -> list[str]:
"""Plain-language driver bullets for the Evidence panel.
Prefers the exported `risk_drivers` field (already human-readable strings from
src/evaluation/behavioral_signals.py). Falls back to templating from the turn's
own scores if that field is missing/empty, so the Evidence panel still shows
something sensible before/without a fresh data export.
"""
drivers = turn.get("risk_drivers")
if drivers:
return list(drivers)
fallback = []
if turn.get("stress", 0) > 0.6:
fallback.append("elevated vocal/language stress")
if (turn.get("alignment_drift") or 0) > 0.6:
fallback.append("tone diverged from prepared remarks")
if turn.get("specificity", 1.0) < 0.3:
fallback.append("low specificity")
return fallback