apikey in header

This commit is contained in:
朱潮 2025-10-08 18:01:11 +08:00
parent 4ba950a1ea
commit d123a67da1
5 changed files with 25 additions and 1026 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
projects/* projects/*
workspace workspace
__pycache__ __pycache__
public

View File

@ -29,16 +29,17 @@ COPY . .
# 创建必要的目录 # 创建必要的目录
RUN mkdir -p /app/projects RUN mkdir -p /app/projects
RUN mkdir -p /app/public
# 设置权限 # 设置权限
RUN chmod +x /app/mcp/json_reader_server.py RUN chmod +x /app/mcp/json_reader_server.py
# 暴露端口 # 暴露端口
EXPOSE 8000 EXPOSE 8001
# 健康检查 # 健康检查
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/ || exit 1 CMD curl -f http://localhost:8001/ || exit 1
# 启动命令 # 启动命令
CMD ["python", "fastapi_app.py"] CMD ["python", "fastapi_app.py"]

1008
chat.html

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ services:
build: . build: .
container_name: qwen-agent-api container_name: qwen-agent-api
ports: ports:
- "8000:8000" - "8001:8001"
environment: environment:
# 应用配置 # 应用配置
- PYTHONPATH=/app - PYTHONPATH=/app
@ -14,10 +14,11 @@ services:
volumes: volumes:
# 挂载项目数据目录 # 挂载项目数据目录
- ./projects:/app/projects - ./projects:/app/projects
- ./public:/app/public
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/"] test: ["CMD", "curl", "-f", "http://localhost:8001/"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3

View File

@ -3,7 +3,7 @@ import os
from typing import AsyncGenerator, Dict, List, Optional, Union from typing import AsyncGenerator, Dict, List, Optional, Union
import uvicorn import uvicorn
from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException, Depends, Header
from fastapi.responses import StreamingResponse, HTMLResponse, FileResponse from fastapi.responses import StreamingResponse, HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
@ -51,6 +51,9 @@ agent_manager = init_global_agent_manager(max_cached_agents=max_cached_agents)
app = FastAPI(title="Database Assistant API", version="1.0.0") app = FastAPI(title="Database Assistant API", version="1.0.0")
# 挂载public文件夹为静态文件服务
app.mount("/public", StaticFiles(directory="public"), name="static")
# 添加CORS中间件支持前端页面 # 添加CORS中间件支持前端页面
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
@ -69,7 +72,6 @@ class Message(BaseModel):
class ChatRequest(BaseModel): class ChatRequest(BaseModel):
messages: List[Message] messages: List[Message]
model: str = "qwen3-next" model: str = "qwen3-next"
api_key: Optional[str] = None
model_server: Optional[str] = None model_server: Optional[str] = None
zip_url: Optional[str] = None zip_url: Optional[str] = None
generate_cfg: Optional[Dict] = None generate_cfg: Optional[Dict] = None
@ -156,18 +158,28 @@ async def generate_stream_response(agent, messages, request) -> AsyncGenerator[s
yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n" yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"
@app.post("/chat/completions") @app.post("/api/v1/chat/completions")
async def chat_completions(request: ChatRequest): async def chat_completions(request: ChatRequest, authorization: Optional[str] = Header(None)):
""" """
Chat completions API similar to OpenAI, supports both streaming and non-streaming Chat completions API similar to OpenAI, supports both streaming and non-streaming
Args: Args:
request: ChatRequest containing messages, model, zip_url, etc. request: ChatRequest containing messages, model, zip_url, etc.
authorization: Authorization header containing API key (Bearer <API_KEY>)
Returns: Returns:
Union[ChatResponse, StreamingResponse]: Chat completion response or stream Union[ChatResponse, StreamingResponse]: Chat completion response or stream
""" """
try: try:
# 从Authorization header中提取API key
api_key = None
if authorization:
# 移除 "Bearer " 前缀
if authorization.startswith("Bearer "):
api_key = authorization[7:]
else:
api_key = authorization
# 从最外层获取zip_url参数 # 从最外层获取zip_url参数
zip_url = request.zip_url zip_url = request.zip_url
@ -191,7 +203,7 @@ async def chat_completions(request: ChatRequest):
zip_url=zip_url, zip_url=zip_url,
files=document_files, files=document_files,
model_name=request.model, model_name=request.model,
api_key=request.api_key, api_key=api_key,
model_server=request.model_server, model_server=request.model_server,
generate_cfg=request.generate_cfg generate_cfg=request.generate_cfg
) )
@ -258,14 +270,6 @@ async def chat_completions(request: ChatRequest):
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}") raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@app.get("/")
async def root():
"""Chat page endpoint"""
return FileResponse("chat.html", media_type="text/html")
@app.get("/api/health") @app.get("/api/health")
async def health_check(): async def health_check():
"""Health check endpoint""" """Health check endpoint"""
@ -353,4 +357,4 @@ async def remove_project_cache(zip_url: str):
if __name__ == "__main__": if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000) uvicorn.run(app, host="0.0.0.0", port=8001)