110 lines
3.8 KiB
Python
110 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from .shared import *
|
|
|
|
from .charter_seed_utils import _safe_threshold
|
|
from .signal_core import _as_dict, _signal_source_context
|
|
from .signal_filters import _replace_signal_sender_in_content, _signal_proposer_name
|
|
|
|
def _extract_feishu_routing_config(integration: Optional[Integration]) -> dict[str, Any]:
|
|
config: dict[str, Any] = {}
|
|
if integration is not None:
|
|
if isinstance(integration.config, dict):
|
|
config = integration.config
|
|
elif isinstance(integration.config, str):
|
|
try:
|
|
parsed = json.loads(integration.config)
|
|
if isinstance(parsed, dict):
|
|
config = parsed
|
|
except (TypeError, ValueError):
|
|
config = {}
|
|
|
|
cold_start_enabled = bool(config.get("cold_start_enabled"))
|
|
signal_threshold = _safe_threshold(
|
|
config.get("signal_auto_enter_threshold"),
|
|
DEFAULT_SIGNAL_AUTO_ENTER_THRESHOLD,
|
|
)
|
|
project_threshold = _safe_threshold(
|
|
config.get("project_auto_create_threshold"),
|
|
DEFAULT_PROJECT_AUTO_CREATE_THRESHOLD,
|
|
)
|
|
uncertain_threshold = min(
|
|
project_threshold,
|
|
_safe_threshold(
|
|
config.get("project_uncertain_threshold"),
|
|
DEFAULT_PROJECT_UNCERTAIN_THRESHOLD,
|
|
),
|
|
)
|
|
return {
|
|
"raw": config,
|
|
"cold_start_enabled": cold_start_enabled,
|
|
"signal_auto_enter_threshold": signal_threshold,
|
|
"project_auto_create_threshold": project_threshold,
|
|
"project_uncertain_threshold": uncertain_threshold,
|
|
}
|
|
|
|
async def _backfill_feishu_sender_names(
|
|
db: AsyncSession,
|
|
*,
|
|
tenant_id: int,
|
|
signals: list[Signal],
|
|
) -> None:
|
|
pending: dict[int, dict[str, str]] = {}
|
|
for signal in signals:
|
|
if str(signal.source or "").lower() != "feishu":
|
|
continue
|
|
source_context = _signal_source_context(signal)
|
|
open_id = str(source_context.get("sender_open_id") or "").strip()
|
|
sender = _signal_proposer_name(signal).strip()
|
|
if not open_id or not sender:
|
|
continue
|
|
if _FEISHU_PLACEHOLDER_RE.match(sender):
|
|
pending[int(signal.id)] = {
|
|
"open_id": open_id,
|
|
"current_sender": sender,
|
|
}
|
|
if not pending:
|
|
return
|
|
|
|
service = get_feishu_service(db)
|
|
await service.load_config(tenant_id=tenant_id)
|
|
if not service.app_id or not service.app_secret:
|
|
return
|
|
|
|
resolved_name_by_open_id: dict[str, str] = {}
|
|
for open_id in sorted({meta["open_id"] for meta in pending.values()})[:20]:
|
|
try:
|
|
remote_name = await service._fetch_user_name_by_open_id(open_id) # noqa: SLF001
|
|
except Exception:
|
|
remote_name = None
|
|
normalized = (remote_name or "").strip()
|
|
if not normalized or _FEISHU_PLACEHOLDER_RE.match(normalized):
|
|
continue
|
|
resolved_name_by_open_id[open_id] = normalized
|
|
|
|
if not resolved_name_by_open_id:
|
|
return
|
|
|
|
changed = False
|
|
for signal in signals:
|
|
meta = pending.get(int(signal.id))
|
|
if not meta:
|
|
continue
|
|
sender_name = resolved_name_by_open_id.get(meta["open_id"])
|
|
if not sender_name:
|
|
continue
|
|
payload = _as_dict(signal.strategic_analysis)
|
|
source_context = payload.get("source_context")
|
|
if not isinstance(source_context, dict):
|
|
source_context = {}
|
|
source_context["sender"] = sender_name
|
|
source_context["sender_open_id"] = meta["open_id"]
|
|
payload["source_context"] = source_context
|
|
signal.strategic_analysis = json.dumps(payload, ensure_ascii=False)
|
|
signal.content = _replace_signal_sender_in_content(str(signal.content or ""), sender_name)
|
|
changed = True
|
|
|
|
if changed:
|
|
await db.commit()
|
|
|