from __future__ import annotations from .shared import * class SignalCaptureSourceAnalyzersMixin: async def _analyze_webpage(self, url: str, title: str, content: str, tenant_id: int) -> Dict[str, Any]: """AI 分析网页价值""" prompt = f"""分析以下网页内容是否有价值: 标题:{title} URL: {url} 内容摘要:{content[:500]} 请判断: 1. 是否是技术文档、竞品信息、行业趋势? 2. 是否值得团队关注? 3. 影响程度(0-1)? 以 JSON 格式返回: {{ "is_valuable": boolean, "reason": "原因", "impact_score": 0.8, "priority": "high/medium/low", "analysis": {{}}, "suggested_tasks": [{{"task_name": "任务", "type": "backend", "estimated_hours": 8}}] }} 如果不是有价值内容,is_valuable 设为 false。""" try: response = await self.llm.generate( prompt, db=self.db, tenant_id=tenant_id, ) response = response.strip() if response.startswith('```'): response = response.split('```')[1] if response.startswith('json'): response = response[4:] return json.loads(response.strip()) except: return {'is_valuable': False, 'reason': 'AI 分析失败'} async def _analyze_github_event(self, repo_url: str, event_type: str, event_data: Dict, tenant_id: int) -> Dict[str, Any]: """AI 分析 GitHub 事件""" description = f"{event_type}: {event_data.get('title', event_data.get('message', ''))}" prompt = f"""分析以下 GitHub 事件是否有价值: 仓库:{repo_url} 事件:{description} 请判断: 1. 是否是技术栈更新、安全修复、重要功能? 2. 是否影响我们的项目? 3. 影响程度(0-1)? 以 JSON 格式返回: {{ "is_valuable": boolean, "reason": "原因", "impact_score": 0.8, "priority": "high/medium/low", "analysis": {{}}, "suggested_tasks": [{{"task_name": "任务", "type": "backend", "estimated_hours": 8}}] }} 如果不是有价值内容,is_valuable 设为 false。""" try: response = await self.llm.generate( prompt, db=self.db, tenant_id=tenant_id, ) response = response.strip() if response.startswith('```'): response = response.split('```')[1] if response.startswith('json'): response = response[4:] return json.loads(response.strip()) except: return {'is_valuable': False, 'reason': 'AI 分析失败'} async def _analyze_hackernews_story(self, story: Dict, tenant_id: int) -> Dict[str, Any]: """AI 分析 HackerNews 故事""" prompt = f"""分析以下 HackerNews 故事是否是重要技术趋势: 标题:{story.get('title', '')} 链接:{story.get('url', '')} 得分:{story.get('points', 0)} 请判断: 1. 是否是行业趋势、技术突破? 2. 是否值得我们关注? 3. 影响程度(0-1)? 以 JSON 格式返回: {{ "is_strategic": boolean, "impact_score": 0.8, "priority": "high/medium/low", "analysis": {{}}, "suggested_tasks": [{{"task_name": "任务", "type": "backend", "estimated_hours": 8}}] }} 如果不是战略性内容,is_strategic 设为 false。""" try: response = await self.llm.generate( prompt, db=self.db, tenant_id=tenant_id, ) response = response.strip() if response.startswith('```'): response = response.split('```')[1] if response.startswith('json'): response = response[4:] result = json.loads(response.strip()) # 重命名字段以匹配其他方法 return { 'is_valuable': result.get('is_strategic', False), 'reason': result.get('reason', ''), 'impact_score': result.get('impact_score', 0.5), 'priority': result.get('priority', 'low'), 'analysis': result.get('analysis', {}), 'suggested_tasks': result.get('suggested_tasks', []) } except: return {'is_valuable': False, 'reason': 'AI 分析失败'} async def _auto_link_to_projects( self, signal_id: int, analysis: Dict[str, Any], tenant_id: int, message_content: Optional[str] = None, ) -> List[int]: """自动关联信号到相关项目""" _ = message_content classification = str(analysis.get("classification") or "").lower() if classification in {"new_project", "pending_classification", "non_requirement"}: return [] if classification == "existing_project": matched_ids: List[int] = [] for pid in analysis.get("matched_project_ids", []) or []: try: matched_ids.append(int(pid)) except Exception: continue matched_ids = sorted(set(matched_ids)) if not matched_ids: return [] result = await self.db.execute( select(Project.id).where( and_( Project.id.in_(matched_ids), Project.status == "active", Project.tenant_id == tenant_id, ) ) ) valid_ids = {int(v) for v in result.scalars().all()} if not valid_ids: return [] confidence = float(analysis.get("confidence") or 0.0) relevance = max(0.5, min(0.98, 0.55 + confidence * 0.4)) link_type = "ai_existing_project_signal" else: result = await self.db.execute( select(Project.id).where( and_(Project.status == "active", Project.tenant_id == tenant_id) ) ) valid_ids = {int(v) for v in result.scalars().all()} if not valid_ids: return [] relevance = 0.7 link_type = "auto_captured" linked_project_ids: List[int] = [] for project_id in sorted(valid_ids): existing = await self.db.execute( text("SELECT id FROM project_signal_links WHERE project_id = :project_id AND signal_id = :signal_id"), {"project_id": project_id, "signal_id": signal_id}, ) if existing.first() is None: from ...models import ProjectSignalLink link = ProjectSignalLink( project_id=project_id, signal_id=signal_id, link_type=link_type, relevance_score=relevance, tenant_id=tenant_id, ) self.db.add(link) linked_project_ids.append(project_id) await self.db.commit() return linked_project_ids