Projeto do Agent Contas ORACLE

This commit is contained in:
2026-08-19 09:35:50 -03:00
commit 950a2bcd33
1366 changed files with 177217 additions and 0 deletions

View File

@@ -0,0 +1,169 @@
from __future__ import annotations
import json
import logging
import os
from dataclasses import dataclass
from functools import lru_cache
from typing import Any
logger = logging.getLogger(__name__)
_TRIPLETS_ENV_VAR = "TIM_PROTOCOL_TRIPLETS_JSON"
_STAGES = ("open", "close")
_FIELDS = ("reason1", "reason2", "reason3")
@dataclass(frozen=True, slots=True)
class ProtocolTriplet:
reason1: str
reason2: str
reason3: str
_DEFAULT_CATALOG: dict[str, dict[str, ProtocolTriplet]] = {
"atendimento_geral": {
"open": ProtocolTriplet("Informação", "Conta", "Valor"),
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
},
"cancelamento_vas_avulso": {
"open": ProtocolTriplet(
"Solicitação", "Serviço VAS", "Ativação/Desativação"
),
"close": ProtocolTriplet(
"Solicitação", "Serviço VAS", "Ativação/Desativação"
),
},
"contestacao": {
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
"close": ProtocolTriplet("Reclamação", "Conta", "Valor"),
},
"vas_estrategico": {
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
},
"invoice_explanation_aceite_fechado": {
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
},
"finalizacao_informacional_fechada": {
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
"close": ProtocolTriplet("Informação", "Conta", "Esclarecimento"),
},
"valor_divergente": {
"open": ProtocolTriplet("Informação", "Conta", "Valor"),
"close": ProtocolTriplet("Informação", "Conta", "Valor"),
},
"pro_rata": {
"open": ProtocolTriplet("Informação", "Conta", "Valor"),
"close": ProtocolTriplet("Informação", "Conta", "Valor"),
},
"pro_rata_mensalidade": {
"open": ProtocolTriplet("Informação", "Conta", "Mensalidade"),
"close": ProtocolTriplet("Informação", "Conta", "Mensalidade"),
},
"pro_rata_reclamacao": {
"open": ProtocolTriplet("Reclamação", "Conta", "Valor"),
"close": ProtocolTriplet("Reclamação", "Conta", "Valor"),
},
"termino_desconto": {
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
},
"conta_certa_manual": {
"open": ProtocolTriplet(
"Processo Interno", "Conta", "Conta Certa - Venc {dia_vencimento}"
),
"close": ProtocolTriplet(
"Processo Interno", "Conta", "Conta Certa - Venc {dia_vencimento}"
),
},
}
class _SafeFormatDict(dict[str, Any]):
def __missing__(self, key: str) -> str:
return ""
def _normalize_text(value: Any) -> str:
return str(value or "").strip()
def _override_triplet(base: ProtocolTriplet, override: dict[str, Any]) -> ProtocolTriplet:
return ProtocolTriplet(
reason1=_normalize_text(override.get("reason1")) or base.reason1,
reason2=_normalize_text(override.get("reason2")) or base.reason2,
reason3=_normalize_text(override.get("reason3")) or base.reason3,
)
@lru_cache(maxsize=1)
def _catalog_with_overrides() -> dict[str, dict[str, ProtocolTriplet]]:
catalog = {
scenario: dict(stages)
for scenario, stages in _DEFAULT_CATALOG.items()
}
raw = os.getenv(_TRIPLETS_ENV_VAR, "").strip()
if not raw:
return catalog
try:
payload = json.loads(raw)
except json.JSONDecodeError:
logger.warning("triplets.override.invalid_json env=%s", _TRIPLETS_ENV_VAR)
return catalog
if not isinstance(payload, dict):
logger.warning("triplets.override.invalid_root env=%s", _TRIPLETS_ENV_VAR)
return catalog
for scenario, stage_payload in payload.items():
scenario_key = _normalize_text(scenario).lower()
if not scenario_key or not isinstance(stage_payload, dict):
continue
current = catalog.get(scenario_key, {})
for stage in _STAGES:
override = stage_payload.get(stage)
if not isinstance(override, dict):
continue
if stage in current:
current[stage] = _override_triplet(current[stage], override)
continue
if any(_normalize_text(override.get(field)) for field in _FIELDS):
current[stage] = ProtocolTriplet(
reason1=_normalize_text(override.get("reason1")),
reason2=_normalize_text(override.get("reason2")),
reason3=_normalize_text(override.get("reason3")),
)
if current:
catalog[scenario_key] = current
return catalog
def resolve_protocol_triplet(
scenario: str,
*,
stage: str,
context: dict[str, Any] | None = None,
fallback_scenario: str = "atendimento_geral",
) -> ProtocolTriplet:
stage_key = _normalize_text(stage).lower()
if stage_key not in _STAGES:
stage_key = "open"
scenario_key = _normalize_text(scenario).lower() or fallback_scenario
fallback_key = _normalize_text(fallback_scenario).lower() or "atendimento_geral"
catalog = _catalog_with_overrides()
stages = catalog.get(scenario_key) or catalog.get(fallback_key) or {}
raw_triplet = stages.get(stage_key)
if raw_triplet is None:
fallback_stages = catalog.get("atendimento_geral", {})
raw_triplet = fallback_stages.get(stage_key) or ProtocolTriplet("", "", "")
fmt_values = _SafeFormatDict(
{key: _normalize_text(value) for key, value in (context or {}).items()}
)
return ProtocolTriplet(
reason1=raw_triplet.reason1.format_map(fmt_values).strip(),
reason2=raw_triplet.reason2.format_map(fmt_values).strip(),
reason3=raw_triplet.reason3.format_map(fmt_values).strip(),
)