from __future__ import annotations from .shared import * from .helpers import _extract_text_from_upload, _resolve_tenant_id @router.get("/knowledge-base/docs") async def list_knowledge_docs( current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), tenant_id: int = Depends(get_tenant_id), ): _ = current_user service = AdaptiveRAGService(db, tenant_id=_resolve_tenant_id(current_user, tenant_id)) return success_response(await service.list_knowledge_docs()) @router.post("/knowledge-base/docs") async def create_knowledge_doc( request: KnowledgeDocCreateRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), tenant_id: int = Depends(get_tenant_id), ): service = AdaptiveRAGService(db, tenant_id=_resolve_tenant_id(current_user, tenant_id)) result = await service.create_knowledge_doc( title=request.title, file_type=request.file_type, raw_content=request.content, uploaded_by=int(current_user.id), source_type=request.source_type, file_url=request.file_url, project_id=request.project_id, ) return success_response(result) @router.post("/knowledge-base/upload") async def upload_knowledge_doc( file: UploadFile = File(...), project_id: int | None = Form(default=None), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), tenant_id: int = Depends(get_tenant_id), ): raw = await file.read() if not raw: raise HTTPException(status_code=400, detail="上传文件为空") if len(raw) > 15 * 1024 * 1024: raise HTTPException(status_code=400, detail="文件过大,限制 15MB") file_type, text = _extract_text_from_upload(file.filename or "uploaded.txt", raw) if not str(text or "").strip(): raise HTTPException(status_code=400, detail="无法提取有效文本内容") effective_tenant_id = _resolve_tenant_id(current_user, tenant_id) service = AdaptiveRAGService(db, tenant_id=effective_tenant_id) doc = await service.create_knowledge_doc_placeholder( title=(file.filename or "uploaded.txt")[:255], file_type=file_type, uploaded_by=int(current_user.id), source_type="file", file_url=None, ) asyncio.create_task( AdaptiveRAGService.process_knowledge_doc_content_async( tenant_id=effective_tenant_id, doc_id=int(doc.id), raw_content=text, project_id=project_id, ) ) return success_response(service._serialize_doc(doc)) @router.post("/knowledge-base/urls") async def create_knowledge_url( request: KnowledgeURLCreateRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), tenant_id: int = Depends(get_tenant_id), ): url = str(request.url or "").strip() if not re.match(r"^https?://", url, flags=re.IGNORECASE): raise HTTPException(status_code=400, detail="URL 必须以 http:// 或 https:// 开头") effective_tenant_id = _resolve_tenant_id(current_user, tenant_id) service = AdaptiveRAGService(db, tenant_id=effective_tenant_id) doc = await service.create_knowledge_doc_placeholder( title=(request.title or url)[:255], file_type="url", uploaded_by=int(current_user.id), source_type="url", file_url=url, ) asyncio.create_task( AdaptiveRAGService.refresh_url_doc_async( tenant_id=effective_tenant_id, doc_id=int(doc.id), project_id=request.project_id, ) ) return success_response(service._serialize_doc(doc)) @router.post("/knowledge-base/docs/{doc_id}/refresh") async def refresh_knowledge_doc( doc_id: int, project_id: int | None = Query(default=None), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), tenant_id: int = Depends(get_tenant_id), ): effective_tenant_id = _resolve_tenant_id(current_user, tenant_id) service = AdaptiveRAGService(db, tenant_id=effective_tenant_id) try: doc = await service.get_knowledge_doc(doc_id=doc_id) if str(doc.get("source_type") or "").lower() != "url": raise HTTPException(status_code=400, detail="仅 URL 类型条目支持 refresh") marked = await service.mark_doc_processing(doc_id=doc_id) except ValueError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc asyncio.create_task( AdaptiveRAGService.refresh_url_doc_async( tenant_id=effective_tenant_id, doc_id=doc_id, project_id=project_id, ) ) return success_response(marked) @router.delete("/knowledge-base/docs/{doc_id}") async def delete_knowledge_doc( doc_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), tenant_id: int = Depends(get_tenant_id), ): _ = current_user service = AdaptiveRAGService(db, tenant_id=_resolve_tenant_id(current_user, tenant_id)) ok = await service.delete_knowledge_doc(doc_id=doc_id) if not ok: raise HTTPException(status_code=404, detail="文档不存在") return success_response({"deleted": True, "doc_id": doc_id})