system-prompts-and-models-o.../dealix/auto_client_acquisition/vertical_os/base.py
2026-05-01 14:03:52 +03:00

117 lines
3.8 KiB
Python

"""
Vertical OS Base — schema for productized sector modules.
Each vertical bundles: ICP, signals, objections, KPIs, message library,
proposal template, QBR template, ROI model, compliance notes.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
# ── KPI definition ────────────────────────────────────────────────
@dataclass(frozen=True)
class KPI:
metric_id: str
name_ar: str
description_ar: str
unit: str
higher_is_better: bool = True
target_p50: float | None = None # sector benchmark
target_p90: float | None = None
# ── Message template ─────────────────────────────────────────────
@dataclass(frozen=True)
class MessageTemplate:
template_id: str
channel: str # whatsapp / email / linkedin
purpose: str # cold / followup_3d / followup_7d / objection_response
subject_ar: str | None
body_ar: str
variables: tuple[str, ...] = () # {company_name}, {city}, {pain_point}, etc.
expected_reply_rate: float = 0.0
# ── Full vertical bundle ─────────────────────────────────────────
@dataclass(frozen=True)
class VerticalOS:
vertical_id: str
sector_ar: str
sector_en: str
# ICP
icp_company_size: tuple[str, ...]
icp_cities: tuple[str, ...]
icp_keywords: tuple[str, ...]
# Pain & objections
pain_points_ar: tuple[str, ...]
top_objection_ids: tuple[str, ...] # ids from revenue_graph.objection_library
# Signals to watch (from market_intelligence.signal_detectors taxonomy)
priority_signals: tuple[str, ...]
# KPIs surfaced on the per-vertical dashboard
dashboard_kpis: tuple[KPI, ...]
# Message library
message_templates: tuple[MessageTemplate, ...]
# Proposal & QBR templates
proposal_template_ar: str
qbr_section_template_ar: str
# ROI model — what to plug into the simulator
avg_deal_value_sar: int
avg_cycle_days: int
benchmark_reply_rate: float
benchmark_meeting_rate: float
benchmark_win_rate: float
# Compliance notes specific to the sector
compliance_notes_ar: tuple[str, ...] = ()
# Recommended channel mix (must sum ~ 1.0)
recommended_channel_mix: dict[str, float] = field(default_factory=dict)
# ── Registry helpers ─────────────────────────────────────────────
_REGISTRY: dict[str, VerticalOS] = {}
def _register(v: VerticalOS) -> None:
_REGISTRY[v.vertical_id] = v
def get_vertical(vertical_id: str) -> VerticalOS | None:
return _REGISTRY.get(vertical_id)
def list_vertical_summaries() -> list[dict[str, Any]]:
"""Compact summary for the verticals overview tile."""
return [
{
"vertical_id": v.vertical_id,
"sector_ar": v.sector_ar,
"sector_en": v.sector_en,
"avg_deal_value_sar": v.avg_deal_value_sar,
"avg_cycle_days": v.avg_cycle_days,
"n_pain_points": len(v.pain_points_ar),
"n_message_templates": len(v.message_templates),
"n_kpis": len(v.dashboard_kpis),
"primary_channel": (
max(v.recommended_channel_mix.items(), key=lambda x: x[1])[0]
if v.recommended_channel_mix else None
),
"benchmark_reply_rate": v.benchmark_reply_rate,
}
for v in _REGISTRY.values()
]
# Will be populated by clinics.py / real_estate.py / logistics.py imports
ALL_VERTICALS: dict[str, VerticalOS] = _REGISTRY