from __future__ import annotations from .shared import * class FeishuReceiveMixin: async def _handle_message_receive( self, event: Dict[str, Any] ) -> Dict[str, Any]: """处理收到的消息事件""" state_trace_id = f"feishu-sm-{uuid4().hex[:12]}" ingress_source = str(event.get("_ingress_source") or "feishu").strip() or "feishu" message = event.get('message', {}) if isinstance(event.get('message', {}), dict) else {} chat = event.get('chat', {}) if isinstance(event.get('chat', {}), dict) else {} sender = event.get('sender', {}) if isinstance(event.get('sender', {}), dict) else {} message_id = (message.get("message_id") or "").strip() or "unknown" perf_t0_raw = event.get("_perf_t0") perf_t0: Optional[float] = None if isinstance(perf_t0_raw, (int, float)): perf_t0 = float(perf_t0_raw) else: try: perf_t0 = float(str(perf_t0_raw).strip()) except Exception: perf_t0 = None self._emit_state_transition( trace_id=state_trace_id, state="RECEIVED", message_id=message_id, message_type=str(message.get("message_type") or "unknown"), ) sender_type = str(sender.get("sender_type") or "").strip().lower() if sender_type in {"app", "bot"}: return {'code': 0, 'msg': 'Ignore bot/app message'} mentioned_bot_names = self._extract_mentioned_bot_names(message) # 解析消息内容与附件元数据 message_payload = self._extract_message_payload(event) message_content = str(message_payload.get("text") or "").strip() or None message_attachments = ( message_payload.get("attachments") if isinstance(message_payload.get("attachments"), list) else [] ) await self._record_ingress_trace( ingress_source=ingress_source, trace_id=state_trace_id, message_id=message_id, event=event, message_content=message_content or "", ) if not message_content: print( f"[Feishu] message.receive_v1 ignored: no text content, " f"message_type={message.get('message_type')}, keys={list(message.keys())}" ) chat_id = chat.get('chat_id') or message.get('chat_id') or '' if mentioned_bot_names and chat_id: await self._safe_reply_text( chat_id=chat_id, mention_open_id=(sender.get('sender_id', {}) or {}).get('open_id'), mention_name=(sender.get('sender_name') or sender.get('name') or '你'), text="我已收到你的消息,但目前无法直接解析纯图片内容。请补充 1-2 句文字需求,我会立即给出分派建议。", trace_id=state_trace_id, source_message_id=message_id, perf_t0=perf_t0, ) self._emit_state_transition( trace_id=state_trace_id, state="REPLIED", route="empty_text_prompt", ) return {'code': 0, 'msg': 'No text content'} # 获取发送者信息 sender_id = sender.get('sender_id', {}) if isinstance(sender.get('sender_id', {}), dict) else {} sender_open_id = (sender_id.get('open_id') or "").strip() or None sender_name = await self._resolve_sender_display_name( sender=sender, sender_id=sender_id, ) # 获取群聊信息 chat_id = chat.get('chat_id') or message.get('chat_id') or '' chat_type = str(chat.get("chat_type") or message.get("chat_type") or "").strip().lower() or "group" captured_at = self._extract_message_datetime(message) occurred_at_iso = ( captured_at.isoformat() if isinstance(captured_at, datetime) else None ) message_attachments = self._normalize_ingress_attachment_records( message_attachments, occurred_at=occurred_at_iso, source_message_id=(message.get("message_id") or "").strip() or None, source_chat_id=chat_id or None, ) # 使用信号捕获服务处理 capture_service = ProactiveSignalCaptureService(self.db) try: result = await capture_service.capture_from_feishu( group_chat_id=chat_id, message_content=message_content, sender=sender_name, tenant_id=self.tenant_id, proposer_open_id=sender_open_id, captured_at=captured_at, mentioned_bot_names=mentioned_bot_names, feishu_message_id=(message.get("message_id") or "").strip() or None, chat_type=chat_type, ) await self._persist_signal_attachments_from_ingress( signal_id=result.get("signal_id"), attachments=message_attachments, ) except Exception as exc: self._emit_state_transition( trace_id=state_trace_id, state="ERROR_REPLY", reason="capture_exception", error=str(exc), ) if chat_id: await self._safe_reply_text( chat_id=chat_id, mention_open_id=sender_open_id, mention_name=sender_name, text=self._build_error_reply_text(), trace_id=state_trace_id, source_message_id=message_id, perf_t0=perf_t0, ) self._emit_state_transition( trace_id=state_trace_id, state="REPLIED", route="error_template", ) return { "code": 0, "msg": "error_handled", "data": { "status": "error", "classification": "error", "ai_trace_id": state_trace_id, }, } print( "[Feishu] Message processed: " f"status={result.get('status')}, " f"classification={result.get('classification')}, " f"linked_projects={result.get('linked_project_ids', [])}, " f"auto_tasks={len(result.get('auto_tasks', []) if isinstance(result.get('auto_tasks', []), list) else [])}, " f"ai_trace_id={result.get('ai_trace_id')}" ) scene = self._classify_message_scene(capture_result=result) self._emit_state_transition( trace_id=state_trace_id, state="CLASSIFIED", scene=scene, status=str(result.get("status") or "unknown"), classification=str(result.get("classification") or "unknown"), ) if str(result.get("status") or "").lower() != "error": self._emit_state_transition( trace_id=state_trace_id, state="COMMITTED", ai_trace_id=str(result.get("ai_trace_id") or ""), ) reply_route = await self._route_scene_reply( scene=scene, result=result, message_content=message_content, chat_id=chat_id, sender_open_id=sender_open_id, sender_name=sender_name, mentioned_bot_names=mentioned_bot_names, trace_id=state_trace_id, message_id=message_id, perf_t0=perf_t0, ) if reply_route != "none": self._emit_state_transition( trace_id=state_trace_id, state="REPLIED", route=reply_route, ) await self._record_message_trace( trace_id=state_trace_id, message_id=message_id, chat_type=chat_type, message_content=message_content, capture_result=result, reply_source=reply_route, ) return { 'code': 0, 'msg': 'success', 'data': { 'status': result.get('status'), 'classification': result.get('classification'), 'linked_project_ids': result.get('linked_project_ids', []), 'auto_tasks_count': len(result.get('auto_tasks', []) if isinstance(result.get('auto_tasks', []), list) else []), 'ai_trace_id': result.get('ai_trace_id'), 'state_trace_id': state_trace_id, 'scene': scene, }, }