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()