PMFlow/backend/app/api/ai_steward_api/routes_conflicts.py

275 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from .shared import *
from .helpers import _parse_related_users, _utc_now_naive
from .schemas import CognitiveConflictResponse, ConflictDetectRequest
CONFLICT_TYPE_LABELS = {
"skill_mismatch": "技能错配",
"quality_drop": "质量下降预警",
"schedule_delay": "进度延期预警",
"unknown": "待识别冲突",
"risk": "风险预警",
}
def _display_conflict_type(value: str | None) -> str:
raw = str(value or "").strip()
if not raw:
return "待识别冲突"
mapped = CONFLICT_TYPE_LABELS.get(raw.lower())
if mapped:
return mapped
if any(separator in raw for separator in ("_", ":", "/", "-", ".")):
return "其他冲突"
return raw
@router.get("/cognitive-conflicts", response_model=List[CognitiveConflictResponse])
async def get_cognitive_conflicts(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
project_id: Optional[int] = None
):
"""
获取认知冲突列表
AI 会自动识别团队中的隐性认知差异,例如:
- 产品说"用户留存提升10%",开发实现的是"DAU提升10%"
- 双方没有争论,但目标不一致,AI 会主动识别并推送对齐提醒
"""
from ...models import CognitiveConflict, TruthNode
from sqlalchemy.future import select
query = select(CognitiveConflict).where(
CognitiveConflict.tenant_id == tenant_id,
CognitiveConflict.status == 'active'
)
if project_id:
# 通过 truth_node 关联到项目
query = query.join(
TruthNode, CognitiveConflict.truth_node_id == TruthNode.id
).where(
TruthNode.project_id == project_id
)
result = await db.execute(query)
conflicts = result.scalars().all()
return [
CognitiveConflictResponse(
id=str(c.id),
type=c.conflict_type,
display_type=_display_conflict_type(c.conflict_type),
description=c.description,
severity="high" if "critical" in (c.description or "").lower() else "medium",
related_users=_parse_related_users(c.involved_user_ids),
)
for c in conflicts
]
@router.post("/conflicts/detect")
async def detect_conflicts(
request: ConflictDetectRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id)
):
"""
检测项目中的认知冲突
支持检测类型:
- all: 全部检测(宪章冲突 + 定义冲突)
- charter: 仅检测宪章中的潜在冲突
- definition: 仅检测用户定义冲突
"""
try:
service = get_cognitive_conflict_service(db)
detected_conflicts = []
if request.detect_type in ["all", "charter"]:
charter_conflicts = await service.detect_charter_conflicts(
project_id=request.project_id,
tenant_id=tenant_id
)
detected_conflicts.extend(charter_conflicts)
if request.detect_type in ["all", "definition"]:
definition_conflicts = await service.detect_user_definition_conflicts(
project_id=request.project_id,
tenant_id=tenant_id
)
detected_conflicts.extend(definition_conflicts)
return {
"project_id": request.project_id,
"detected_count": len(detected_conflicts),
"conflicts": detected_conflicts
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"冲突检测失败: {str(e)}")
@router.post("/conflicts/{conflict_id}/propose-resolution")
async def propose_conflict_resolution(
conflict_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id)
):
"""
AI 生成认知冲突解决方案
为冲突双方生成对齐方案:
1. 分析冲突根因
2. 提出妥协方案
3. 生成可执行的对齐计划
"""
try:
service = get_cognitive_conflict_service(db)
resolution = await service.propose_alignment_resolution(
conflict_id=conflict_id,
tenant_id=tenant_id
)
return resolution
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"方案生成失败: {str(e)}")
@router.post("/conflicts/{conflict_id}/align")
async def trigger_async_alignment(
conflict_id: int,
user1_id: int,
user2_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id)
):
"""
触发异步 1v1 认知对齐
为冲突双方创建独立的对齐任务:
1. 发送对齐邀请
2. 提供背景信息
3. 收集双方观点
4. AI 生成共识方案
"""
try:
service = get_cognitive_conflict_service(db)
alignment = await service.trigger_async_alignment(
conflict_id=conflict_id,
user1_id=user1_id,
user2_id=user2_id,
tenant_id=tenant_id
)
return alignment
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"对齐触发失败: {str(e)}")
@router.post("/cognitive-conflicts/{conflict_id}/resolve")
async def resolve_cognitive_conflict(
conflict_id: int,
resolution_note: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id)
):
"""
解决认知冲突
AI 会生成解决方案建议,双方确认后标记为已解决
"""
from ...models import CognitiveConflict
from sqlalchemy.future import select
result = await db.execute(
select(CognitiveConflict).where(
CognitiveConflict.id == conflict_id,
CognitiveConflict.tenant_id == tenant_id
)
)
conflict = result.scalar_one_or_none()
if not conflict:
raise HTTPException(status_code=404, detail="冲突记录不存在")
conflict.status = 'resolved'
conflict.resolved_at = _utc_now_naive()
conflict.description += f"\n\n解决方案({current_user.username}): {resolution_note}"
await db.commit()
return {"message": "冲突已标记为已解决"}
@router.get("/conflicts/task-mismatch/{task_id}")
async def check_task_charter_mismatch(
task_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id)
):
"""
检测任务与宪章的一致性
检查:
1. 任务描述是否与宪章目标一致
2. 技术选型是否符合约束
3. 是否偏离项目方向
"""
from ...models import Task, TruthNode
from sqlalchemy.future import select
try:
# 获取任务
result = await db.execute(
select(Task).where(
Task.id == task_id,
Task.tenant_id == tenant_id
)
)
task = result.scalar_one_or_none()
if not task:
raise HTTPException(status_code=404, detail="任务不存在")
# 获取宪章
charter_result = await db.execute(
select(TruthNode).where(
TruthNode.id == task.truth_node_id,
TruthNode.tenant_id == tenant_id
)
)
charter = charter_result.scalar_one_or_none()
if not charter:
raise HTTPException(status_code=404, detail="宪章不存在")
# 检测一致性
service = get_cognitive_conflict_service(db)
mismatch = await service.detect_task_charter_mismatch(
task=task,
charter_content=charter.content,
tenant_id=tenant_id
)
if mismatch:
return {
"is_aligned": False,
"mismatch": mismatch
}
return {
"is_aligned": True,
"message": "任务与宪章一致"
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"一致性检测失败: {str(e)}")