PMFlow/backend/app/api/signals_api/feedback.py

119 lines
3.9 KiB
Python

"""Signal feedback endpoints."""
from __future__ import annotations
import json
from typing import List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from ...core.response import success_response
from ...core.database import get_db
from ...dependencies.auth import get_current_user
from ...dependencies.tenant import get_tenant_id
from ...models import Signal, SignalFeedback, User
from ...schemas import SignalFeedbackCreate, SignalFeedbackResponse
from ...services.feedback_center import FeedbackCenterService
router = APIRouter()
@router.post("/{signal_id}/feedback")
async def submit_signal_feedback(
signal_id: int,
feedback: SignalFeedbackCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
"""提交信号反馈"""
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
result = await db.execute(
select(Signal).where(
Signal.id == signal_id,
Signal.tenant_id == effective_tenant_id,
)
)
signal = result.scalar_one_or_none()
if not signal:
raise HTTPException(status_code=404, detail="Signal not found")
ai_predicted_strategic = False
ai_confidence = 0.0
if signal.strategic_analysis:
try:
analysis = json.loads(signal.strategic_analysis)
ai_predicted_strategic = analysis.get("is_strategic", signal.impact_score >= 0.9)
ai_confidence = analysis.get("confidence", 0.0)
except Exception:
ai_predicted_strategic = signal.impact_score >= 0.9
new_feedback = SignalFeedback(
tenant_id=effective_tenant_id,
signal_id=signal_id,
was_strategic=feedback.was_strategic,
reason=feedback.reason,
user_id=str(getattr(current_user, "id", feedback.user_id) or feedback.user_id or ""),
ai_predicted_strategic=ai_predicted_strategic,
ai_confidence=ai_confidence,
)
db.add(new_feedback)
await db.commit()
await db.refresh(new_feedback)
try:
await FeedbackCenterService(db).ingest_signal_feedback(
signal_feedback=new_feedback,
signal=signal,
commit=True,
)
except Exception:
await db.rollback()
is_correct = ai_predicted_strategic == feedback.was_strategic
return success_response(
SignalFeedbackResponse(
id=new_feedback.id,
signal_id=new_feedback.signal_id,
was_strategic=new_feedback.was_strategic,
ai_predicted_strategic=new_feedback.ai_predicted_strategic,
ai_confidence=new_feedback.ai_confidence or 0.0,
is_correct=is_correct,
).model_dump()
)
@router.get("/{signal_id}/feedbacks")
async def get_signal_feedbacks(
signal_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
tenant_id: int = Depends(get_tenant_id),
):
"""获取某信号的全部反馈"""
effective_tenant_id = int(getattr(current_user, "tenant_id", tenant_id) or tenant_id)
result = await db.execute(
select(SignalFeedback)
.where(
SignalFeedback.signal_id == signal_id,
SignalFeedback.tenant_id == effective_tenant_id,
)
.order_by(SignalFeedback.created_at.desc())
)
feedbacks = result.scalars().all()
items = [
SignalFeedbackResponse(
id=feedback.id,
signal_id=feedback.signal_id,
was_strategic=feedback.was_strategic,
ai_predicted_strategic=feedback.ai_predicted_strategic,
ai_confidence=feedback.ai_confidence or 0.0,
is_correct=feedback.ai_predicted_strategic == feedback.was_strategic,
).model_dump()
for feedback in feedbacks
]
return success_response({"items": items})