修复生成文件路径问题

This commit is contained in:
2025-12-03 11:22:41 +08:00
parent bc1f19542f
commit 90c3c0b0ba

50
main.py
View File

@ -15,13 +15,15 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from pydantic import BaseModel, HttpUrl from pydantic import BaseModel, HttpUrl
# 只导入AI_Agent的统一入口方法不再导入多个内部方法
from AI_Agent import generate_tender_from_input from AI_Agent import generate_tender_from_input
from config import DetectionResponse from config import DetectionResponse
from process import detect_large_image_from_url from process import detect_large_image_from_url
# 配置文件存储路径 # 配置文件存储路径(使用绝对路径确保一致性)
UPLOAD_DIR = Path("uploaded_files") BASE_DIR = Path(__file__).parent.resolve() # 项目根目录绝对路径
OUTPUT_DIR = Path("generated_tenders") UPLOAD_DIR = BASE_DIR / "uploaded_files"
OUTPUT_DIR = BASE_DIR / "generated_tenders"
UPLOAD_DIR.mkdir(exist_ok=True) UPLOAD_DIR.mkdir(exist_ok=True)
OUTPUT_DIR.mkdir(exist_ok=True) OUTPUT_DIR.mkdir(exist_ok=True)
@ -147,9 +149,11 @@ async def get_supported_types():
async def generate_tender_file(file: UploadFile = File(...)): async def generate_tender_file(file: UploadFile = File(...)):
""" """
上传招标文件Word格式生成投标文件 上传招标文件Word格式生成投标文件
支持的文件格式:.docx 支持的文件格式:.docx
返回生成文件的相对路径,用于下载接口 返回生成文件的相对路径,用于下载接口
""" """
# 初始化upload_path变量避免UnboundLocalError
upload_path = None upload_path = None
# 验证文件类型 # 验证文件类型
@ -172,15 +176,16 @@ async def generate_tender_file(file: UploadFile = File(...)):
print(f"已接收上传文件:{upload_path}") print(f"已接收上传文件:{upload_path}")
# 生成输出文件名和路径 # 生成输出文件名和路径(使用绝对路径)
output_filename = f"投标文件_生成版_{timestamp}.docx" output_filename = f"投标文件_生成版_{timestamp}.docx"
output_path = OUTPUT_DIR / output_filename output_path = OUTPUT_DIR / output_filename
output_path_abs = str(output_path.resolve()) # 绝对路径
# 调用AI_Agent的统一入口方法仅这一个调用 # 调用AI_Agent的统一入口方法仅这一个调用
print("开始生成投标文件...") print("开始生成投标文件...")
generate_success = generate_tender_from_input( generate_success = generate_tender_from_input(
input_word_path=str(upload_path), input_word_path=str(upload_path.resolve()), # 传入绝对路径
output_word_path=str(output_path) output_word_path=output_path_abs
) )
if not generate_success: if not generate_success:
@ -193,10 +198,19 @@ async def generate_tender_file(file: UploadFile = File(...)):
# 计算文件大小 # 计算文件大小
file_size = output_path.stat().st_size file_size = output_path.stat().st_size
# 构建相对路径(相对于项目根目录) # 修复使用os.path.relpath计算相对路径更灵活
relative_path = str(output_path.relative_to(Path.cwd())) try:
# 计算相对于项目根目录的相对路径
relative_path = os.path.relpath(output_path_abs, str(BASE_DIR))
# 统一路径分隔符为 '/'避免Windows和Linux差异
relative_path = relative_path.replace(os.sep, '/')
except Exception as e:
# 异常情况下直接返回文件名(降级方案)
relative_path = output_filename
print(f"计算相对路径失败,使用降级方案:{e}")
print(f"投标文件生成成功:{output_path}") print(f"投标文件生成成功:{output_path_abs}")
print(f"相对路径:{relative_path}")
return { return {
"status": "success", "status": "success",
@ -229,12 +243,17 @@ async def generate_tender_file(file: UploadFile = File(...)):
async def download_generated_file(relative_path: str): async def download_generated_file(relative_path: str):
""" """
根据相对路径下载生成的投标文件 根据相对路径下载生成的投标文件
Args: Args:
relative_path: 生成文件的相对路径(从/generate_tender接口获取 relative_path: 生成文件的相对路径(从/generate_tender接口获取
""" """
# 解析绝对路径,防止路径穿越攻击
try: try:
abs_path = Path(relative_path).resolve() # 修复:将相对路径转换为绝对路径
# 统一路径分隔符
relative_path = relative_path.replace('/', os.sep)
# 拼接项目根目录得到绝对路径
abs_path = BASE_DIR / relative_path
abs_path = abs_path.resolve() # 解析完整路径
# 验证路径是否在允许的输出目录内 # 验证路径是否在允许的输出目录内
if not abs_path.is_relative_to(OUTPUT_DIR.resolve()): if not abs_path.is_relative_to(OUTPUT_DIR.resolve()):
@ -271,9 +290,16 @@ async def list_generated_files():
"""列出所有生成的投标文件(可选接口)""" """列出所有生成的投标文件(可选接口)"""
files = [] files = []
for file in OUTPUT_DIR.glob("*.docx"): for file in OUTPUT_DIR.glob("*.docx"):
# 计算相对路径
try:
relative_path = os.path.relpath(str(file.resolve()), str(BASE_DIR))
relative_path = relative_path.replace(os.sep, '/')
except:
relative_path = file.name
files.append({ files.append({
"file_name": file.name, "file_name": file.name,
"relative_path": str(file.relative_to(Path.cwd())), "relative_path": relative_path,
"file_size": file.stat().st_size, "file_size": file.stat().st_size,
"created_time": file.stat().st_ctime "created_time": file.stat().st_ctime
}) })