fix: 知识库文档上传(尾斜杠+FormData+真文件接收); AI回复强制Markdown; 平台全功能知识库注入系统提示

This commit is contained in:
QihuAI Design committed 2026-07-14 23:04:30 +08:00
1 parent 62631a3b95
commit 463824480b
5 files changed
+183 -24

No files matched your search

+12
View File
@@ -26,6 +26,7 @@ from ..models import (
gen_uuid
)
from ..auth import get_current_user
from ..platform_knowledge import get_platform_knowledge
from ..middleware.log_service import LogService
from ..capability_registry import resolve_auto_model
@@ -656,6 +657,17 @@ def _build_system_prompt(
返回: (system_prompt_str, function_definitions_list)
"""
system_parts = ["你是AIFlow平台的AI助手,具备专业的知识储备和工具调用能力。"]
# 平台知识库注入(始终开启):确保AI优先使用平台已有能力
try:
pk = get_platform_knowledge()
if pk:
system_parts.append(f"【平台知识库——优先使用以下知识回答用户问题】\n{pk}")
except Exception:
pass
# 回复格式要求:强制使用Markdown
system_parts.append("回复格式要求:你必须使用Markdown格式回复,确保层次分明、条理清晰。使用##和###做标题、**加粗**强调重点、-或1.做列表、```代码块包裹代码或配置、表格展示对比数据。禁止回复纯文本长段落。")
function_definitions = []
+64 -20
View File
@@ -851,9 +851,12 @@ def get_documents(
@router.post("/bases/{base_id}/documents")
def upload_document(
async def upload_document(
base_id: str,
req: CreateDocumentRequest,
file: Optional[UploadFile] = File(None),
filename: str = Form(...),
file_type: Optional[str] = Form(None),
file_size: Optional[int] = Form(None),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
@@ -864,7 +867,7 @@ def upload_document(
raise HTTPException(status_code=404, detail="知识库不存在")
# 确定文件扩展名和存储路径
file_ext = (req.file_type or "txt").lower()
file_ext = (file_type or "txt").lower()
if file_ext.startswith("."):
file_ext = file_ext[1:]
@@ -877,28 +880,69 @@ def upload_document(
stored_filename = f"{doc_id}.{file_ext}"
stored_path = os.path.join(storage_dir, stored_filename)
# 文本解析:根据文件类型生成模拟文档内容
# 实际生产环境中应使用 PyPDF2/pdfplumber(PDF)、python-docx(Word)、openpyxl(Excel)等库
file_size = req.file_size or len(req.filename.encode('utf-8')) * 100
content = _generate_document_content(req.filename, file_ext, file_size)
# 文件内容解析
actual_size = file_size or 0
content = ""
uploaded_content = b""
# 将内容写入存储文件
try:
with open(stored_path, "w", encoding="utf-8") as f:
f.write(content)
logger.info(f"知识库文档已写入: {stored_path}, size={len(content)} chars")
except Exception as e:
logger.error(f"知识库文档写入失败: {stored_path}, error={e}")
raise HTTPException(status_code=500, detail=f"文件存储失败: {str(e)}")
# 如果有真实文件上传,先保存并读取内容
if file and file.filename:
try:
uploaded_content = await file.read()
actual_size = len(uploaded_content)
# 先写入原始文件
with open(stored_path, "wb") as f:
f.write(uploaded_content)
# 对于文本类格式,尝试直接解析
text_exts = {"txt", "md", "csv", "json", "yaml", "yml", "xml", "py", "js", "ts", "html", "css", "log"}
if file_ext in text_exts:
try:
content = uploaded_content.decode("utf-8")
except UnicodeDecodeError:
try:
content = uploaded_content.decode("gbk")
except UnicodeDecodeError:
content = f"[二进制文件: {filename}, 大小: {actual_size} bytes]"
else:
# 非文本格式:记录文件但内容用摘要代替
content = _generate_document_content(filename, file_ext, actual_size)
logger.info(f"非文本文件 {filename}({file_ext}) 已保存到 {stored_path}, 使用模拟内容用于检索")
except Exception as e:
logger.error(f"文件读取失败: {e}")
content = _generate_document_content(filename, file_ext, actual_size)
else:
# 无文件上传(兼容旧 JSON 模式):生成模拟内容
actual_size = file_size or len(filename.encode('utf-8')) * 100
content = _generate_document_content(filename, file_ext, actual_size)
# 写入模拟内容
try:
with open(stored_path, "w", encoding="utf-8") as f:
f.write(content)
except Exception as e:
logger.error(f"知识库文档写入失败: {stored_path}, error={e}")
raise HTTPException(status_code=500, detail=f"文件存储失败: {str(e)}")
# 文本分块:将内容按段落分割为chunks
# 确保文件已写入(防止重复写入)
if uploaded_content and file_ext not in {"txt", "md", "csv", "json", "yaml", "yml", "xml", "py", "js", "ts", "html", "css", "log"}:
pass # 已在上面 wb 写入
elif not os.path.exists(stored_path):
try:
with open(stored_path, "w", encoding="utf-8") as f:
f.write(content)
except Exception as e:
logger.error(f"知识库文档写入失败: {stored_path}, error={e}")
raise HTTPException(status_code=500, detail=f"文件存储失败: {str(e)}")
logger.info(f"知识库文档已处理: {stored_path}, ext={file_ext}, size={actual_size}, content_len={len(content)}")
# 文本分块
chunks = _split_content_into_chunks(content, chunk_size=500)
doc = KnowledgeDocument(
id=doc_id,
knowledge_base_id=base_id,
filename=req.filename,
file_size=file_size,
filename=filename,
file_size=actual_size,
file_type=file_ext,
status="completed",
chunk_count=len(chunks),
@@ -911,8 +955,8 @@ def upload_document(
kb.document_count = (kb.document_count or 0) + 1
kb.updated_at = datetime.now()
# 同步创建Asset记录(问题9:资产关联知识库文档用量)
_sync_asset_for_knowledge_doc(db, current_user.id, doc_id, req.filename, file_ext, file_size)
# 同步创建Asset记录
_sync_asset_for_knowledge_doc(db, current_user.id, doc_id, filename, file_ext, actual_size)
db.commit()
db.refresh(doc)