from __future__ import annotations from .shared import * class SignalCaptureEntryMixin: def __init__(self, db: AsyncSession): self.db = db self.llm = LLMService() async def capture_from_feishu( self, group_chat_id: str, message_content: str, sender: str, tenant_id: int = 1, proposer_open_id: Optional[str] = None, captured_at: Optional[datetime] = None, mentioned_bot_names: Optional[List[str]] = None, feishu_message_id: Optional[str] = None, chat_type: Optional[str] = None, ) -> Dict[str, Any]: """ 从飞书群聊捕获信号 触发条件: - 提到产品、竞品、技术关键词 - 讨论架构、技术选型 - 分享技术文章 """ trace_id = f"feishu-{uuid4().hex[:12]}" captured_dt = captured_at or now_cn_aware() if captured_dt.tzinfo is None: captured_dt = captured_dt.replace(tzinfo=CN_TZ) proposer_name = self._normalize_single_line_text(sender or "未知用户", max_len=80) or "未知用户" proposer_open_id = self._normalize_single_line_text(proposer_open_id or "", max_len=128) or None self._emit_ai_think( "capture_start", trace_id=trace_id, tenant_id=tenant_id, group_chat_id=group_chat_id, sender=proposer_name, ) cleaned_message = self._sanitize_feishu_message(message_content) if not cleaned_message: self._emit_ai_think("capture_skip_empty", trace_id=trace_id) return {"status": "ignored", "reason": "empty_or_emoji_only"} if self._is_non_requirement_message(cleaned_message) and not self._is_question_like(cleaned_message): self._emit_ai_think( "capture_skip_noise", trace_id=trace_id, message_preview=cleaned_message[:120], ) return {"status": "ignored", "reason": "non_requirement_noise"} kernel = AIPMOKernelService(self.db, tenant_id=tenant_id) try: pipeline_result = await kernel.process_feishu_message( group_chat_id=group_chat_id, message_content=cleaned_message, sender=proposer_name, source_message_id=feishu_message_id, source_sender_open_id=proposer_open_id, captured_at=captured_dt, chat_type=chat_type, ) if not bool(pipeline_result.get("handled")): self._emit_ai_think( "capture_kernel_failed", trace_id=trace_id, reason=pipeline_result.get("reason"), error=pipeline_result.get("error"), ) return { "status": "error", "reason": str(pipeline_result.get("reason") or "kernel_not_handled"), "classification": "error", "project_scope": "error", "linked_project_ids": [], "signal_id": None, "created_project_id": None, "auto_tasks": [], "ai_trace_id": trace_id, "direct_reply_required": True, "direct_reply_text": "系统处理中出现异常,本次未执行入库。请稍后重试,或补充更明确的目标/对象/动作。", } self._emit_ai_think( "capture_done_ai_pmo", trace_id=trace_id, classification=pipeline_result.get("classification"), linked_project_ids=pipeline_result.get("linked_project_ids", []), work_item_id=pipeline_result.get("work_item_id"), ) pipeline_result = await self._apply_pipeline_post_actions( trace_id=trace_id, tenant_id=tenant_id, cleaned_message=cleaned_message, proposer_name=proposer_name, captured_at=captured_dt, pipeline_result=pipeline_result, ) try: await self._sync_feishu_recent_cache( tenant_id=tenant_id, group_chat_id=group_chat_id, sender=proposer_name, sender_open_id=proposer_open_id, message=cleaned_message, pipeline_result=pipeline_result, ) except Exception as cache_exc: self._emit_ai_think( "capture_recent_cache_sync_failed", trace_id=trace_id, error=str(cache_exc), ) try: asyncio.create_task( AdaptiveRAGService.ingest_feishu_message_async( tenant_id=tenant_id, content=cleaned_message, sender=proposer_name, chat_id=group_chat_id, message_id=feishu_message_id, captured_at=captured_dt, project_id=( int(pipeline_result["linked_project_ids"][0]) if isinstance(pipeline_result.get("linked_project_ids"), list) and pipeline_result.get("linked_project_ids") else None ), ) ) except Exception: pass return pipeline_result except Exception as exc: self._emit_ai_think("capture_kernel_failed", trace_id=trace_id, error=str(exc)) try: await self.db.rollback() except Exception as rollback_exc: self._emit_ai_think( "capture_kernel_failed_rollback_failed", trace_id=trace_id, error=str(rollback_exc), ) return { "status": "error", "reason": "kernel_failed", "classification": "error", "project_scope": "error", "linked_project_ids": [], "signal_id": None, "created_project_id": None, "auto_tasks": [], "ai_trace_id": trace_id, "direct_reply_required": True, "direct_reply_text": "系统处理中出现异常,本次未执行入库。请稍后重试,或补充更明确的目标/对象/动作。", } return await self._capture_from_feishu_legacy_flow( trace_id=trace_id, group_chat_id=group_chat_id, message_content=message_content, cleaned_message=cleaned_message, proposer_name=proposer_name, proposer_open_id=proposer_open_id, mentioned_bot_names=mentioned_bot_names, tenant_id=tenant_id, captured_dt=captured_dt, )