From ebf27a6c3e7cee1fa62e7b3098d43938d510bf1c Mon Sep 17 00:00:00 2001 From: plf Date: Thu, 18 Jun 2026 14:06:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20KGEmptyError=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=BC=82=E5=B8=B8=20+=20CORS=20=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - qa_service 定义 KGEmptyError 异常,run_query 抛出;routers/query 精确捕获 → HTTP 400 + code 3002,移除字符串匹配 - main.py CORS 改为读 CORS_ORIGINS 环境变量:未设置时 wildcard + credentials=False(合规默认),设置后显式列表 + credentials=True - .env.example 新增 CORS_ORIGINS 默认值(后端 + 前端 4 个域名) --- backend/.env.example | 2 ++ backend/main.py | 17 +++++++++++++++-- backend/routers/query.py | 11 ++++++----- backend/services/qa_service.py | 9 ++++++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index 4ee51a7..26920d8 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -19,3 +19,5 @@ KEYCLOAK_REALM=plfai KEYCLOAK_CLIENT_ID=graphrag-backend KEYCLOAK_CLIENT_SECRET=your_keycloak_client_secret_here KEYCLOAK_AUDIENCE=account + +CORS_ORIGINS=https://graphrag-backend.plfai.cn,https://test-graphrag-backend.plfai.cn,https://graphrag.plfai.cn,https://test-graphrag.plfai.cn diff --git a/backend/main.py b/backend/main.py index 96eb6d7..5eab48d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2,6 +2,7 @@ GraphRAG Studio — FastAPI Backend Entry point: uvicorn main:app --host 0.0.0.0 --port 8000 --reload """ +import os import sys from pathlib import Path @@ -25,10 +26,22 @@ app = FastAPI( redoc_url="/redoc", ) +# CORS — explicit origins when set, wildcard otherwise. +# Auth uses Bearer headers (not cookies), so credentials are only needed when +# the browser is also sending cookies; keep credentials=False with wildcard to +# avoid the CORS spec rejecting the combo at runtime. +_cors_origins_raw = os.getenv("CORS_ORIGINS", "").strip() +if _cors_origins_raw: + _cors_origins = [o.strip() for o in _cors_origins_raw.split(",") if o.strip()] + _cors_credentials = True +else: + _cors_origins = ["*"] + _cors_credentials = False + app.add_middleware( CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, + allow_origins=_cors_origins, + allow_credentials=_cors_credentials, allow_methods=["*"], allow_headers=["*"], ) diff --git a/backend/routers/query.py b/backend/routers/query.py index 52bf9a8..20d7e28 100644 --- a/backend/routers/query.py +++ b/backend/routers/query.py @@ -7,6 +7,7 @@ from fastapi.responses import JSONResponse from models.schemas import APIResponse, BatchQueryRequest, QueryRequest from services import qa_service as svc +from services.qa_service import KGEmptyError router = APIRouter(prefix="/query", tags=["QA"]) @@ -20,12 +21,12 @@ async def run_query(body: QueryRequest): partial(svc.run_query, body.question, [m.model_dump() for m in body.history]), ) return APIResponse.ok(result) + except KGEmptyError as e: + return JSONResponse( + status_code=400, + content=APIResponse.err(3002, str(e)).model_dump(), + ) except ValueError as e: - if "KG_EMPTY" in str(e): - return JSONResponse( - status_code=400, - content=APIResponse.err(3002, "Knowledge graph is empty. Index documents first.").model_dump(), - ) return JSONResponse( status_code=500, content=APIResponse.err(4001, str(e)).model_dump(), diff --git a/backend/services/qa_service.py b/backend/services/qa_service.py index 62e4fbb..4afc1ba 100644 --- a/backend/services/qa_service.py +++ b/backend/services/qa_service.py @@ -8,6 +8,13 @@ from datetime import datetime, timezone from storage import file_store as fs +class KGEmptyError(Exception): + """Raised when a QA request is made but the knowledge graph has no nodes.""" + + def __init__(self, msg: str = "Knowledge graph is empty. Index documents first."): + super().__init__(msg) + + def run_query(question: str, history: list[dict]) -> dict: from pipeline.qa_agent import run_qa @@ -15,7 +22,7 @@ def run_query(question: str, history: list[dict]) -> dict: edges = fs.load_kg_edges() if not nodes: - raise ValueError("KG_EMPTY") + raise KGEmptyError() start = time.time() result = run_qa(question, history, nodes, edges)