PMFlow/backend/app/api/model_capability_api/routes_context.py

132 lines
4.1 KiB
Python
Raw Permalink 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 *
@router.post("/cost-optimization/analyze")
async def analyze_cost_optimization(
request: CostOptimizationAnalyzeRequest,
current_user: User = Depends(get_current_user),
tenant_id: int = Depends(get_tenant_id),
db: AsyncSession = Depends(get_db),
):
"""生成并持久化成本优化建议。"""
_ = current_user
service = CostOptimizationService(db)
try:
data = await service.analyze_cost_optimization(
truth_node_id=request.truth_node_id,
tenant_id=tenant_id,
period=request.period,
project_id=request.project_id,
)
return success_response(data=data)
except ValueError as exc:
return JSONResponse(
status_code=400,
content=error_response(ErrorCode.BAD_REQUEST, str(exc)),
)
except Exception as exc:
return JSONResponse(
status_code=500,
content=error_response(ErrorCode.INTERNAL_ERROR, f"成本优化分析失败: {exc}"),
)
@router.get("/context/projects/{project_id}/truth-nodes")
async def list_project_truth_nodes(
project_id: int,
current_user: User = Depends(get_current_user),
tenant_id: int = Depends(get_tenant_id),
db: AsyncSession = Depends(get_db),
):
"""获取项目上下文中的宪章列表,用于前端选择器。"""
_ = current_user
result = await db.execute(
select(TruthNode).where(
and_(
TruthNode.tenant_id == tenant_id,
TruthNode.project_id == project_id,
)
).order_by(TruthNode.created_at.desc())
)
nodes = result.scalars().all()
return success_response(
data={
"items": [
{
"id": n.id,
"title": n.title,
"status": n.status,
"node_type": n.node_type,
}
for n in nodes
]
}
)
@router.get("/context/projects/{project_id}/experiments")
async def list_project_experiments(
project_id: int,
current_user: User = Depends(get_current_user),
tenant_id: int = Depends(get_tenant_id),
db: AsyncSession = Depends(get_db),
):
"""获取项目上下文中的实验列表(基于 linked_context_nodes 关联)。"""
_ = current_user
truth_ids_result = await db.execute(
select(TruthNode.id).where(
and_(
TruthNode.tenant_id == tenant_id,
TruthNode.project_id == project_id,
)
)
)
truth_ids = {int(row[0]) for row in truth_ids_result.all()}
if not truth_ids:
return success_response(data={"items": []})
exp_result = await db.execute(
select(Experiment)
.where(Experiment.tenant_id == tenant_id)
.order_by(Experiment.created_at.desc())
)
experiments = exp_result.scalars().all()
def _linked_ids(raw) -> set[int]:
ids = set()
if isinstance(raw, list):
for x in raw:
try:
ids.add(int(x))
except (TypeError, ValueError):
continue
return ids
items = []
for e in experiments:
if e.project_id is not None:
if int(e.project_id) != int(project_id):
continue
items.append(
{
"id": e.id,
"title": e.title or f"Experiment {e.id}",
"status": e.status,
"target_metric": e.target_metric,
}
)
continue
# 迁移兼容:project_id 为空时,回退到 linked_context_nodes 交叉判断。
if _linked_ids(e.linked_context_nodes).isdisjoint(truth_ids):
continue
items.append(
{
"id": e.id,
"title": e.title or f"Experiment {e.id}",
"status": e.status,
"target_metric": e.target_metric,
}
)
return success_response(data={"items": items})