修复 画布,mcp服务,搜索,文档的接口

This commit is contained in:
2025-11-07 09:34:35 +08:00
parent c5f8fe06e7
commit 54532747d2
21 changed files with 1023 additions and 272 deletions

View File

@@ -17,15 +17,23 @@ import logging
import os
import pathlib
import re
from typing import Optional, List
import flask
from flask import request
from flask_login import login_required, current_user
from fastapi import APIRouter, Depends, Query, UploadFile, File, Form
from fastapi.responses import Response
from api.apps.models.auth_dependencies import get_current_user
from api.apps.models.file_models import (
CreateFileRequest,
DeleteFilesRequest,
RenameFileRequest,
MoveFilesRequest,
)
from api.common.check_team_permission import check_file_team_permission
from api.db.services.document_service import DocumentService
from api.db.services.file2document_service import File2DocumentService
from api.utils.api_utils import server_error_response, get_data_error_result, validate_request
from api.utils.api_utils import server_error_response, get_data_error_result
from api.utils import get_uuid
from api.db import FileType, FileSource
from api.db.services import duplicate_name
@@ -36,35 +44,41 @@ from api.utils.file_utils import filename_type
from api.utils.web_utils import CONTENT_TYPE_MAP
from rag.utils.storage_factory import STORAGE_IMPL
# 创建路由器
router = APIRouter()
@manager.route('/upload', methods=['POST']) # noqa: F821
@login_required
# @validate_request("parent_id")
def upload():
pf_id = request.form.get("parent_id")
@router.post('/upload')
async def upload(
files: List[UploadFile] = File(...),
parent_id: Optional[str] = Form(None),
current_user = Depends(get_current_user)
):
"""上传文件"""
pf_id = parent_id
if not pf_id:
root_folder = FileService.get_root_folder(current_user.id)
pf_id = root_folder["id"]
if 'file' not in request.files:
if not files:
return get_json_result(
data=False, message='No file part!', code=settings.RetCode.ARGUMENT_ERROR)
file_objs = request.files.getlist('file')
for file_obj in file_objs:
if file_obj.filename == '':
for file_obj in files:
if not file_obj.filename or file_obj.filename == '':
return get_json_result(
data=False, message='No file selected!', code=settings.RetCode.ARGUMENT_ERROR)
file_res = []
try:
e, pf_folder = FileService.get_by_id(pf_id)
if not e:
return get_data_error_result( message="Can't find this folder!")
for file_obj in file_objs:
return get_data_error_result(message="Can't find this folder!")
for file_obj in files:
MAX_FILE_NUM_PER_USER = int(os.environ.get('MAX_FILE_NUM_PER_USER', 0))
if MAX_FILE_NUM_PER_USER > 0 and DocumentService.get_doc_count(current_user.id) >= MAX_FILE_NUM_PER_USER:
return get_data_error_result( message="Exceed the maximum file number of a free user!")
return get_data_error_result(message="Exceed the maximum file number of a free user!")
# split file name path
if not file_obj.filename:
@@ -97,7 +111,7 @@ def upload():
location = file_obj_names[file_len - 1]
while STORAGE_IMPL.obj_exist(last_folder.id, location):
location += "_"
blob = file_obj.read()
blob = await file_obj.read()
filename = duplicate_name(
FileService.query,
name=file_obj_names[file_len - 1],
@@ -120,13 +134,16 @@ def upload():
return server_error_response(e)
@manager.route('/create', methods=['POST']) # noqa: F821
@login_required
@validate_request("name")
def create():
req = request.json
pf_id = request.json.get("parent_id")
input_file_type = request.json.get("type")
@router.post('/create')
async def create(
request: CreateFileRequest,
current_user = Depends(get_current_user)
):
"""创建文件/文件夹"""
req = request.model_dump(exclude_unset=True)
pf_id = req.get("parent_id")
input_file_type = req.get("type")
if not pf_id:
root_folder = FileService.get_root_folder(current_user.id)
pf_id = root_folder["id"]
@@ -160,17 +177,22 @@ def create():
return server_error_response(e)
@manager.route('/list', methods=['GET']) # noqa: F821
@login_required
def list_files():
pf_id = request.args.get("parent_id")
@router.get('/list')
async def list_files(
parent_id: Optional[str] = Query(None, description="父文件夹ID"),
keywords: Optional[str] = Query("", description="搜索关键词"),
page: Optional[int] = Query(1, description="页码"),
page_size: Optional[int] = Query(15, description="每页数量"),
orderby: Optional[str] = Query("create_time", description="排序字段"),
desc: Optional[bool] = Query(True, description="是否降序"),
current_user = Depends(get_current_user)
):
"""列出文件"""
pf_id = parent_id
keywords = request.args.get("keywords", "")
page_number = int(request.args.get("page", 1))
items_per_page = int(request.args.get("page_size", 15))
orderby = request.args.get("orderby", "create_time")
desc = request.args.get("desc", True)
page_number = int(page) if page else 1
items_per_page = int(page_size) if page_size else 15
if not pf_id:
root_folder = FileService.get_root_folder(current_user.id)
pf_id = root_folder["id"]
@@ -192,9 +214,11 @@ def list_files():
return server_error_response(e)
@manager.route('/root_folder', methods=['GET']) # noqa: F821
@login_required
def get_root_folder():
@router.get('/root_folder')
async def get_root_folder(
current_user = Depends(get_current_user)
):
"""获取根文件夹"""
try:
root_folder = FileService.get_root_folder(current_user.id)
return get_json_result(data={"root_folder": root_folder})
@@ -202,10 +226,12 @@ def get_root_folder():
return server_error_response(e)
@manager.route('/parent_folder', methods=['GET']) # noqa: F821
@login_required
def get_parent_folder():
file_id = request.args.get("file_id")
@router.get('/parent_folder')
async def get_parent_folder(
file_id: str = Query(..., description="文件ID"),
current_user = Depends(get_current_user)
):
"""获取父文件夹"""
try:
e, file = FileService.get_by_id(file_id)
if not e:
@@ -217,10 +243,12 @@ def get_parent_folder():
return server_error_response(e)
@manager.route('/all_parent_folder', methods=['GET']) # noqa: F821
@login_required
def get_all_parent_folders():
file_id = request.args.get("file_id")
@router.get('/all_parent_folder')
async def get_all_parent_folders(
file_id: str = Query(..., description="文件ID"),
current_user = Depends(get_current_user)
):
"""获取所有父文件夹"""
try:
e, file = FileService.get_by_id(file_id)
if not e:
@@ -235,12 +263,13 @@ def get_all_parent_folders():
return server_error_response(e)
@manager.route("/rm", methods=["POST"]) # noqa: F821
@login_required
@validate_request("file_ids")
def rm():
req = request.json
file_ids = req["file_ids"]
@router.post("/rm")
async def rm(
request: DeleteFilesRequest,
current_user = Depends(get_current_user)
):
"""删除文件"""
file_ids = request.file_ids
def _delete_single_file(file):
try:
@@ -296,11 +325,13 @@ def rm():
return server_error_response(e)
@manager.route('/rename', methods=['POST']) # noqa: F821
@login_required
@validate_request("file_id", "name")
def rename():
req = request.json
@router.post('/rename')
async def rename(
request: RenameFileRequest,
current_user = Depends(get_current_user)
):
"""重命名文件"""
req = request.model_dump()
try:
e, file = FileService.get_by_id(req["file_id"])
if not e:
@@ -314,8 +345,8 @@ def rename():
data=False,
message="The extension of file can't be changed",
code=settings.RetCode.ARGUMENT_ERROR)
for file in FileService.query(name=req["name"], pf_id=file.parent_id):
if file.name == req["name"]:
for existing_file in FileService.query(name=req["name"], pf_id=file.parent_id):
if existing_file.name == req["name"]:
return get_data_error_result(
message="Duplicated file name in the same folder.")
@@ -336,9 +367,12 @@ def rename():
return server_error_response(e)
@manager.route('/get/<file_id>', methods=['GET']) # noqa: F821
@login_required
def get(file_id):
@router.get('/get/{file_id}')
async def get(
file_id: str,
current_user = Depends(get_current_user)
):
"""获取文件内容"""
try:
e, file = FileService.get_by_id(file_id)
if not e:
@@ -351,25 +385,28 @@ def get(file_id):
b, n = File2DocumentService.get_storage_address(file_id=file_id)
blob = STORAGE_IMPL.get(b, n)
response = flask.make_response(blob)
ext = re.search(r"\.([^.]+)$", file.name.lower())
ext = ext.group(1) if ext else None
content_type = "application/octet-stream"
if ext:
if file.type == FileType.VISUAL.value:
content_type = CONTENT_TYPE_MAP.get(ext, f"image/{ext}")
else:
content_type = CONTENT_TYPE_MAP.get(ext, f"application/{ext}")
response.headers.set("Content-Type", content_type)
return response
return Response(content=blob, media_type=content_type)
except Exception as e:
return server_error_response(e)
@manager.route("/mv", methods=["POST"]) # noqa: F821
@login_required
@validate_request("src_file_ids", "dest_file_id")
def move():
req = request.json
@router.post("/mv")
async def move(
request: MoveFilesRequest,
current_user = Depends(get_current_user)
):
"""移动文件"""
req = request.model_dump()
try:
file_ids = req["src_file_ids"]
dest_parent_id = req["dest_file_id"]