107 lines
3.4 KiB
Python
107 lines
3.4 KiB
Python
"""Signal list/create/project-link endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.future import select
|
|
|
|
from ...database import get_db
|
|
from ...models import Project, ProjectSignalLink, Signal
|
|
from ...schemas import SignalCreate
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/")
|
|
async def list_signals(
|
|
roles: Optional[str] = Query(None, description="逗号分隔的角色列表,如 'frontend,backend'"),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取信号列表,支持按角色过滤"""
|
|
result = await db.execute(select(Signal).order_by(Signal.impact_score.desc()))
|
|
signals = result.scalars().all()
|
|
|
|
if roles:
|
|
role_list = [r.strip() for r in roles.split(",")]
|
|
filtered_signals = []
|
|
for signal in signals:
|
|
tasks = []
|
|
if signal.tasks_generated:
|
|
try:
|
|
tasks = json.loads(signal.tasks_generated)
|
|
except Exception:
|
|
tasks = []
|
|
|
|
filtered_tasks = [task for task in tasks if task.get("type") in role_list]
|
|
|
|
if filtered_tasks:
|
|
signal_dict = {
|
|
"id": str(signal.id),
|
|
"source": signal.source,
|
|
"content": signal.content,
|
|
"impact_score": signal.impact_score,
|
|
"priority": signal.priority,
|
|
"processed": signal.processed,
|
|
"strategic_analysis": signal.strategic_analysis,
|
|
"tasks_generated": signal.tasks_generated,
|
|
"tasks_filtered": filtered_tasks,
|
|
"created_at": signal.created_at.isoformat() if signal.created_at else None,
|
|
}
|
|
filtered_signals.append(signal_dict)
|
|
|
|
return filtered_signals
|
|
|
|
return signals
|
|
|
|
|
|
@router.post("/", response_model=dict)
|
|
async def create_signal(signal: SignalCreate, db: AsyncSession = Depends(get_db)):
|
|
new_signal = Signal(
|
|
source=signal.source,
|
|
content=signal.content,
|
|
impact_score=signal.impact_score,
|
|
)
|
|
db.add(new_signal)
|
|
await db.commit()
|
|
await db.refresh(new_signal)
|
|
return {"id": str(new_signal.id), "status": "received"}
|
|
|
|
|
|
@router.get("/{signal_id}/projects")
|
|
async def get_signal_projects(
|
|
signal_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取信号关联的项目"""
|
|
try:
|
|
sid = int(signal_id)
|
|
except (ValueError, TypeError):
|
|
raise HTTPException(status_code=400, detail="Invalid signal_id")
|
|
|
|
signal_result = await db.execute(select(Signal).where(Signal.id == sid))
|
|
if not signal_result.scalar_one_or_none():
|
|
raise HTTPException(status_code=404, detail="Signal not found")
|
|
|
|
result = await db.execute(
|
|
select(Project, ProjectSignalLink)
|
|
.join(ProjectSignalLink, Project.id == ProjectSignalLink.project_id)
|
|
.where(ProjectSignalLink.signal_id == sid)
|
|
)
|
|
rows = result.all()
|
|
|
|
return [
|
|
{
|
|
"id": str(project.id),
|
|
"title": project.title,
|
|
"status": project.status,
|
|
"assigned_role": project.assigned_role,
|
|
"link_type": link.link_type,
|
|
"relevance_score": link.relevance_score,
|
|
}
|
|
for project, link in rows
|
|
]
|