This commit is contained in:
aaron 2025-12-28 10:28:18 +08:00
parent 24687e572b
commit 9d50a2bae8
9 changed files with 771 additions and 10 deletions

87
.dockerignore Normal file
View File

@ -0,0 +1,87 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
env/
ENV/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Git
.git/
.gitignore
# Docker
Dockerfile*
docker-compose*.yml
.dockerignore
# Logs
logs/
*.log
# Environment files
.env
.env.local
.env.development
.env.test
.env.production
# Cache directories
.cache/
.pytest_cache/
# Coverage reports
htmlcov/
.coverage
.coverage.*
coverage.xml
# Documentation
docs/_build/
# Node modules (if any)
node_modules/
# Database files
*.db
*.sqlite
*.sqlite3
# Temporary files
tmp/
temp/
# Test files
.tox/
.coverage
.pytest_cache/

17
.env.docker Normal file
View File

@ -0,0 +1,17 @@
# Tushare API配置
TUSHARE_TOKEN=your_tushare_token_here
# Redis配置
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_DB=0
# API配置
API_HOST=0.0.0.0
API_PORT=8000
# 数据库配置(可选)
# DATABASE_URL=sqlite:///./stockagent.db
# 日志级别
# LOG_LEVEL=INFO

40
Dockerfile.backend Normal file
View File

@ -0,0 +1,40 @@
# 使用官方Python 3.9运行时作为基础镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONPATH=/app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
g++ \
&& rm -rf /var/lib/apt/lists/*
# 复制requirements文件
COPY requirements.txt .
# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制项目文件
COPY . .
# 创建非root用户
RUN useradd --create-home --shell /bin/bash app \
&& chown -R app:app /app
USER app
# 暴露端口
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/ || exit 1
# 启动命令
CMD ["python", "main.py"]

37
Dockerfile.frontend Normal file
View File

@ -0,0 +1,37 @@
# 使用官方Python 3.9运行时作为基础镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
FLASK_APP=app.py \
FLASK_ENV=production
# 安装系统依赖
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
# 安装Flask和相关依赖
RUN pip install --no-cache-dir flask requests
# 复制web目录
COPY web/ .
# 创建非root用户
RUN useradd --create-home --shell /bin/bash app \
&& chown -R app:app /app
USER app
# 暴露端口
EXPOSE 5001
# 健康检查
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5001/ || exit 1
# 启动命令
CMD ["python", "app.py"]

196
README.md
View File

@ -24,7 +24,74 @@
## 快速开始 ## 快速开始
### 1. 环境配置 ### 方法一Docker部署 (推荐)
使用Docker Compose可以一键部署整个应用包括前端、后端和Redis缓存。
#### 1. 环境准备
```bash
# 确保已安装Docker和Docker Compose
docker --version
docker-compose --version
# 克隆项目
git clone <repository-url>
cd StockAgent
```
#### 2. 配置环境变量
```bash
# 复制环境变量模板
cp .env.docker .env
# 编辑环境变量文件设置你的tushare token
vim .env # 或使用其他编辑器
```
`.env` 文件中设置:
```bash
TUSHARE_TOKEN=your_tushare_token_here
```
#### 3. 启动服务
```bash
# 一键启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
```
#### 4. 访问应用
- **Web界面**: http://localhost:5001
- **API文档**: http://localhost:8000/docs
- **Redis管理**: localhost:6379
#### 5. 管理命令
```bash
# 停止服务
docker-compose down
# 重启服务
docker-compose restart
# 更新应用
docker-compose down
docker-compose build --no-cache
docker-compose up -d
# 清理数据
docker-compose down -v # 警告会删除Redis数据
```
### 方法二:本地开发部署
适合开发和调试环境。
#### 1. 环境配置
```bash ```bash
# 创建虚拟环境 # 创建虚拟环境
@ -39,14 +106,14 @@ cp .env.example .env
# 编辑 .env 文件,设置你的 tushare token # 编辑 .env 文件,设置你的 tushare token
``` ```
### 2. 配置 tushare token #### 2. 配置 tushare token
`.env` 文件中设置: `.env` 文件中设置:
``` ```
TUSHARE_TOKEN=your_tushare_token_here TUSHARE_TOKEN=your_tushare_token_here
``` ```
### 3. 启动服务 #### 3. 启动服务
```bash ```bash
# 启动后端 API 服务 # 启动后端 API 服务
@ -56,7 +123,7 @@ python main.py
cd web && python app.py cd web && python app.py
``` ```
### 4. 访问应用 #### 4. 访问应用
- **Web界面**: http://localhost:5001 (主要入口) - **Web界面**: http://localhost:5001 (主要入口)
- **API文档**: http://localhost:8000/docs (后端API) - **API文档**: http://localhost:8000/docs (后端API)
@ -208,11 +275,120 @@ print(f"综合评分: {comprehensive_score}")
- **止损建议**: 基于ATR、布林带等技术指标动态计算 - **止损建议**: 基于ATR、布林带等技术指标动态计算
- **仓位管理**: 根据风险评级提供合理的仓位建议 - **仓位管理**: 根据风险评级提供合理的仓位建议
### ⚡ 性能优化 ## 部署说明
- **缓存机制**: Redis缓存减少重复计算
- **批量处理**: 限制处理数量避免超时
- **防重复提交**: 前端防重复点击,后端缓存复用
## 许可证 ### 🐳 Docker部署架构
MIT License ```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │ │ Backend │ │ Redis Cache │
│ (Flask) │────│ (FastAPI) │────│ (Redis) │
│ Port: 5001 │ │ Port: 8000 │ │ Port: 6379 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└────────────────────────┼────────────────────────┘
Docker Network: stockagent-network
```
### 🔧 生产环境优化
对于生产环境部署,可以使用以下优化配置:
#### 1. 创建生产环境Docker Compose文件
```bash
# 创建生产环境配置
cp docker-compose.yml docker-compose.prod.yml
```
#### 2. 生产环境配置优化
- 使用nginx反向代理
- 添加SSL证书支持
- 配置日志轮转
- 设置资源限制
- 添加监控和告警
### 🔍 故障排除
#### 常见问题及解决方案
**1. Tushare Token配置问题**
```bash
# 检查环境变量
docker-compose exec backend env | grep TUSHARE_TOKEN
# 如果未设置,停止服务并重新配置
docker-compose down
vim .env # 设置正确的token
docker-compose up -d
```
**2. Redis连接问题**
```bash
# 检查Redis服务状态
docker-compose exec redis redis-cli ping
# 查看Redis日志
docker-compose logs redis
```
**3. 服务启动失败**
```bash
# 查看详细日志
docker-compose logs backend
docker-compose logs frontend
# 重新构建镜像
docker-compose build --no-cache
docker-compose up -d
```
**4. 端口冲突**
```bash
# 检查端口占用
netstat -tlnp | grep :5001
netstat -tlnp | grep :8000
# 修改docker-compose.yml中的端口映射
```
### 📊 监控和维护
#### 1. 服务监控
```bash
# 查看服务状态
docker-compose ps
# 查看资源使用情况
docker stats $(docker-compose ps -q)
# 查看实时日志
docker-compose logs -f --tail=100
```
#### 2. 数据备份
```bash
# 备份Redis数据
docker-compose exec redis redis-cli BGSAVE
docker cp stockagent-redis:/data/dump.rdb ./backup/redis-$(date +%Y%m%d).rdb
# 备份配置文件
tar -czf backup/config-$(date +%Y%m%d).tar.gz config/ .env
```
#### 3. 更新和维护
```bash
# 拉取最新代码
git pull
# 停止服务
docker-compose down
# 重新构建并启动
docker-compose build --no-cache
docker-compose up -d
# 验证服务正常
curl http://localhost:5001
curl http://localhost:8000/docs
```

View File

@ -0,0 +1,60 @@
version: '3.8'
services:
# 后端API服务 - 使用外部Redis
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: stockagent-backend
restart: unless-stopped
ports:
- "8000:8000"
environment:
- TUSHARE_TOKEN=${TUSHARE_TOKEN}
- REDIS_HOST=host.docker.internal # 连接到宿主机的Redis
- REDIS_PORT=6379
- REDIS_DB=0 # 可以使用不同的数据库编号避免冲突
- API_HOST=0.0.0.0
- API_PORT=8000
volumes:
- ./logs:/app/logs
- ./config:/app/config
networks:
- stockagent-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
extra_hosts:
- "host.docker.internal:host-gateway"
# 前端Web服务
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
container_name: stockagent-frontend
restart: unless-stopped
ports:
- "5001:5001"
environment:
- API_BASE_URL=http://backend:8000/api
depends_on:
- backend
networks:
- stockagent-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5001/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
# 网络配置
networks:
stockagent-network:
driver: bridge
name: stockagent-network

139
docker-compose.prod.yml Normal file
View File

@ -0,0 +1,139 @@
version: '3.8'
services:
# Nginx反向代理
nginx:
image: nginx:alpine
container_name: stockagent-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- ./logs/nginx:/var/log/nginx
depends_on:
- frontend
- backend
networks:
- stockagent-network
# Redis缓存服务
redis:
image: redis:7-alpine
container_name: stockagent-redis
restart: unless-stopped
ports:
- "127.0.0.1:6379:6379" # 只绑定到本地
volumes:
- redis_data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- stockagent-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
# 后端API服务
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: stockagent-backend
restart: unless-stopped
expose:
- "8000"
environment:
- TUSHARE_TOKEN=${TUSHARE_TOKEN}
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_DB=0
- API_HOST=0.0.0.0
- API_PORT=8000
- LOG_LEVEL=INFO
volumes:
- ./logs:/app/logs
- ./config:/app/config
depends_on:
redis:
condition: service_healthy
networks:
- stockagent-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 1G
cpus: '0.5'
reservations:
memory: 512M
cpus: '0.25'
# 前端Web服务
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
container_name: stockagent-frontend
restart: unless-stopped
expose:
- "5001"
environment:
- API_BASE_URL=http://backend:8000/api
- FLASK_ENV=production
depends_on:
backend:
condition: service_healthy
networks:
- stockagent-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5001/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
deploy:
resources:
limits:
memory: 256M
cpus: '0.25'
reservations:
memory: 128M
cpus: '0.1'
# 日志收集器(可选)
# logrotate:
# image: tutum/logrotate
# container_name: stockagent-logrotate
# restart: unless-stopped
# volumes:
# - ./logs:/logs
# environment:
# - LOGS_DIRECTORIES=/logs
# 网络配置
networks:
stockagent-network:
driver: bridge
name: stockagent-network
# 数据卷配置
volumes:
redis_data:
driver: local
name: stockagent-redis-data

86
docker-compose.yml Normal file
View File

@ -0,0 +1,86 @@
version: '3.8'
services:
# Redis缓存服务
redis:
image: redis:7-alpine
container_name: stockagent-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
networks:
- stockagent-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# 后端API服务
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: stockagent-backend
restart: unless-stopped
ports:
- "8000:8000"
environment:
- TUSHARE_TOKEN=${TUSHARE_TOKEN}
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_DB=0
- API_HOST=0.0.0.0
- API_PORT=8000
volumes:
- ./logs:/app/logs
- ./config:/app/config
depends_on:
redis:
condition: service_healthy
networks:
- stockagent-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# 前端Web服务
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
container_name: stockagent-frontend
restart: unless-stopped
ports:
- "5001:5001"
environment:
- API_BASE_URL=http://backend:8000/api
depends_on:
backend:
condition: service_healthy
networks:
- stockagent-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5001/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
# 网络配置
networks:
stockagent-network:
driver: bridge
name: stockagent-network
# 数据卷配置
volumes:
redis_data:
driver: local
name: stockagent-redis-data

119
nginx/nginx.conf Normal file
View File

@ -0,0 +1,119 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json;
# 限制请求速率
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=web:10m rate=30r/s;
# 上游服务器配置
upstream backend {
server frontend:5001;
}
upstream api {
server backend:8000;
}
# HTTP服务器配置
server {
listen 80;
server_name localhost;
# 静态文件缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options nosniff;
}
# API路由
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 300s;
}
# Web应用路由
location / {
limit_req zone=web burst=50 nodelay;
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
# HTTPS服务器配置可选
# server {
# listen 443 ssl http2;
# server_name your-domain.com;
#
# ssl_certificate /etc/nginx/ssl/cert.pem;
# ssl_certificate_key /etc/nginx/ssl/key.pem;
# ssl_session_timeout 1d;
# ssl_session_cache shared:SSL:50m;
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# ssl_prefer_server_ciphers off;
#
# # 其他配置同HTTP服务器...
# }
}