from typing import Optional from fastapi import APIRouter, Depends, HTTPException, status, Request from pydantic import BaseModel from open_webui.models.users import Users, UserModel from open_webui.models.feedbacks import ( FeedbackModel, FeedbackResponse, FeedbackForm, Feedbacks, ) from open_webui.models.user_feedback import ( UserFeedbackModel, UserFeedbackForm, UserFeedbacks, ) from open_webui.constants import ERROR_MESSAGES from open_webui.utils.auth import get_admin_user, get_verified_user router = APIRouter() ############################ # GetConfig ############################ @router.get("/config") async def get_config(request: Request, user=Depends(get_admin_user)): return { "ENABLE_EVALUATION_ARENA_MODELS": request.app.state.config.ENABLE_EVALUATION_ARENA_MODELS, "EVALUATION_ARENA_MODELS": request.app.state.config.EVALUATION_ARENA_MODELS, } ############################ # UpdateConfig ############################ class UpdateConfigForm(BaseModel): ENABLE_EVALUATION_ARENA_MODELS: Optional[bool] = None EVALUATION_ARENA_MODELS: Optional[list[dict]] = None @router.post("/config") async def update_config( request: Request, form_data: UpdateConfigForm, user=Depends(get_admin_user), ): config = request.app.state.config if form_data.ENABLE_EVALUATION_ARENA_MODELS is not None: config.ENABLE_EVALUATION_ARENA_MODELS = form_data.ENABLE_EVALUATION_ARENA_MODELS if form_data.EVALUATION_ARENA_MODELS is not None: config.EVALUATION_ARENA_MODELS = form_data.EVALUATION_ARENA_MODELS return { "ENABLE_EVALUATION_ARENA_MODELS": config.ENABLE_EVALUATION_ARENA_MODELS, "EVALUATION_ARENA_MODELS": config.EVALUATION_ARENA_MODELS, } class UserResponse(BaseModel): id: str name: str email: str role: str = "pending" last_active_at: int # timestamp in epoch updated_at: int # timestamp in epoch created_at: int # timestamp in epoch class FeedbackUserResponse(FeedbackResponse): user: Optional[UserResponse] = None class UserSuggestionForm(BaseModel): content: str contact: Optional[str] = None @router.get("/feedbacks/all", response_model=list[FeedbackUserResponse]) async def get_all_feedbacks(user=Depends(get_admin_user)): feedbacks = Feedbacks.get_all_feedbacks() feedback_list = [] for feedback in feedbacks: user = Users.get_user_by_id(feedback.user_id) feedback_list.append( FeedbackUserResponse( **feedback.model_dump(), user=UserResponse(**user.model_dump()) if user else None, ) ) return feedback_list @router.delete("/feedbacks/all") async def delete_all_feedbacks(user=Depends(get_admin_user)): success = Feedbacks.delete_all_feedbacks() return success @router.get("/feedbacks/all/export", response_model=list[FeedbackModel]) async def get_all_feedbacks(user=Depends(get_admin_user)): feedbacks = Feedbacks.get_all_feedbacks() return feedbacks @router.get("/feedbacks/user", response_model=list[FeedbackUserResponse]) async def get_feedbacks(user=Depends(get_verified_user)): feedbacks = Feedbacks.get_feedbacks_by_user_id(user.id) return feedbacks @router.delete("/feedbacks", response_model=bool) async def delete_feedbacks(user=Depends(get_verified_user)): success = Feedbacks.delete_feedbacks_by_user_id(user.id) return success @router.post("/feedback", response_model=FeedbackModel) async def create_feedback( request: Request, form_data: FeedbackForm, user=Depends(get_verified_user), ): feedback = Feedbacks.insert_new_feedback(user_id=user.id, form_data=form_data) if not feedback: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT(), ) return feedback @router.post("/feedback/suggestion", response_model=UserFeedbackModel) async def create_suggestion_feedback( form_data: UserSuggestionForm, user=Depends(get_verified_user) ): """用户主动反馈入口:带 4 小时冷却期,命中则返回 429。""" content = (form_data.content or "").strip() if not content: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="反馈内容不能为空", ) # 4 小时限流 recent = UserFeedbacks.get_recent_within(user.id, seconds=4 * 60 * 60) if recent: raise HTTPException( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="您最近反馈过,请再等等一天", ) feedback = UserFeedbacks.create( user_id=user.id, content=content, contact=(form_data.contact or "").strip() or None, ) if not feedback: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT(), ) return feedback @router.get("/feedbacks/suggestion", response_model=list[UserFeedbackModel]) async def list_user_suggestions(user=Depends(get_admin_user)): """管理员查看所有用户反馈。""" return UserFeedbacks.list_all() @router.delete("/feedback/suggestion/{id}") async def delete_user_suggestion(id: str, user=Depends(get_admin_user)): """管理员删除单条用户反馈。""" success = UserFeedbacks.delete_by_id(id) if not success: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND ) return True @router.get("/feedback/{id}", response_model=FeedbackModel) async def get_feedback_by_id(id: str, user=Depends(get_verified_user)): if user.role == "admin": feedback = Feedbacks.get_feedback_by_id(id=id) else: feedback = Feedbacks.get_feedback_by_id_and_user_id(id=id, user_id=user.id) if not feedback: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND ) return feedback @router.post("/feedback/{id}", response_model=FeedbackModel) async def update_feedback_by_id( id: str, form_data: FeedbackForm, user=Depends(get_verified_user) ): if user.role == "admin": feedback = Feedbacks.update_feedback_by_id(id=id, form_data=form_data) else: feedback = Feedbacks.update_feedback_by_id_and_user_id( id=id, user_id=user.id, form_data=form_data ) if not feedback: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND ) return feedback @router.delete("/feedback/{id}") async def delete_feedback_by_id(id: str, user=Depends(get_verified_user)): if user.role == "admin": success = Feedbacks.delete_feedback_by_id(id=id) else: success = Feedbacks.delete_feedback_by_id_and_user_id(id=id, user_id=user.id) if not success: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND ) return success