add docker

This commit is contained in:
朱潮 2025-10-07 17:33:35 +08:00
parent 7b538d4967
commit 9245864314
7 changed files with 168 additions and 93 deletions

56
.dockerignore Normal file
View File

@ -0,0 +1,56 @@
# Git
.git
.gitignore
# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
pip-log.txt
pip-delete-this-directory.txt
.tox
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.log
.git
.mypy_cache
.pytest_cache
.hypothesis
# Virtual environments
venv/
env/
ENV/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Project specific
logs/
projects/_cache/
*.zip
# Docker
Dockerfile
docker-compose.yml
.dockerignore

44
Dockerfile Normal file
View File

@ -0,0 +1,44 @@
# 使用Python 3.12官方镜像作为基础镜像
FROM python:3.12-slim
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1
ENV AGENT_POOL_SIZE=1
# 安装系统依赖
RUN sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources && \
apt-get update && apt-get install -y \
curl \
wget \
git \
nodejs \
npm \
ripgrep \
&& rm -rf /var/lib/apt/lists/*
# 复制requirements文件并安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt
# 复制应用代码
COPY . .
# 创建必要的目录
RUN mkdir -p /app/projects
# 设置权限
RUN chmod +x /app/mcp/json_reader_server.py
# 暴露端口
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/ || exit 1
# 启动命令
CMD ["python", "fastapi_app.py"]

24
docker-compose.yml Normal file
View File

@ -0,0 +1,24 @@
version: "3.8"
services:
qwen-agent:
build: .
container_name: qwen-agent-api
ports:
- "8000:8000"
environment:
# 应用配置
- PYTHONPATH=/app
- PYTHONUNBUFFERED=1
- AGENT_POOL_SIZE=2
volumes:
# 挂载项目数据目录
- ./projects:/app/projects
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

View File

@ -1,6 +1,7 @@
import json
import os
from typing import AsyncGenerator, Dict, List, Optional, Union
from contextlib import asynccontextmanager
import uvicorn
from fastapi import BackgroundTasks, FastAPI, HTTPException
@ -42,12 +43,40 @@ from agent_pool import (get_agent_from_pool, init_global_agent_pool,
from gbase_agent import init_agent_service_universal, update_agent_llm
from zip_project_handler import zip_handler
app = FastAPI(title="Database Assistant API", version="1.0.0")
# 全局助手实例池,在应用启动时初始化
agent_pool_size = int(os.getenv("AGENT_POOL_SIZE", "1"))
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时初始化助手实例池
print(f"正在启动FastAPI应用初始化助手实例池大小: {agent_pool_size}...")
try:
def agent_factory():
return init_agent_service_universal()
await init_global_agent_pool(pool_size=agent_pool_size, agent_factory=agent_factory)
print("助手实例池初始化完成!")
yield
except Exception as e:
print(f"助手实例池初始化失败: {e}")
raise
# 关闭时清理实例池
print("正在关闭应用,清理助手实例池...")
from agent_pool import get_agent_pool
pool = get_agent_pool()
if pool:
await pool.shutdown()
print("助手实例池清理完成!")
app = FastAPI(title="Database Assistant API", version="1.0.0", lifespan=lifespan)
class Message(BaseModel):
role: str
content: str
@ -279,32 +308,6 @@ async def cleanup_cache():
raise HTTPException(status_code=500, detail=f"缓存清理失败: {str(e)}")
@app.on_event("startup")
async def startup_event():
"""应用启动时初始化助手实例池"""
print(f"正在启动FastAPI应用初始化助手实例池大小: {agent_pool_size}...")
try:
def agent_factory():
return init_agent_service_universal()
await init_global_agent_pool(pool_size=agent_pool_size, agent_factory=agent_factory)
print("助手实例池初始化完成!")
except Exception as e:
print(f"助手实例池初始化失败: {e}")
raise
@app.on_event("shutdown")
async def shutdown_event():
"""应用关闭时清理实例池"""
print("正在关闭应用,清理助手实例池...")
from agent_pool import get_agent_pool
pool = get_agent_pool()
if pool:
await pool.shutdown()
print("助手实例池清理完成!")
if __name__ == "__main__":

View File

@ -21,7 +21,6 @@ import os
from typing import Dict, List, Optional, Union
from qwen_agent.agents import Assistant
from qwen_agent.gui import WebUI
from qwen_agent.llm.oai import TextChatAtOAI
from qwen_agent.llm.schema import ASSISTANT, FUNCTION, Message
from qwen_agent.utils.output_beautify import typewriter_print
@ -169,67 +168,3 @@ def test(query="数据库里有几张表"):
final_response = responses[-1][-1] # 取最后一个响应作为最终结果
print("Answer:", final_response["content"])
def app_tui():
# Define the agent - 使用通用初始化
bot = init_agent_service_universal()
# Chat
messages = []
while True:
# Query example: 数据库里有几张表
query = input("user question: ")
# File example: resource/poem.pdf
file = input("file url (press enter if no file): ").strip()
if not query:
print("user question cannot be empty")
continue
if not file:
messages.append({"role": "user", "content": query})
else:
messages.append(
{"role": "user", "content": [{"text": query}, {"file": file}]}
)
response = []
for response in bot.run(messages):
print("bot response:", response)
messages.extend(response)
def app_gui():
# Define the agent - 使用通用初始化
bot = init_agent_service_universal()
chatbot_config = {
"prompt.suggestions": [
"数据库里有几张表",
"创建一个学生表包括学生的姓名、年龄",
"增加一个学生名字叫韩梅梅今年6岁",
]
}
WebUI(
bot,
chatbot_config=chatbot_config,
).run()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="数据库助手")
parser.add_argument(
"--query", type=str, default="数据库里有几张表", help="用户问题"
)
parser.add_argument(
"--mode",
type=str,
choices=["test", "tui", "gui"],
default="test",
help="运行模式",
)
args = parser.parse_args()
if args.mode == "test":
test(args.query)
elif args.mode == "tui":
app_tui()
elif args.mode == "gui":
app_gui()

13
requirements.txt Normal file
View File

@ -0,0 +1,13 @@
# FastAPI和Web服务器
fastapi==0.116.1
uvicorn==0.35.0
# HTTP客户端
requests==2.32.5
# Qwen Agent框架
qwen-agent[mcp]==0.0.29
# 数据处理
pydantic==2.10.5
python-dateutil==2.8.2