174 lines
7.0 KiB
Python
174 lines
7.0 KiB
Python
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,
|
|
)
|
|
|