main
mula.liu 2025-09-03 18:11:07 +08:00
parent d85f12fb9d
commit d6602435c4
7 changed files with 231 additions and 19 deletions

31
Dockerfile 100644
View File

@ -0,0 +1,31 @@
# 使用Python 3.9.6基础镜像
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/python:3.12.9-slim
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
default-libmysqlclient-dev \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements-prod.txt .
# 安装Python依赖
RUN pip install --no-cache-dir -r requirements-prod.txt
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 8001
# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"]

View File

@ -22,7 +22,7 @@ MARKDOWN_DIR.mkdir(exist_ok=True)
DATABASE_CONFIG = { DATABASE_CONFIG = {
'host': os.getenv('DB_HOST', 'localhost'), 'host': os.getenv('DB_HOST', 'localhost'),
'user': os.getenv('DB_USER', 'root'), 'user': os.getenv('DB_USER', 'root'),
'password': os.getenv('DB_PASSWORD', ''), 'password': os.getenv('DB_PASSWORD', 'sagacity'),
'database': os.getenv('DB_NAME', 'imeeting'), 'database': os.getenv('DB_NAME', 'imeeting'),
'port': int(os.getenv('DB_PORT', '3306')), 'port': int(os.getenv('DB_PORT', '3306')),
'charset': 'utf8mb4' 'charset': 'utf8mb4'
@ -31,8 +31,7 @@ DATABASE_CONFIG = {
# API配置 # API配置
API_CONFIG = { API_CONFIG = {
'host': os.getenv('API_HOST', '0.0.0.0'), 'host': os.getenv('API_HOST', '0.0.0.0'),
'port': int(os.getenv('API_PORT', '8000')), 'port': int(os.getenv('API_PORT', '8000'))
'cors_origins': os.getenv('CORS_ORIGINS', 'http://localhost:5173').split(',')
} }
# 七牛云配置 # 七牛云配置

View File

@ -2,24 +2,14 @@
from fastapi import HTTPException from fastapi import HTTPException
import mysql.connector import mysql.connector
from mysql.connector import Error from mysql.connector import Error
from app.core.config import DATABASE_CONFIG
from contextlib import contextmanager from contextlib import contextmanager
DB_CONFIG = {
'host': 'localhost',
'database': 'imeeting',
'user': 'root',
'password': 'sagacity',
'port': 3306,
'charset': 'utf8mb4',
'autocommit': False, # 禁用自动提交
'consume_results': True # 自动消费未读结果
}
@contextmanager @contextmanager
def get_db_connection(): def get_db_connection():
connection = None connection = None
try: try:
connection = mysql.connector.connect(**DB_CONFIG) connection = mysql.connector.connect(**DATABASE_CONFIG)
yield connection yield connection
except Error as e: except Error as e:
print(f"数据库连接错误: {e}") print(f"数据库连接错误: {e}")

41
deploy-prod.sh 100755
View File

@ -0,0 +1,41 @@
#!/bin/bash
echo "🚀 开始部署iMeeting后端服务..."
# 检查虚拟环境
if [ ! -d "venv" ]; then
echo "❌ 虚拟环境不存在!请先创建虚拟环境"
exit 1
fi
echo "✅ 发现虚拟环境,继续部署..."
# 停止并删除现有容器
echo "📦 停止现有容器..."
docker-compose -f docker-compose.prod.yml down
# 构建新镜像
echo "🔨 构建Docker镜像..."
docker-compose -f docker-compose.prod.yml build --no-cache
# 启动服务
echo "▶️ 启动服务..."
docker-compose -f docker-compose.prod.yml up -d
# 检查服务状态
echo "🔍 检查服务状态..."
sleep 10
docker-compose -f docker-compose.prod.yml ps
# 检查健康状态
echo "🏥 检查健康状态..."
curl -f http://localhost:8001/health && echo "✅ 后端服务健康检查通过" || echo "❌ 后端服务健康检查失败"
echo ""
echo "🎉 部署完成!"
echo "🔧 后端服务访问地址: http://localhost:8001"
echo "📊 查看日志: docker-compose -f docker-compose.prod.yml logs -f"
echo "🛑 停止服务: docker-compose -f docker-compose.prod.yml down"
echo ""
echo "💡 提示:如需更新后端,请:"
echo " 1. 修改代码后运行 ./deploy-prod.sh 重新部署"

View File

@ -0,0 +1,59 @@
version: '3.8'
services:
imeeting-backend:
build:
context: .
dockerfile: Dockerfile
ports:
- "8001:8001"
environment:
# Python运行环境
- PYTHONPATH=/app
- PYTHONUNBUFFERED=1
# 数据库配置
- DB_HOST=host.docker.internal
- DB_USER=root
- DB_PASSWORD=sagacity
- DB_NAME=imeeting
- DB_PORT=3306
# Redis配置
- REDIS_HOST=host.docker.internal
- REDIS_PORT=6379
- REDIS_DB=6
- REDIS_PASSWORD=
# API配置
- API_HOST=0.0.0.0
- API_PORT=8001
# 应用配置
- BASE_URL=http://imeeting.unisspace.com
# 七牛云配置
- QINIU_ACCESS_KEY=A0tp96HCtg-wZCughTgi5vc2pJnw3btClwxRE_e8
- QINIU_SECRET_KEY=Lj-MSHpaVbmzpS86kMIjmwikvYOT9iPBjCk9hm6k
- QINIU_BUCKET=imeeting
- QINIU_DOMAIN=t0vogyxkz.hn-bkt.clouddn.com
# LLM配置
- QWEN_API_KEY=sk-c2bf06ea56b4491ea3d1e37fdb472b8f
- LLM_MODEL_NAME=qwen-plus
- LLM_API_URL=https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation
- LLM_MAX_TOKENS=2000
- LLM_TEMPERATURE=0.7
- LLM_TOP_P=0.9
volumes:
# 挂载上传目录保持数据持久化
- ./uploads:/app/uploads
restart: unless-stopped
container_name: imeeting-backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

42
main.py
View File

@ -1,9 +1,9 @@
import uvicorn import uvicorn
from fastapi import FastAPI from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from app.api.endpoints import auth, users, meetings from app.api.endpoints import auth, users, meetings
from app.core.config import UPLOAD_DIR, API_CONFIG from app.core.config import UPLOAD_DIR, API_CONFIG, MAX_FILE_SIZE
import os import os
app = FastAPI( app = FastAPI(
@ -12,10 +12,23 @@ app = FastAPI(
version="1.0.0" version="1.0.0"
) )
# 添加请求体大小检查中间件
@app.middleware("http")
async def check_content_size(request: Request, call_next):
# 检查Content-Length头
content_length = request.headers.get("content-length")
if content_length:
content_length = int(content_length)
if content_length > MAX_FILE_SIZE:
raise HTTPException(status_code=413, detail=f"Request entity too large. Maximum size is {MAX_FILE_SIZE//1024//1024}MB")
response = await call_next(request)
return response
# 添加CORS中间件 # 添加CORS中间件
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=API_CONFIG['cors_origins'], # allow_origins=API_CONFIG['cors_origins'],
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
@ -34,5 +47,26 @@ app.include_router(meetings.router, prefix="/api", tags=["Meetings"])
def read_root(): def read_root():
return {"message": "Welcome to iMeeting API"} return {"message": "Welcome to iMeeting API"}
@app.get("/health")
def health_check():
"""健康检查端点"""
return {
"status": "healthy",
"service": "iMeeting API",
"version": "1.0.0"
}
if __name__ == "__main__": if __name__ == "__main__":
uvicorn.run(app, host=API_CONFIG['host'], port=API_CONFIG['port']) # 简单的uvicorn配置避免参数冲突
uvicorn.run(
"main:app",
host=API_CONFIG['host'],
port=API_CONFIG['port'],
limit_max_requests=1000,
timeout_keep_alive=30,
reload=True,
# 设置更大的请求体限制以支持音频文件上传
h11_max_incomplete_event_size=104857600, # 100MB
)

View File

@ -0,0 +1,58 @@
aiohappyeyeballs==2.6.1
aiohttp==3.12.15
aiosignal==1.4.0
annotated-types==0.7.0
anyio==3.7.1
async-timeout==5.0.1
attrs==25.3.0
bcrypt==4.3.0
certifi==2025.8.3
cffi==1.17.1
charset-normalizer==3.4.3
click==8.1.8
cryptography==45.0.6
dashscope==1.24.1
distro==1.9.0
dnspython==2.7.0
ecdsa==0.19.1
email_validator==2.2.0
exceptiongroup==1.3.0
fastapi==0.104.1
frozenlist==1.7.0
h11==0.16.0
httpcore==1.0.9
httptools==0.6.4
httpx==0.28.1
idna==3.10
jiter==0.10.0
multidict==6.6.4
mysql-connector-python==8.2.0
openai==1.99.9
passlib==1.7.4
propcache==0.3.2
protobuf==4.21.12
pyasn1==0.6.1
pycparser==2.22
pydantic==2.5.0
pydantic_core==2.14.1
PyJWT==2.10.1
python-dotenv==1.1.1
python-jose==3.5.0
python-multipart==0.0.6
PyYAML==6.0.2
qiniu==7.17.0
redis==6.4.0
requests==2.32.4
rsa==4.9.1
six==1.17.0
sniffio==1.3.1
starlette==0.27.0
tqdm==4.67.1
typing_extensions==4.14.1
urllib3==2.5.0
uvicorn==0.24.0
uvloop==0.21.0
watchfiles==1.1.0
websocket-client==1.8.0
websockets==15.0.1
yarl==1.20.1