mirror of
https://github.com/stardrophere/InsightRadar.git
synced 2026-06-05 23:56:36 +08:00
big update
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.dependencies import get_current_user, get_db
|
||||
from app.models.models import AppUser, UserTopicPreference
|
||||
from app.schemas.preference_schema import (
|
||||
MatchedEventResponse,
|
||||
UserPreferenceRecommendationResponse,
|
||||
UserTopicPreferenceCreate,
|
||||
UserTopicPreferenceResponse,
|
||||
)
|
||||
from app.services.matching_service import recommend_events_for_user
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _ensure_self_access(path_user_id: int, current_user: AppUser) -> None:
|
||||
"""校验路径 user_id 是否为当前登录用户本人。"""
|
||||
if path_user_id != current_user.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="You can only operate your own resources",
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/users/{user_id}/preferences",
|
||||
response_model=List[UserTopicPreferenceResponse],
|
||||
)
|
||||
def list_user_preferences(
|
||||
user_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: AppUser = Depends(get_current_user),
|
||||
):
|
||||
"""获取用户已设置的兴趣关键词。"""
|
||||
_ensure_self_access(user_id, current_user)
|
||||
preferences = (
|
||||
db.query(UserTopicPreference)
|
||||
.filter(UserTopicPreference.user_id == user_id)
|
||||
.order_by(UserTopicPreference.created_at.desc())
|
||||
.all()
|
||||
)
|
||||
return preferences
|
||||
|
||||
|
||||
@router.post(
|
||||
"/users/{user_id}/preferences",
|
||||
response_model=UserTopicPreferenceResponse,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
def create_user_preference(
|
||||
user_id: int,
|
||||
payload: UserTopicPreferenceCreate,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: AppUser = Depends(get_current_user),
|
||||
):
|
||||
"""新增一个用户兴趣关键词。"""
|
||||
_ensure_self_access(user_id, current_user)
|
||||
|
||||
keyword = payload.interested_keyword.strip()
|
||||
if not keyword:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Keyword cannot be empty")
|
||||
|
||||
db_obj = UserTopicPreference(
|
||||
user_id=user_id,
|
||||
interested_keyword=keyword,
|
||||
)
|
||||
db.add(db_obj)
|
||||
try:
|
||||
db.commit()
|
||||
except IntegrityError:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
detail="Preference keyword already exists for this user",
|
||||
)
|
||||
|
||||
db.refresh(db_obj)
|
||||
return db_obj
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/users/{user_id}/preferences/{preference_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
)
|
||||
def delete_user_preference(
|
||||
user_id: int,
|
||||
preference_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: AppUser = Depends(get_current_user),
|
||||
):
|
||||
"""删除一个用户兴趣关键词。"""
|
||||
_ensure_self_access(user_id, current_user)
|
||||
preference = (
|
||||
db.query(UserTopicPreference)
|
||||
.filter(
|
||||
UserTopicPreference.id == preference_id,
|
||||
UserTopicPreference.user_id == user_id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not preference:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Preference not found")
|
||||
|
||||
db.delete(preference)
|
||||
db.commit()
|
||||
return None
|
||||
|
||||
|
||||
@router.get(
|
||||
"/users/{user_id}/recommended-events",
|
||||
response_model=UserPreferenceRecommendationResponse,
|
||||
)
|
||||
def recommend_events(
|
||||
user_id: int,
|
||||
min_hot: int = Query(3, ge=1, description="最小热度阈值"),
|
||||
hours: int = Query(72, ge=1, le=24 * 30, description="仅匹配最近多少小时的事件"),
|
||||
limit: int = Query(20, ge=1, le=50, description="最多返回多少条推荐"),
|
||||
semantic_threshold: float = Query(0.78, ge=0.0, le=1.0, description="语义匹配相似度阈值"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: AppUser = Depends(get_current_user),
|
||||
):
|
||||
"""基于用户兴趣词推荐事件(精确匹配 + 语义匹配)。"""
|
||||
_ensure_self_access(user_id, current_user)
|
||||
|
||||
matched = recommend_events_for_user(
|
||||
db,
|
||||
user_id=user_id,
|
||||
min_hot=min_hot,
|
||||
hours=hours,
|
||||
limit=limit,
|
||||
semantic_threshold=semantic_threshold,
|
||||
)
|
||||
|
||||
result_data: list[MatchedEventResponse] = []
|
||||
for item in matched:
|
||||
result_data.append(
|
||||
MatchedEventResponse(
|
||||
event_id=item.event.id,
|
||||
unified_title=item.event.unified_title,
|
||||
summary=item.event.ai_comprehensive_summary,
|
||||
hot_score=item.event.hot_score,
|
||||
created_at=item.event.created_at,
|
||||
tags=item.tags,
|
||||
match_score=item.match_score,
|
||||
exact_hits=item.exact_hits,
|
||||
semantic_hits=item.semantic_hits,
|
||||
)
|
||||
)
|
||||
|
||||
return UserPreferenceRecommendationResponse(
|
||||
user_id=user_id,
|
||||
total=len(result_data),
|
||||
data=result_data,
|
||||
)
|
||||
Reference in New Issue
Block a user