密钥写死,处理报错
This commit is contained in:
306
.github/workflows/ci-cd.yml
vendored
Normal file
306
.github/workflows/ci-cd.yml
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
name: Flask 提示词大师 - CI/CD 流水线
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: '3.12'
|
||||
FLASK_ENV: testing
|
||||
|
||||
jobs:
|
||||
# 代码质量检查
|
||||
code-quality:
|
||||
name: 代码质量检查
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置Python环境
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install flake8 black isort mypy
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: 代码格式检查
|
||||
run: |
|
||||
echo "检查代码格式..."
|
||||
black --check --diff .
|
||||
isort --check-only --diff .
|
||||
|
||||
- name: 代码质量检查
|
||||
run: |
|
||||
echo "运行Flake8检查..."
|
||||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||
|
||||
- name: 类型检查
|
||||
run: |
|
||||
echo "运行类型检查..."
|
||||
mypy src/ --ignore-missing-imports
|
||||
|
||||
# 单元测试
|
||||
test:
|
||||
name: 单元测试
|
||||
runs-on: ubuntu-latest
|
||||
needs: code-quality
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: test123456
|
||||
MYSQL_DATABASE: test_db
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置Python环境
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip install pytest pytest-cov pytest-mock
|
||||
|
||||
- name: 创建测试环境变量
|
||||
run: |
|
||||
echo "FLASK_ENV=testing" >> $GITHUB_ENV
|
||||
echo "DATABASE_URL=mysql+pymysql://root:test123456@localhost:3306/test_db?charset=utf8mb4" >> $GITHUB_ENV
|
||||
echo "SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV
|
||||
echo "LLM_API_KEY=test-api-key" >> $GITHUB_ENV
|
||||
|
||||
- name: 等待数据库就绪
|
||||
run: |
|
||||
echo "等待MySQL数据库启动..."
|
||||
sleep 30
|
||||
|
||||
- name: 运行单元测试
|
||||
run: |
|
||||
echo "运行单元测试..."
|
||||
pytest tests/ -v --cov=src --cov-report=xml --cov-report=html
|
||||
|
||||
- name: 上传测试覆盖率报告
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage.xml
|
||||
flags: unittests
|
||||
name: codecov-umbrella
|
||||
|
||||
# 集成测试
|
||||
integration-test:
|
||||
name: 集成测试
|
||||
runs-on: ubuntu-latest
|
||||
needs: test
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: test123456
|
||||
MYSQL_DATABASE: test_db
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置Python环境
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: 安装依赖
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: 创建测试环境变量
|
||||
run: |
|
||||
echo "FLASK_ENV=testing" >> $GITHUB_ENV
|
||||
echo "DATABASE_URL=mysql+pymysql://root:test123456@localhost:3306/test_db?charset=utf8mb4" >> $GITHUB_ENV
|
||||
echo "SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV
|
||||
echo "LLM_API_KEY=test-api-key" >> $GITHUB_ENV
|
||||
|
||||
- name: 等待数据库就绪
|
||||
run: |
|
||||
echo "等待MySQL数据库启动..."
|
||||
sleep 30
|
||||
|
||||
- name: 启动应用进行集成测试
|
||||
run: |
|
||||
echo "启动应用进行集成测试..."
|
||||
python run_dev.py &
|
||||
sleep 10
|
||||
|
||||
- name: 运行集成测试
|
||||
run: |
|
||||
echo "运行集成测试..."
|
||||
python -c "
|
||||
import requests
|
||||
import time
|
||||
|
||||
# 等待应用启动
|
||||
time.sleep(5)
|
||||
|
||||
# 测试健康检查
|
||||
response = requests.get('http://localhost:5000/health')
|
||||
assert response.status_code == 200
|
||||
print('健康检查通过')
|
||||
|
||||
# 测试主页
|
||||
response = requests.get('http://localhost:5000/')
|
||||
assert response.status_code == 200
|
||||
print('主页访问通过')
|
||||
|
||||
# 测试API端点
|
||||
response = requests.post('http://localhost:5000/api/wx/templates/intent',
|
||||
json={'text': '测试文本'})
|
||||
assert response.status_code == 200
|
||||
print('API测试通过')
|
||||
"
|
||||
|
||||
# 构建Docker镜像
|
||||
build:
|
||||
name: 构建Docker镜像
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test, integration-test]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: 登录Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: 构建并推送Docker镜像
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_USERNAME }}/flask-prompt-master:latest
|
||||
${{ secrets.DOCKER_USERNAME }}/flask-prompt-master:${{ github.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# 部署到测试环境
|
||||
deploy-test:
|
||||
name: 部署到测试环境
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/develop'
|
||||
environment: test
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 部署到测试服务器
|
||||
run: |
|
||||
echo "部署到测试环境..."
|
||||
# 这里可以添加部署到测试服务器的脚本
|
||||
# 例如:使用SSH连接到测试服务器并更新应用
|
||||
|
||||
- name: 运行部署后测试
|
||||
run: |
|
||||
echo "运行部署后测试..."
|
||||
# 等待应用启动
|
||||
sleep 30
|
||||
|
||||
# 测试应用是否正常运行
|
||||
curl -f http://test-server:5000/health || exit 1
|
||||
|
||||
# 部署到生产环境
|
||||
deploy-production:
|
||||
name: 部署到生产环境
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
environment: production
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 部署到生产服务器
|
||||
run: |
|
||||
echo "部署到生产环境..."
|
||||
# 这里可以添加部署到生产服务器的脚本
|
||||
# 例如:使用SSH连接到生产服务器并更新应用
|
||||
|
||||
- name: 运行部署后测试
|
||||
run: |
|
||||
echo "运行部署后测试..."
|
||||
# 等待应用启动
|
||||
sleep 30
|
||||
|
||||
# 测试应用是否正常运行
|
||||
curl -f https://production-server/health || exit 1
|
||||
|
||||
- name: 发送部署通知
|
||||
run: |
|
||||
echo "部署完成,发送通知..."
|
||||
# 这里可以添加发送通知的逻辑
|
||||
# 例如:发送邮件、Slack消息等
|
||||
|
||||
# 监控系统部署
|
||||
deploy-monitoring:
|
||||
name: 部署监控系统
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy-production
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 部署监控系统
|
||||
run: |
|
||||
echo "部署监控系统..."
|
||||
# 部署监控脚本到服务器
|
||||
# 配置定时任务
|
||||
# 启动监控服务
|
||||
|
||||
- name: 验证监控系统
|
||||
run: |
|
||||
echo "验证监控系统..."
|
||||
# 检查监控系统是否正常运行
|
||||
# 测试监控脚本功能
|
||||
26
Dockerfile.log-manager
Normal file
26
Dockerfile.log-manager
Normal file
@@ -0,0 +1,26 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 复制日志管理相关文件
|
||||
COPY log_manager.py .
|
||||
COPY requirements.txt .
|
||||
|
||||
# 安装Python依赖
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 创建日志目录
|
||||
RUN mkdir -p /app/logs
|
||||
|
||||
# 设置环境变量
|
||||
ENV PYTHONPATH=/app
|
||||
|
||||
# 创建定时任务
|
||||
RUN echo "0 2 * * * cd /app && python log_manager.py" > /etc/cron.d/log-maintenance
|
||||
|
||||
# 安装cron
|
||||
RUN apt-get update && apt-get install -y cron && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 启动cron和日志管理
|
||||
CMD ["sh", "-c", "cron && python log_manager.py"]
|
||||
33
Dockerfile.monitor
Normal file
33
Dockerfile.monitor
Normal file
@@ -0,0 +1,33 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 安装系统依赖
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制监控相关文件
|
||||
COPY simple_monitor.py .
|
||||
COPY log_manager.py .
|
||||
COPY monitor_manager.py .
|
||||
COPY requirements.txt .
|
||||
|
||||
# 安装Python依赖
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 创建日志目录
|
||||
RUN mkdir -p /app/logs
|
||||
|
||||
# 设置环境变量
|
||||
ENV PYTHONPATH=/app
|
||||
ENV APP_URL=http://app:5000
|
||||
ENV MONITOR_INTERVAL=30
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD python -c "import requests; requests.get('$APP_URL/health')" || exit 1
|
||||
|
||||
# 启动监控服务
|
||||
CMD ["python", "simple_monitor.py"]
|
||||
@@ -22,22 +22,12 @@ class Config:
|
||||
}
|
||||
|
||||
# OpenAI兼容API配置
|
||||
LLM_API_URL = os.environ.get('LLM_API_URL')
|
||||
if not LLM_API_URL:
|
||||
raise ValueError("LLM_API_URL 环境变量未设置")
|
||||
|
||||
LLM_API_KEY = os.environ.get('LLM_API_KEY')
|
||||
if not LLM_API_KEY:
|
||||
raise ValueError("LLM_API_KEY 环境变量未设置")
|
||||
|
||||
LLM_API_URL = os.environ.get('LLM_API_URL') or 'https://api.deepseek.com/v1'
|
||||
LLM_API_KEY = os.environ.get('LLM_API_KEY') or 'sk-your-api-key-here'
|
||||
|
||||
# 微信小程序配置
|
||||
WX_APPID = os.environ.get('WX_APPID')
|
||||
if not WX_APPID:
|
||||
raise ValueError("WX_APPID 环境变量未设置")
|
||||
|
||||
WX_SECRET = os.environ.get('WX_SECRET')
|
||||
if not WX_SECRET:
|
||||
raise ValueError("WX_SECRET 环境变量未设置")
|
||||
WX_APPID = os.environ.get('WX_APPID') or 'wx-your-appid-here'
|
||||
WX_SECRET = os.environ.get('WX_SECRET') or 'your-wx-secret-here'
|
||||
|
||||
# 跨域配置
|
||||
CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',')
|
||||
|
||||
139
docker-compose.prod.yml
Normal file
139
docker-compose.prod.yml
Normal file
@@ -0,0 +1,139 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Flask应用服务
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: flask-prompt-master:latest
|
||||
container_name: flask-prompt-master-app
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- FLASK_ENV=production
|
||||
- DATABASE_URL=mysql+pymysql://root:${MYSQL_ROOT_PASSWORD}@mysql:3306/${MYSQL_DATABASE}?charset=utf8mb4
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
- LLM_API_KEY=${LLM_API_KEY}
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
- ./uploads:/app/uploads
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# MySQL数据库
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: flask-prompt-master-mysql
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||
- MYSQL_USER=${MYSQL_USER}
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# Redis缓存
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: flask-prompt-master-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# Nginx反向代理
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: flask-prompt-master-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./docker/nginx/ssl:/etc/nginx/ssl
|
||||
- ./logs/nginx:/var/log/nginx
|
||||
depends_on:
|
||||
- app
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# 监控服务
|
||||
monitor:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.monitor
|
||||
image: flask-prompt-master-monitor:latest
|
||||
container_name: flask-prompt-master-monitor
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- APP_URL=http://app:5000
|
||||
- MONITOR_INTERVAL=30
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
- app
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import requests; requests.get('http://app:5000/health')"]
|
||||
interval: 60s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# 日志管理服务
|
||||
log-manager:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.log-manager
|
||||
image: flask-prompt-master-log-manager:latest
|
||||
container_name: flask-prompt-master-log-manager
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- app-network
|
||||
command: ["python", "log_manager.py"]
|
||||
profiles:
|
||||
- maintenance
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
194
docs/development/自动化部署指南.md
Normal file
194
docs/development/自动化部署指南.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Flask 提示词大师 - 自动化部署指南
|
||||
|
||||
## 概述
|
||||
|
||||
本文档介绍Flask提示词大师项目的自动化部署流程,包括CI/CD流水线、Docker部署、Kubernetes部署等。
|
||||
|
||||
## CI/CD流水线
|
||||
|
||||
### GitHub Actions配置
|
||||
|
||||
配置文件: `.github/workflows/ci-cd.yml`
|
||||
|
||||
#### 主要阶段:
|
||||
1. **代码质量检查** - Flake8, Black, MyPy
|
||||
2. **单元测试** - pytest + 覆盖率
|
||||
3. **集成测试** - 完整功能测试
|
||||
4. **构建镜像** - Docker镜像构建
|
||||
5. **部署** - 测试/生产环境部署
|
||||
|
||||
### 环境变量配置
|
||||
|
||||
在GitHub Secrets中配置:
|
||||
```bash
|
||||
DOCKER_USERNAME=your-docker-username
|
||||
DOCKER_PASSWORD=your-docker-password
|
||||
SSH_PRIVATE_KEY=your-ssh-key
|
||||
SSH_HOST=your-server-host
|
||||
```
|
||||
|
||||
## Docker部署
|
||||
|
||||
### Docker Compose配置
|
||||
|
||||
文件: `docker-compose.prod.yml`
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 查看状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f app
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
创建`.env`文件:
|
||||
```bash
|
||||
MYSQL_ROOT_PASSWORD=your-password
|
||||
MYSQL_DATABASE=flask_prompt_master
|
||||
SECRET_KEY=your-secret-key
|
||||
LLM_API_KEY=your-api-key
|
||||
```
|
||||
|
||||
## Kubernetes部署
|
||||
|
||||
### 部署步骤
|
||||
|
||||
```bash
|
||||
# 创建命名空间
|
||||
kubectl create namespace flask-prompt-master
|
||||
|
||||
# 创建密钥
|
||||
kubectl create secret generic flask-secrets \
|
||||
--from-literal=secret-key="your-secret" \
|
||||
--from-literal=llm-api-key="your-api-key" \
|
||||
-n flask-prompt-master
|
||||
|
||||
# 部署应用
|
||||
kubectl apply -f k8s/deployment.yaml -n flask-prompt-master
|
||||
|
||||
# 部署监控
|
||||
kubectl apply -f k8s/monitoring.yaml -n flask-prompt-master
|
||||
```
|
||||
|
||||
## 传统服务器部署
|
||||
|
||||
### 自动化脚本
|
||||
|
||||
脚本: `scripts/deploy.sh`
|
||||
|
||||
```bash
|
||||
# 部署到测试环境
|
||||
./scripts/deploy.sh -e test -s test.example.com -u deploy -k ~/.ssh/id_rsa
|
||||
|
||||
# 部署到生产环境
|
||||
./scripts/deploy.sh -e production -s prod.example.com -u deploy -k ~/.ssh/id_rsa
|
||||
```
|
||||
|
||||
### 部署流程
|
||||
|
||||
1. **准备部署包** - 清理文件,创建压缩包
|
||||
2. **上传服务器** - SCP上传,执行远程脚本
|
||||
3. **服务管理** - 停止旧服务,安装新版本
|
||||
4. **验证部署** - 健康检查,功能测试
|
||||
|
||||
## 监控系统集成
|
||||
|
||||
### CI/CD中的监控
|
||||
|
||||
监控系统在应用部署后自动部署:
|
||||
- 部署监控脚本
|
||||
- 配置定时任务
|
||||
- 启动监控服务
|
||||
|
||||
### Docker中的监控
|
||||
|
||||
监控服务作为独立容器运行:
|
||||
```yaml
|
||||
monitor:
|
||||
image: flask-prompt-master-monitor:latest
|
||||
environment:
|
||||
- APP_URL=http://app:5000
|
||||
- MONITOR_INTERVAL=30
|
||||
```
|
||||
|
||||
### Kubernetes中的监控
|
||||
|
||||
通过Deployment和CronJob管理:
|
||||
```yaml
|
||||
# 监控服务
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: flask-monitor
|
||||
|
||||
# 日志维护
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: log-maintenance
|
||||
spec:
|
||||
schedule: "0 2 * * *"
|
||||
```
|
||||
|
||||
## 部署验证
|
||||
|
||||
### 健康检查
|
||||
|
||||
```bash
|
||||
# 应用健康检查
|
||||
curl -f http://your-server/health
|
||||
|
||||
# 监控服务检查
|
||||
curl -f http://your-server:8080/health
|
||||
```
|
||||
|
||||
### 功能测试
|
||||
|
||||
```bash
|
||||
# 测试API
|
||||
curl -X POST http://your-server/api/wx/templates/intent \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "测试文本"}'
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **部署失败** - 检查SSH连接和权限
|
||||
2. **服务启动失败** - 检查环境变量配置
|
||||
3. **数据库连接失败** - 检查数据库服务状态
|
||||
|
||||
### 日志查看
|
||||
|
||||
```bash
|
||||
# Docker日志
|
||||
docker-compose logs -f app
|
||||
|
||||
# Kubernetes日志
|
||||
kubectl logs -f deployment/flask-prompt-master
|
||||
|
||||
# 系统日志
|
||||
journalctl -u flask-prompt-master -f
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **蓝绿部署** - 减少停机时间
|
||||
2. **健康检查** - 确保服务可用性
|
||||
3. **监控告警** - 及时发现问题
|
||||
4. **安全配置** - 使用密钥管理
|
||||
5. **资源限制** - 设置CPU/内存限制
|
||||
|
||||
## 总结
|
||||
|
||||
通过自动化部署系统,您可以:
|
||||
- 实现代码到生产的快速部署
|
||||
- 确保部署的一致性和可靠性
|
||||
- 集成完整的监控和日志管理
|
||||
- 支持多种部署环境和方式
|
||||
129
k8s/deployment.yaml
Normal file
129
k8s/deployment.yaml
Normal file
@@ -0,0 +1,129 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: flask-prompt-master
|
||||
labels:
|
||||
app: flask-prompt-master
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: flask-prompt-master
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: flask-prompt-master
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: flask-prompt-master:latest
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
env:
|
||||
- name: FLASK_ENV
|
||||
value: "production"
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flask-secrets
|
||||
key: database-url
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flask-secrets
|
||||
key: secret-key
|
||||
- name: LLM_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flask-secrets
|
||||
key: llm-api-key
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 5000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 5000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
volumeMounts:
|
||||
- name: logs
|
||||
mountPath: /app/logs
|
||||
- name: uploads
|
||||
mountPath: /app/uploads
|
||||
volumes:
|
||||
- name: logs
|
||||
persistentVolumeClaim:
|
||||
claimName: logs-pvc
|
||||
- name: uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: uploads-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: flask-prompt-master-service
|
||||
spec:
|
||||
selector:
|
||||
app: flask-prompt-master
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 5000
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: flask-prompt-master-ingress
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- flask-prompt-master.example.com
|
||||
secretName: flask-prompt-master-tls
|
||||
rules:
|
||||
- host: flask-prompt-master.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: flask-prompt-master-service
|
||||
port:
|
||||
number: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: logs-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: uploads-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
113
k8s/monitoring.yaml
Normal file
113
k8s/monitoring.yaml
Normal file
@@ -0,0 +1,113 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: flask-monitor
|
||||
labels:
|
||||
app: flask-monitor
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: flask-monitor
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: flask-monitor
|
||||
spec:
|
||||
containers:
|
||||
- name: monitor
|
||||
image: flask-prompt-master-monitor:latest
|
||||
env:
|
||||
- name: APP_URL
|
||||
value: "http://flask-prompt-master-service:80"
|
||||
- name: MONITOR_INTERVAL
|
||||
value: "30"
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "200m"
|
||||
volumeMounts:
|
||||
- name: logs
|
||||
mountPath: /app/logs
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- python
|
||||
- -c
|
||||
- "import requests; requests.get('$APP_URL/health')"
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 60
|
||||
volumes:
|
||||
- name: logs
|
||||
persistentVolumeClaim:
|
||||
claimName: logs-pvc
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: flask-log-manager
|
||||
labels:
|
||||
app: flask-log-manager
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: flask-log-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: flask-log-manager
|
||||
spec:
|
||||
containers:
|
||||
- name: log-manager
|
||||
image: flask-prompt-master-log-manager:latest
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
volumeMounts:
|
||||
- name: logs
|
||||
mountPath: /app/logs
|
||||
volumes:
|
||||
- name: logs
|
||||
persistentVolumeClaim:
|
||||
claimName: logs-pvc
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: log-maintenance
|
||||
spec:
|
||||
schedule: "0 2 * * *" # 每天凌晨2点执行
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: log-maintenance
|
||||
image: flask-prompt-master-log-manager:latest
|
||||
command: ["python", "log_manager.py"]
|
||||
volumeMounts:
|
||||
- name: logs
|
||||
mountPath: /app/logs
|
||||
volumes:
|
||||
- name: logs
|
||||
persistentVolumeClaim:
|
||||
claimName: logs-pvc
|
||||
restartPolicy: OnFailure
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: monitor-config
|
||||
data:
|
||||
monitor-interval: "30"
|
||||
alert-threshold: "2.0"
|
||||
retention-days: "30"
|
||||
max-file-size: "10485760" # 10MB
|
||||
358
scripts/deploy.sh
Normal file
358
scripts/deploy.sh
Normal file
@@ -0,0 +1,358 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Flask 提示词大师 - 自动化部署脚本
|
||||
# 支持测试环境和生产环境部署
|
||||
|
||||
set -e # 遇到错误立即退出
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo "Flask 提示词大师 - 自动化部署脚本"
|
||||
echo ""
|
||||
echo "用法: $0 [选项]"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " -e, --environment ENV 部署环境 (test|production)"
|
||||
echo " -s, --server SERVER 服务器地址"
|
||||
echo " -u, --user USER 用户名"
|
||||
echo " -k, --key KEY_PATH SSH密钥路径"
|
||||
echo " -b, --branch BRANCH 代码分支 (默认: main)"
|
||||
echo " -c, --config CONFIG 配置文件路径"
|
||||
echo " -h, --help 显示此帮助信息"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 -e test -s test.example.com -u deploy -k ~/.ssh/id_rsa"
|
||||
echo " $0 -e production -s prod.example.com -u deploy -k ~/.ssh/id_rsa"
|
||||
}
|
||||
|
||||
# 解析命令行参数
|
||||
parse_args() {
|
||||
ENVIRONMENT=""
|
||||
SERVER=""
|
||||
USER=""
|
||||
KEY_PATH=""
|
||||
BRANCH="main"
|
||||
CONFIG_PATH=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-e|--environment)
|
||||
ENVIRONMENT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-s|--server)
|
||||
SERVER="$2"
|
||||
shift 2
|
||||
;;
|
||||
-u|--user)
|
||||
USER="$2"
|
||||
shift 2
|
||||
;;
|
||||
-k|--key)
|
||||
KEY_PATH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-b|--branch)
|
||||
BRANCH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-c|--config)
|
||||
CONFIG_PATH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "未知参数: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 验证必需参数
|
||||
if [[ -z "$ENVIRONMENT" ]]; then
|
||||
log_error "请指定部署环境 (-e 或 --environment)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$SERVER" ]]; then
|
||||
log_error "请指定服务器地址 (-s 或 --server)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$USER" ]]; then
|
||||
log_error "请指定用户名 (-u 或 --user)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查依赖
|
||||
check_dependencies() {
|
||||
log_info "检查部署依赖..."
|
||||
|
||||
# 检查SSH
|
||||
if ! command -v ssh &> /dev/null; then
|
||||
log_error "SSH 未安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_warning "Docker 未安装,将使用传统部署方式"
|
||||
fi
|
||||
|
||||
# 检查Git
|
||||
if ! command -v git &> /dev/null; then
|
||||
log_error "Git 未安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "依赖检查完成"
|
||||
}
|
||||
|
||||
# 准备部署包
|
||||
prepare_deployment() {
|
||||
log_info "准备部署包..."
|
||||
|
||||
# 创建临时目录
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
DEPLOY_DIR="$TEMP_DIR/flask-prompt-master"
|
||||
|
||||
# 复制项目文件
|
||||
cp -r . "$DEPLOY_DIR"
|
||||
|
||||
# 清理不需要的文件
|
||||
cd "$DEPLOY_DIR"
|
||||
rm -rf .git .github .venv __pycache__ *.pyc .pytest_cache
|
||||
|
||||
# 创建部署包
|
||||
tar -czf "../flask-prompt-master-$ENVIRONMENT.tar.gz" .
|
||||
|
||||
log_success "部署包准备完成: flask-prompt-master-$ENVIRONMENT.tar.gz"
|
||||
}
|
||||
|
||||
# 部署到服务器
|
||||
deploy_to_server() {
|
||||
log_info "开始部署到服务器: $SERVER"
|
||||
|
||||
# 构建SSH命令
|
||||
SSH_CMD="ssh"
|
||||
if [[ -n "$KEY_PATH" ]]; then
|
||||
SSH_CMD="$SSH_CMD -i $KEY_PATH"
|
||||
fi
|
||||
SSH_CMD="$SSH_CMD -o StrictHostKeyChecking=no $USER@$SERVER"
|
||||
|
||||
# 创建远程部署脚本
|
||||
cat > remote_deploy.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# 远程部署脚本
|
||||
ENVIRONMENT="$1"
|
||||
DEPLOY_PATH="/opt/flask-prompt-master"
|
||||
BACKUP_PATH="/opt/backups/flask-prompt-master"
|
||||
|
||||
echo "开始远程部署..."
|
||||
|
||||
# 创建备份
|
||||
if [ -d "$DEPLOY_PATH" ]; then
|
||||
echo "创建备份..."
|
||||
mkdir -p "$BACKUP_PATH"
|
||||
cp -r "$DEPLOY_PATH" "$BACKUP_PATH/$(date +%Y%m%d_%H%M%S)"
|
||||
fi
|
||||
|
||||
# 停止现有服务
|
||||
echo "停止现有服务..."
|
||||
if systemctl is-active --quiet flask-prompt-master; then
|
||||
systemctl stop flask-prompt-master
|
||||
fi
|
||||
|
||||
# 清理旧文件
|
||||
echo "清理旧文件..."
|
||||
rm -rf "$DEPLOY_PATH"
|
||||
|
||||
# 解压新文件
|
||||
echo "解压新文件..."
|
||||
mkdir -p "$DEPLOY_PATH"
|
||||
tar -xzf flask-prompt-master.tar.gz -C "$DEPLOY_PATH"
|
||||
|
||||
# 设置权限
|
||||
echo "设置权限..."
|
||||
chown -R www-data:www-data "$DEPLOY_PATH"
|
||||
chmod +x "$DEPLOY_PATH"/*.sh
|
||||
|
||||
# 安装依赖
|
||||
echo "安装依赖..."
|
||||
cd "$DEPLOY_PATH"
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 配置环境
|
||||
echo "配置环境..."
|
||||
if [ "$ENVIRONMENT" = "production" ]; then
|
||||
cp env.production .env
|
||||
else
|
||||
cp env.test .env
|
||||
fi
|
||||
|
||||
# 数据库迁移
|
||||
echo "执行数据库迁移..."
|
||||
flask db upgrade
|
||||
|
||||
# 启动服务
|
||||
echo "启动服务..."
|
||||
systemctl start flask-prompt-master
|
||||
systemctl enable flask-prompt-master
|
||||
|
||||
# 部署监控系统
|
||||
echo "部署监控系统..."
|
||||
if [ -f "simple_monitor.py" ]; then
|
||||
# 创建监控服务
|
||||
cat > /etc/systemd/system/flask-monitor.service << 'MONITOR_EOF'
|
||||
[Unit]
|
||||
Description=Flask Prompt Master Monitor
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
WorkingDirectory=/opt/flask-prompt-master
|
||||
ExecStart=/opt/flask-prompt-master/venv/bin/python simple_monitor.py
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
MONITOR_EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable flask-monitor
|
||||
systemctl start flask-monitor
|
||||
fi
|
||||
|
||||
echo "部署完成!"
|
||||
EOF
|
||||
|
||||
# 上传文件到服务器
|
||||
log_info "上传部署包到服务器..."
|
||||
scp -i "$KEY_PATH" -o StrictHostKeyChecking=no \
|
||||
"flask-prompt-master-$ENVIRONMENT.tar.gz" \
|
||||
"remote_deploy.sh" \
|
||||
"$USER@$SERVER:/tmp/"
|
||||
|
||||
# 执行远程部署
|
||||
log_info "执行远程部署..."
|
||||
$SSH_CMD "chmod +x /tmp/remote_deploy.sh && /tmp/remote_deploy.sh $ENVIRONMENT"
|
||||
|
||||
log_success "部署完成"
|
||||
}
|
||||
|
||||
# 验证部署
|
||||
verify_deployment() {
|
||||
log_info "验证部署..."
|
||||
|
||||
# 等待服务启动
|
||||
sleep 10
|
||||
|
||||
# 测试健康检查
|
||||
HEALTH_URL="http://$SERVER/health"
|
||||
if [[ "$ENVIRONMENT" = "production" ]]; then
|
||||
HEALTH_URL="https://$SERVER/health"
|
||||
fi
|
||||
|
||||
for i in {1..30}; do
|
||||
if curl -f "$HEALTH_URL" > /dev/null 2>&1; then
|
||||
log_success "服务健康检查通过"
|
||||
break
|
||||
else
|
||||
log_warning "等待服务启动... ($i/30)"
|
||||
sleep 2
|
||||
fi
|
||||
done
|
||||
|
||||
if ! curl -f "$HEALTH_URL" > /dev/null 2>&1; then
|
||||
log_error "服务健康检查失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 测试主要功能
|
||||
log_info "测试主要功能..."
|
||||
|
||||
# 测试主页
|
||||
if curl -f "http://$SERVER/" > /dev/null 2>&1; then
|
||||
log_success "主页访问正常"
|
||||
else
|
||||
log_error "主页访问失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 测试API
|
||||
API_RESPONSE=$(curl -s -X POST "http://$SERVER/api/wx/templates/intent" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "测试文本"}')
|
||||
|
||||
if echo "$API_RESPONSE" | grep -q "code.*200"; then
|
||||
log_success "API功能正常"
|
||||
else
|
||||
log_error "API功能异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "部署验证完成"
|
||||
}
|
||||
|
||||
# 清理临时文件
|
||||
cleanup() {
|
||||
log_info "清理临时文件..."
|
||||
rm -rf "$TEMP_DIR"
|
||||
rm -f remote_deploy.sh
|
||||
log_success "清理完成"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
log_info "开始自动化部署..."
|
||||
|
||||
parse_args "$@"
|
||||
check_dependencies
|
||||
prepare_deployment
|
||||
deploy_to_server
|
||||
verify_deployment
|
||||
cleanup
|
||||
|
||||
log_success "自动化部署完成!"
|
||||
log_info "应用地址: http://$SERVER"
|
||||
log_info "健康检查: http://$SERVER/health"
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
@@ -3,39 +3,21 @@ from openai import OpenAI
|
||||
from src.flask_prompt_master import db
|
||||
from src.flask_prompt_master.models import User, Prompt, Feedback, PromptTemplate, WxUser
|
||||
from src.flask_prompt_master.forms import PromptForm, FeedbackForm
|
||||
from src.flask_prompt_master.config import Config
|
||||
import pymysql
|
||||
from datetime import datetime
|
||||
import requests
|
||||
import hashlib
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
|
||||
main_bp = Blueprint('main', __name__)
|
||||
|
||||
@main_bp.route('/health')
|
||||
def health_check():
|
||||
"""健康检查接口"""
|
||||
return jsonify({
|
||||
'status': 'healthy',
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'environment': os.environ.get('FLASK_ENV', 'unknown')
|
||||
})
|
||||
client = OpenAI(api_key='sk-fdf7cc1c73504e628ec0119b7e11b8cc', base_url='https://api.deepseek.com/v1')
|
||||
|
||||
# 使用current_app获取配置,而不是直接导入
|
||||
def get_openai_client():
|
||||
"""获取OpenAI客户端实例"""
|
||||
return OpenAI(
|
||||
api_key=current_app.config['LLM_API_KEY'],
|
||||
base_url=current_app.config['LLM_API_URL']
|
||||
)
|
||||
|
||||
def get_wx_config():
|
||||
"""获取微信小程序配置"""
|
||||
return {
|
||||
'appid': current_app.config['WX_APPID'],
|
||||
'secret': current_app.config['WX_SECRET']
|
||||
}
|
||||
# 从配置中获取微信小程序配置
|
||||
WX_APPID = Config.WX_APPID
|
||||
WX_SECRET = Config.WX_SECRET
|
||||
|
||||
def get_system_prompt(template_id=None):
|
||||
"""获取系统提示词模板"""
|
||||
@@ -66,9 +48,6 @@ def generate_with_llm(input_text, template_id=None):
|
||||
try:
|
||||
system_prompt = get_system_prompt(template_id)
|
||||
|
||||
# 获取OpenAI客户端
|
||||
client = get_openai_client()
|
||||
|
||||
# 打印参数
|
||||
print("\n=== API 调用参数 ===")
|
||||
print(f"模板ID: {template_id}")
|
||||
@@ -76,35 +55,6 @@ def generate_with_llm(input_text, template_id=None):
|
||||
print(f"系统提示: {system_prompt}")
|
||||
print("==================\n")
|
||||
|
||||
# 开发环境模拟API响应(当API密钥无效时)
|
||||
api_key = current_app.config.get('LLM_API_KEY', '')
|
||||
print(f"\n=== 当前API密钥: {api_key} ===")
|
||||
|
||||
if api_key in ['test-api-key', 'your-actual-api-key-here', 'sk-your-api-key-here'] or 'test' in api_key.lower() or 'your-api-key' in api_key.lower():
|
||||
# 模拟API响应
|
||||
mock_responses = {
|
||||
"写一篇关于python的文章": "请帮我写一篇关于Python编程语言的技术文章,要求:\n1. 介绍Python的基本特性和优势\n2. 包含实际代码示例\n3. 适合初学者阅读\n4. 字数在1000-1500字之间\n5. 结构清晰,逻辑性强",
|
||||
"python代码优化": "请帮我优化以下Python代码,要求:\n1. 提高代码执行效率\n2. 改善代码可读性\n3. 遵循Python编码规范\n4. 添加必要的注释\n5. 考虑内存使用优化",
|
||||
"python程序优化": "请帮我优化Python程序,要求:\n1. 分析程序性能瓶颈\n2. 提供优化建议\n3. 展示优化前后对比\n4. 考虑不同场景的优化策略\n5. 提供可执行的优化代码"
|
||||
}
|
||||
|
||||
# 根据输入文本返回相应的模拟响应
|
||||
for key, value in mock_responses.items():
|
||||
if key in input_text:
|
||||
generated_text = value
|
||||
print("\n=== 模拟API响应结果 ===")
|
||||
print(f"生成的提示词: {generated_text}")
|
||||
print("==================\n")
|
||||
return generated_text
|
||||
|
||||
# 默认模拟响应
|
||||
generated_text = f"请帮我{input_text},要求:\n1. 内容专业且实用\n2. 结构清晰,逻辑性强\n3. 包含具体示例\n4. 适合目标受众\n5. 符合行业标准"
|
||||
print("\n=== 模拟API响应结果 ===")
|
||||
print(f"生成的提示词: {generated_text}")
|
||||
print("==================\n")
|
||||
return generated_text
|
||||
|
||||
# 真实API调用
|
||||
response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
@@ -399,13 +349,10 @@ def wx_get_template_detail(template_id):
|
||||
def wx_login():
|
||||
"""微信小程序登录接口"""
|
||||
try:
|
||||
# 获取微信小程序配置
|
||||
wx_config = get_wx_config()
|
||||
|
||||
# 添加调试日志
|
||||
print("\n=== 微信登录配置 ===")
|
||||
print(f"APPID: {wx_config['appid']}")
|
||||
print(f"SECRET: {wx_config['secret']}")
|
||||
print(f"APPID: {WX_APPID}")
|
||||
print(f"SECRET: {WX_SECRET}")
|
||||
print("==================\n")
|
||||
|
||||
data = request.get_json()
|
||||
@@ -422,8 +369,8 @@ def wx_login():
|
||||
# 请求微信接口
|
||||
wx_url = 'https://api.weixin.qq.com/sns/jscode2session'
|
||||
params = {
|
||||
'appid': wx_config['appid'],
|
||||
'secret': wx_config['secret'],
|
||||
'appid': WX_APPID,
|
||||
'secret': WX_SECRET,
|
||||
'js_code': code,
|
||||
'grant_type': 'authorization_code'
|
||||
}
|
||||
@@ -903,54 +850,17 @@ def wx_get_template_by_intent():
|
||||
|
||||
只返回分类名称,不要其他任何内容。"""
|
||||
|
||||
# 开发环境模拟API响应(当API密钥无效时)
|
||||
api_key = current_app.config.get('LLM_API_KEY', '')
|
||||
print(f"\n=== 意图识别API密钥: {api_key} ===")
|
||||
# 调用意图识别
|
||||
response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": intent_system_prompt},
|
||||
{"role": "user", "content": user_input}
|
||||
],
|
||||
temperature=0.1
|
||||
)
|
||||
|
||||
if api_key in ['test-api-key', 'your-actual-api-key-here', 'sk-your-api-key-here'] or 'test' in api_key.lower() or 'your-api-key' in api_key.lower():
|
||||
# 模拟意图识别响应
|
||||
mock_intents = {
|
||||
"写代码": "代码开发",
|
||||
"开发": "代码开发",
|
||||
"编程": "代码开发",
|
||||
"网站": "网站开发",
|
||||
"网页": "网站开发",
|
||||
"设计": "产品设计",
|
||||
"UI": "产品设计",
|
||||
"界面": "产品设计",
|
||||
"图片": "生成图片",
|
||||
"图像": "生成图片",
|
||||
"新闻": "新闻获取",
|
||||
"资讯": "新闻获取",
|
||||
"文案": "文案创作",
|
||||
"营销": "市场营销",
|
||||
"推广": "市场营销",
|
||||
"数据": "数据分析",
|
||||
"分析": "数据分析"
|
||||
}
|
||||
|
||||
# 根据输入文本返回相应的模拟意图
|
||||
for key, value in mock_intents.items():
|
||||
if key in user_input:
|
||||
intent = value
|
||||
print(f"\n=== 模拟意图识别结果: {intent} ===")
|
||||
break
|
||||
else:
|
||||
intent = "其它"
|
||||
print(f"\n=== 模拟意图识别结果: {intent} ===")
|
||||
else:
|
||||
# 真实API调用
|
||||
client = get_openai_client()
|
||||
response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": intent_system_prompt},
|
||||
{"role": "user", "content": user_input}
|
||||
],
|
||||
temperature=0.1
|
||||
)
|
||||
|
||||
intent = response.choices[0].message.content.strip()
|
||||
intent = response.choices[0].message.content.strip()
|
||||
|
||||
# 根据意图获取对应的模板提示词
|
||||
intent_prompts = {
|
||||
@@ -1056,81 +966,17 @@ def wx_generate_expert_prompt():
|
||||
6. 不要添加任何额外的文本"""
|
||||
|
||||
try:
|
||||
# 开发环境模拟API响应(当API密钥无效时)
|
||||
api_key = current_app.config.get('LLM_API_KEY', '')
|
||||
print(f"\n=== 专家意图分析API密钥: {api_key} ===")
|
||||
# 获取意图分析结果
|
||||
intent_response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": intent_analyst_prompt},
|
||||
{"role": "user", "content": user_input}
|
||||
],
|
||||
temperature=0.1 # 降低温度,使输出更确定
|
||||
)
|
||||
|
||||
if api_key in ['test-api-key', 'your-actual-api-key-here', 'sk-your-api-key-here'] or 'test' in api_key.lower() or 'your-api-key' in api_key.lower():
|
||||
# 模拟意图分析响应
|
||||
mock_intent_analysis = {
|
||||
"core_intent": "技术",
|
||||
"domain": "软件开发",
|
||||
"key_requirements": [
|
||||
"功能完整性",
|
||||
"性能优化",
|
||||
"代码质量"
|
||||
],
|
||||
"expected_output": "可执行的代码解决方案",
|
||||
"constraints": [
|
||||
"遵循最佳实践",
|
||||
"考虑可维护性"
|
||||
],
|
||||
"keywords": [
|
||||
"编程",
|
||||
"开发",
|
||||
"技术"
|
||||
]
|
||||
}
|
||||
|
||||
# 根据输入文本调整分析结果
|
||||
print(f"\n=== 输入文本分析: {user_input} ===")
|
||||
|
||||
if any(keyword in user_input for keyword in ["设计", "UI", "界面", "用户体验", "视觉", "交互", "原型", "界面设计", "UI设计"]):
|
||||
mock_intent_analysis["core_intent"] = "创意"
|
||||
mock_intent_analysis["domain"] = "产品设计"
|
||||
mock_intent_analysis["key_requirements"] = ["用户体验", "视觉设计", "交互设计"]
|
||||
mock_intent_analysis["expected_output"] = "设计方案和原型"
|
||||
mock_intent_analysis["keywords"] = ["设计", "UI", "用户体验"]
|
||||
print("=== 匹配到创意类型 ===")
|
||||
elif any(keyword in user_input for keyword in ["分析", "数据", "统计", "报告", "洞察", "趋势", "图表", "可视化", "挖掘"]):
|
||||
mock_intent_analysis["core_intent"] = "分析"
|
||||
mock_intent_analysis["domain"] = "数据分析"
|
||||
mock_intent_analysis["key_requirements"] = ["数据准确性", "分析深度", "洞察价值"]
|
||||
mock_intent_analysis["expected_output"] = "分析报告和建议"
|
||||
mock_intent_analysis["keywords"] = ["分析", "数据", "洞察"]
|
||||
print("=== 匹配到分析类型 ===")
|
||||
elif any(keyword in user_input for keyword in ["咨询", "建议", "方案", "策略", "规划", "优化", "改进", "评估", "诊断"]):
|
||||
mock_intent_analysis["core_intent"] = "咨询"
|
||||
mock_intent_analysis["domain"] = "业务咨询"
|
||||
mock_intent_analysis["key_requirements"] = ["专业建议", "可行性分析", "实施方案"]
|
||||
mock_intent_analysis["expected_output"] = "咨询报告和方案"
|
||||
mock_intent_analysis["keywords"] = ["咨询", "建议", "方案"]
|
||||
print("=== 匹配到咨询类型 ===")
|
||||
elif any(keyword in user_input for keyword in ["代码", "编程", "开发", "技术", "系统", "软件", "应用", "程序", "算法", "架构"]):
|
||||
mock_intent_analysis["core_intent"] = "技术"
|
||||
mock_intent_analysis["domain"] = "软件开发"
|
||||
mock_intent_analysis["key_requirements"] = ["功能完整性", "性能优化", "代码质量"]
|
||||
mock_intent_analysis["expected_output"] = "可执行的代码解决方案"
|
||||
mock_intent_analysis["keywords"] = ["编程", "开发", "技术"]
|
||||
print("=== 匹配到技术类型 ===")
|
||||
else:
|
||||
print("=== 未匹配到特定类型,使用默认技术类型 ===")
|
||||
|
||||
intent_analysis_text = json.dumps(mock_intent_analysis, ensure_ascii=False, indent=2)
|
||||
print(f"\n=== 模拟意图分析结果: {intent_analysis_text} ===")
|
||||
else:
|
||||
# 真实API调用
|
||||
client = get_openai_client()
|
||||
intent_response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": intent_analyst_prompt},
|
||||
{"role": "user", "content": user_input}
|
||||
],
|
||||
temperature=0.1 # 降低温度,使输出更确定
|
||||
)
|
||||
|
||||
intent_analysis_text = intent_response.choices[0].message.content.strip()
|
||||
intent_analysis_text = intent_response.choices[0].message.content.strip()
|
||||
|
||||
# 添加日志记录
|
||||
current_app.logger.info(f"AI返回的意图分析结果: {intent_analysis_text}")
|
||||
@@ -1265,176 +1111,19 @@ def wx_generate_expert_prompt():
|
||||
)
|
||||
|
||||
try:
|
||||
# 开发环境模拟API响应(当API密钥无效时)
|
||||
api_key = current_app.config.get('LLM_API_KEY', '')
|
||||
print(f"\n=== 专家提示词生成API密钥: {api_key} ===")
|
||||
# 生成最终提示词
|
||||
final_response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": expert_prompt.format(
|
||||
analysis=json.dumps(intent_analysis, ensure_ascii=False, indent=2)
|
||||
)},
|
||||
{"role": "user", "content": user_input}
|
||||
],
|
||||
temperature=0.7
|
||||
)
|
||||
|
||||
if api_key in ['test-api-key', 'your-actual-api-key-here', 'sk-your-api-key-here'] or 'test' in api_key.lower() or 'your-api-key' in api_key.lower():
|
||||
# 模拟专家提示词生成响应
|
||||
core_intent = intent_analysis.get('core_intent', '技术')
|
||||
domain = intent_analysis.get('domain', '软件开发')
|
||||
|
||||
mock_expert_prompts = {
|
||||
"技术": f"""基于您的需求,我为您生成一个专业的技术任务提示词:
|
||||
|
||||
**技术背景和上下文:**
|
||||
您需要在{domain}领域完成一项技术任务,需要确保技术方案的可行性和实用性。
|
||||
|
||||
**技术要求和规范:**
|
||||
1. 遵循行业最佳实践和标准
|
||||
2. 确保代码质量和可维护性
|
||||
3. 考虑性能和安全性要求
|
||||
4. 提供完整的实现方案
|
||||
|
||||
**性能和质量标准:**
|
||||
- 代码执行效率优化
|
||||
- 错误处理和异常管理
|
||||
- 文档和注释完整性
|
||||
- 测试覆盖率要求
|
||||
|
||||
**技术约束条件:**
|
||||
- 技术栈兼容性
|
||||
- 资源使用限制
|
||||
- 时间进度要求
|
||||
- 团队协作规范
|
||||
|
||||
**预期交付成果:**
|
||||
- 完整的技术实现方案
|
||||
- 详细的代码示例
|
||||
- 部署和配置说明
|
||||
- 测试验证方案
|
||||
|
||||
**评估标准:**
|
||||
- 功能完整性验证
|
||||
- 性能指标达标
|
||||
- 代码质量审查
|
||||
- 用户体验评估""",
|
||||
|
||||
"创意": f"""基于您的创意需求,我为您生成一个专业的创意设计提示词:
|
||||
|
||||
**创意方向和灵感来源:**
|
||||
在{domain}领域探索创新的设计理念,结合用户需求和市场趋势,创造独特的视觉体验。
|
||||
|
||||
**风格和氛围要求:**
|
||||
1. 现代简约的设计风格
|
||||
2. 温暖友好的用户界面
|
||||
3. 专业可信的品牌形象
|
||||
4. 富有创意的视觉元素
|
||||
|
||||
**目标受众定义:**
|
||||
- 明确用户群体特征
|
||||
- 理解用户行为习惯
|
||||
- 分析用户需求痛点
|
||||
- 设计用户旅程地图
|
||||
|
||||
**设计元素规范:**
|
||||
- 色彩搭配和视觉层次
|
||||
- 字体选择和排版规范
|
||||
- 图标和插画风格
|
||||
- 布局和空间设计
|
||||
|
||||
**创意表现形式:**
|
||||
- 交互设计创新
|
||||
- 动效和过渡效果
|
||||
- 响应式设计适配
|
||||
- 无障碍设计考虑
|
||||
|
||||
**评估标准:**
|
||||
- 视觉吸引力评估
|
||||
- 用户体验测试
|
||||
- 品牌一致性检查
|
||||
- 创新性价值验证""",
|
||||
|
||||
"分析": f"""基于您的分析需求,我为您生成一个专业的数据分析提示词:
|
||||
|
||||
**分析目标和范围:**
|
||||
在{domain}领域进行深入的数据分析,挖掘有价值的信息洞察,为决策提供数据支撑。
|
||||
|
||||
**数据要求和规范:**
|
||||
1. 数据来源的可靠性和完整性
|
||||
2. 数据格式和结构标准化
|
||||
3. 数据清洗和预处理要求
|
||||
4. 数据安全和隐私保护
|
||||
|
||||
**分析方法和工具:**
|
||||
- 统计分析方法和模型选择
|
||||
- 数据可视化工具和技术
|
||||
- 机器学习算法应用
|
||||
- 业务指标和KPI定义
|
||||
|
||||
**输出格式要求:**
|
||||
- 分析报告的结构和内容
|
||||
- 图表和可视化展示
|
||||
- 关键发现和建议总结
|
||||
- 可操作的洞察建议
|
||||
|
||||
**关键指标定义:**
|
||||
- 核心业务指标监控
|
||||
- 趋势分析和预测模型
|
||||
- 异常检测和预警机制
|
||||
- 效果评估和ROI分析
|
||||
|
||||
**质量控制标准:**
|
||||
- 数据准确性验证
|
||||
- 分析逻辑合理性
|
||||
- 结果可解释性
|
||||
- 建议可操作性""",
|
||||
|
||||
"咨询": f"""基于您的咨询需求,我为您生成一个专业的咨询服务提示词:
|
||||
|
||||
**咨询问题界定:**
|
||||
在{domain}领域提供专业的咨询服务,帮助您解决业务挑战,制定有效的解决方案。
|
||||
|
||||
**背景信息要求:**
|
||||
1. 当前业务状况和挑战
|
||||
2. 目标和期望结果
|
||||
3. 资源和约束条件
|
||||
4. 时间进度要求
|
||||
|
||||
**分析框架设定:**
|
||||
- 问题分析和诊断方法
|
||||
- 市场调研和竞争分析
|
||||
- 风险评估和管理策略
|
||||
- 成本效益分析模型
|
||||
|
||||
**建议输出格式:**
|
||||
- 咨询报告的结构和内容
|
||||
- 解决方案的详细说明
|
||||
- 实施计划和里程碑
|
||||
- 预期效果和评估指标
|
||||
|
||||
**实施考虑因素:**
|
||||
- 组织变革管理
|
||||
- 团队培训和能力建设
|
||||
- 技术支持和维护
|
||||
- 持续改进机制
|
||||
|
||||
**效果评估标准:**
|
||||
- 目标达成度评估
|
||||
- 投资回报率分析
|
||||
- 客户满意度调查
|
||||
- 长期价值创造"""
|
||||
}
|
||||
|
||||
generated_prompt = mock_expert_prompts.get(core_intent, mock_expert_prompts["技术"])
|
||||
print(f"\n=== 模拟专家提示词生成结果 ===")
|
||||
print(f"生成的提示词: {generated_prompt[:200]}...")
|
||||
print("==================\n")
|
||||
else:
|
||||
# 真实API调用
|
||||
client = get_openai_client()
|
||||
final_response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{"role": "system", "content": expert_prompt.format(
|
||||
analysis=json.dumps(intent_analysis, ensure_ascii=False, indent=2)
|
||||
)},
|
||||
{"role": "user", "content": user_input}
|
||||
],
|
||||
temperature=0.7
|
||||
)
|
||||
|
||||
generated_prompt = final_response.choices[0].message.content.strip()
|
||||
generated_prompt = final_response.choices[0].message.content.strip()
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"生成提示词失败: {str(e)}")
|
||||
|
||||
108
test_api_fix.py
Normal file
108
test_api_fix.py
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 设置环境变量
|
||||
os.environ['FLASK_ENV'] = 'development'
|
||||
os.environ['SECRET_KEY'] = 'test-secret-key'
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def test_app_creation():
|
||||
"""测试应用创建"""
|
||||
try:
|
||||
from src.flask_prompt_master import create_app
|
||||
app = create_app()
|
||||
print("✅ 应用创建成功")
|
||||
return app
|
||||
except Exception as e:
|
||||
print(f"❌ 应用创建失败: {e}")
|
||||
return None
|
||||
|
||||
def test_config_loading():
|
||||
"""测试配置加载"""
|
||||
try:
|
||||
from src.flask_prompt_master import create_app
|
||||
app = create_app()
|
||||
|
||||
# 检查关键配置
|
||||
configs = [
|
||||
'LLM_API_KEY',
|
||||
'LLM_API_URL',
|
||||
'WX_APPID',
|
||||
'WX_SECRET',
|
||||
'SECRET_KEY'
|
||||
]
|
||||
|
||||
for config_name in configs:
|
||||
value = app.config.get(config_name)
|
||||
print(f"✅ {config_name}: {value}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ 配置加载失败: {e}")
|
||||
return False
|
||||
|
||||
def test_api_generation():
|
||||
"""测试API生成功能"""
|
||||
try:
|
||||
from src.flask_prompt_master import create_app
|
||||
app = create_app()
|
||||
|
||||
with app.app_context():
|
||||
from src.flask_prompt_master.routes.routes import generate_with_llm
|
||||
|
||||
# 测试不同的输入
|
||||
test_inputs = [
|
||||
"写一个产品介绍",
|
||||
"帮我写个邮件",
|
||||
"测试文本",
|
||||
"开发一个网站"
|
||||
]
|
||||
|
||||
for input_text in test_inputs:
|
||||
result = generate_with_llm(input_text)
|
||||
print(f"✅ 输入: {input_text}")
|
||||
print(f" 输出: {result[:100]}...")
|
||||
print()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ API生成测试失败: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""主测试函数"""
|
||||
print("🔧 开始测试API修复...")
|
||||
print("=" * 50)
|
||||
|
||||
# 测试1: 应用创建
|
||||
print("1. 测试应用创建...")
|
||||
app = test_app_creation()
|
||||
if not app:
|
||||
return False
|
||||
|
||||
print()
|
||||
|
||||
# 测试2: 配置加载
|
||||
print("2. 测试配置加载...")
|
||||
if not test_config_loading():
|
||||
return False
|
||||
|
||||
print()
|
||||
|
||||
# 测试3: API生成
|
||||
print("3. 测试API生成功能...")
|
||||
if not test_api_generation():
|
||||
return False
|
||||
|
||||
print("=" * 50)
|
||||
print("🎉 所有测试通过!API修复成功!")
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
success = main()
|
||||
sys.exit(0 if success else 1)
|
||||
Reference in New Issue
Block a user