主要功能: - 图片上传时 OCR 内容去重(3个上传端点统一使用公共函数 _check_ocr_duplicate) - 图片管理 Tab:展示所有图片、手动删除、一键去重 - 搜索结果详情弹窗增加删除按钮(带确认弹窗) - 图片管理卡片点击查看详情(复用 showOcrDetailModal) - 搜索限制和 LLM 批量判断数量可通过网站设置 - MiniMax API 调用添加 reasoning_split=True - 企业微信机器人:WebSocket 长连接、图片搜索、配置化搜索数量 - 版本号升级至 1.2.0
113 lines
3.6 KiB
Python
113 lines
3.6 KiB
Python
"""
|
|
知识页面 API 路由
|
|
提供知识页面的 CRUD 接口
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database import get_db
|
|
from app.schemas.page import PageCreate, PageDetailResponse, PageListResponse, PageResponse, PageUpdate
|
|
from app.services.page_service import PageService
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("", response_model=PageListResponse, summary="获取知识页面列表")
|
|
async def list_pages(
|
|
page: int = Query(1, ge=1, description="页码"),
|
|
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
|
course_name: Optional[str] = Query(None, description="按课程名称过滤"),
|
|
teacher_name: Optional[str] = Query(None, description="按讲师名称过滤"),
|
|
keyword: Optional[str] = Query(None, description="关键词搜索"),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""分页查询知识页面列表,支持按课程/讲师/关键词过滤"""
|
|
service = PageService(db)
|
|
result = await service.list_pages(
|
|
page=page,
|
|
page_size=page_size,
|
|
course_name=course_name,
|
|
teacher_name=teacher_name,
|
|
keyword=keyword,
|
|
)
|
|
return PageListResponse(
|
|
total=result["total"],
|
|
page=result["page"],
|
|
page_size=result["page_size"],
|
|
items=[PageResponse.model_validate(p) for p in result["items"]],
|
|
)
|
|
|
|
|
|
@router.get("/{page_id}", response_model=PageDetailResponse, summary="获取知识页面详情")
|
|
async def get_page(
|
|
page_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""根据 ID 获取知识页面详情,包含关联的分块信息"""
|
|
service = PageService(db)
|
|
page = await service.get_page(page_id)
|
|
if page is None:
|
|
raise HTTPException(status_code=404, detail="知识页面不存在")
|
|
|
|
chunks = await service.get_page_chunks(page_id)
|
|
return PageDetailResponse(
|
|
**page.to_dict(),
|
|
chunks=[c.to_dict() for c in chunks],
|
|
)
|
|
|
|
|
|
@router.post("", response_model=PageResponse, status_code=201, summary="创建知识页面")
|
|
async def create_page(
|
|
data: PageCreate,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""创建新的知识页面"""
|
|
service = PageService(db)
|
|
page = await service.create_page(data)
|
|
return PageResponse.model_validate(page)
|
|
|
|
|
|
@router.put("/{page_id}", response_model=PageResponse, summary="更新知识页面")
|
|
async def update_page(
|
|
page_id: int,
|
|
data: PageUpdate,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""更新知识页面信息"""
|
|
service = PageService(db)
|
|
page = await service.update_page(page_id, data)
|
|
if page is None:
|
|
raise HTTPException(status_code=404, detail="知识页面不存在")
|
|
return PageResponse.model_validate(page)
|
|
|
|
|
|
@router.delete("/{page_id}", status_code=204, summary="删除知识页面")
|
|
async def delete_page(
|
|
page_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""删除知识页面及其关联的所有分块"""
|
|
service = PageService(db)
|
|
success = await service.delete_page(page_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="知识页面不存在")
|
|
|
|
|
|
@router.post("/{page_id}/reindex", summary="重新索引知识页面")
|
|
async def reindex_page(
|
|
page_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""重新对知识页面进行分块和向量化(页面内容更新后使用)"""
|
|
service = PageService(db)
|
|
try:
|
|
result = await service.reindex_page(page_id)
|
|
return result
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=404, detail=str(e))
|