继续完善
This commit is contained in:
50
InfoGenie-backend/.dockerignore
Normal file
50
InfoGenie-backend/.dockerignore
Normal file
@@ -0,0 +1,50 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
env/
|
||||
venv/
|
||||
.venv/
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.pytest_cache/
|
||||
|
||||
# 环境变量文件
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# 日志文件
|
||||
*.log
|
||||
|
||||
# 测试文件(可选,如果不想包含在镜像中)
|
||||
test/
|
||||
|
||||
# 文档文件(可选)
|
||||
*.md
|
||||
LICENSE
|
||||
|
||||
# 启动脚本(Windows)
|
||||
*.bat
|
||||
|
||||
# 其他临时文件
|
||||
*.tmp
|
||||
.cache/
|
||||
@@ -11,4 +11,4 @@ MAIL_PASSWORD=your-app-password
|
||||
SECRET_KEY=infogenie-production-secret-key-2025
|
||||
|
||||
# 会话安全配置
|
||||
SESSION_COOKIE_SECURE=True
|
||||
HWT_SECURE=True
|
||||
163
InfoGenie-backend/DOCKER_README.md
Normal file
163
InfoGenie-backend/DOCKER_README.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# InfoGenie 后端 Docker 部署指南
|
||||
|
||||
## 项目概述
|
||||
|
||||
InfoGenie 是一个基于 Flask 的 Python 后端应用,提供用户认证、AI 模型应用、小游戏等功能。
|
||||
|
||||
## Docker 部署
|
||||
|
||||
### 前置要求
|
||||
|
||||
- Docker >= 20.0
|
||||
- Docker Compose >= 2.0
|
||||
|
||||
### 快速开始
|
||||
|
||||
1. **克隆项目并进入后端目录**
|
||||
```bash
|
||||
cd InfoGenie-backend
|
||||
```
|
||||
|
||||
2. **设置环境变量**
|
||||
```bash
|
||||
cp .env.example .env # 如果有示例文件
|
||||
# 编辑 .env 文件,设置必要的环境变量
|
||||
```
|
||||
|
||||
3. **构建并运行**
|
||||
```bash
|
||||
# 方法1:使用构建脚本
|
||||
./build_docker.sh
|
||||
|
||||
# 方法2:使用 Docker Compose(推荐)
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 环境变量配置
|
||||
|
||||
在 `.env` 文件中配置以下变量:
|
||||
|
||||
```env
|
||||
# Flask 配置
|
||||
SECRET_KEY=your-secret-key-here
|
||||
FLASK_ENV=production
|
||||
|
||||
# MongoDB 配置
|
||||
MONGO_URI=mongodb://mongodb:27017/InfoGenie
|
||||
|
||||
# 邮件配置
|
||||
MAIL_USERNAME=your-email@qq.com
|
||||
MAIL_PASSWORD=your-app-password
|
||||
|
||||
# AI 配置(可选)
|
||||
# 在 ai_config.json 中配置 AI API 密钥
|
||||
```
|
||||
|
||||
### 服务端口
|
||||
|
||||
- 后端 API: `http://localhost:5002`
|
||||
- MongoDB: `localhost:27017`
|
||||
- 健康检查: `http://localhost:5002/api/health`
|
||||
|
||||
### Docker Compose 命令
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
docker-compose up -d
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f infogenie-backend
|
||||
|
||||
# 停止服务
|
||||
docker-compose down
|
||||
|
||||
# 重建镜像
|
||||
docker-compose build --no-cache
|
||||
|
||||
# 清理数据卷
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
### 单独构建 Docker 镜像
|
||||
|
||||
如果不需要 MongoDB,可以单独构建后端镜像:
|
||||
|
||||
```bash
|
||||
# 构建镜像
|
||||
docker build -t infogenie-backend:latest .
|
||||
|
||||
# 运行容器(需要外部 MongoDB)
|
||||
docker run -d \
|
||||
--name infogenie-backend \
|
||||
-p 5002:5002 \
|
||||
-e MONGO_URI=mongodb://your-mongo-host:27017/InfoGenie \
|
||||
-e SECRET_KEY=your-secret-key \
|
||||
infogenie-backend:latest
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
InfoGenie-backend/
|
||||
├── Dockerfile # Docker 镜像构建文件
|
||||
├── docker-compose.yml # Docker Compose 配置
|
||||
├── build_docker.sh # 构建脚本
|
||||
├── .dockerignore # Docker 忽略文件
|
||||
├── app.py # Flask 应用主入口
|
||||
├── config.py # 应用配置
|
||||
├── requirements.txt # Python 依赖
|
||||
├── ai_config.json # AI 模型配置
|
||||
├── modules/ # 功能模块
|
||||
│ ├── auth.py # 用户认证
|
||||
│ ├── user_management.py # 用户管理
|
||||
│ ├── email_service.py # 邮件服务
|
||||
│ └── aimodelapp.py # AI 模型应用
|
||||
└── test/ # 测试文件
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **安全性**: 生产环境请使用强密码和随机生成的 SECRET_KEY
|
||||
2. **数据库**: 默认使用 MongoDB 6.0,确保数据持久化
|
||||
3. **端口**: 如需修改端口,请同时更新 Dockerfile 和 docker-compose.yml
|
||||
4. **日志**: 应用日志通过 `docker-compose logs` 查看
|
||||
5. **备份**: 重要数据请定期备份 MongoDB 数据卷
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **端口占用**
|
||||
```bash
|
||||
# 检查端口占用
|
||||
lsof -i :5002
|
||||
# 修改端口映射
|
||||
docker-compose up -d --scale infogenie-backend=0
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
2. **数据库连接失败**
|
||||
```bash
|
||||
# 检查 MongoDB 状态
|
||||
docker-compose ps
|
||||
docker-compose logs mongodb
|
||||
```
|
||||
|
||||
3. **构建失败**
|
||||
```bash
|
||||
# 清理缓存重新构建
|
||||
docker system prune -f
|
||||
docker-compose build --no-cache
|
||||
```
|
||||
|
||||
## 开发环境
|
||||
|
||||
本地开发仍可使用原有的 `start_backend.sh` 脚本:
|
||||
|
||||
```bash
|
||||
./start_backend.sh
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目采用 MIT 许可证。
|
||||
32
InfoGenie-backend/Dockerfile
Normal file
32
InfoGenie-backend/Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
||||
# 使用官方Python镜像作为基础镜像
|
||||
FROM python:3.10-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 安装系统依赖(如果需要)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制requirements.txt并安装Python依赖
|
||||
COPY requirements.txt .
|
||||
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 5002
|
||||
|
||||
# 设置环境变量
|
||||
ENV FLASK_APP=app.py
|
||||
ENV FLASK_ENV=production
|
||||
|
||||
# 启动命令
|
||||
CMD ["python", "app.py"]
|
||||
@@ -6,7 +6,7 @@ Created by: 神奇万事通
|
||||
Date: 2025-09-02
|
||||
"""
|
||||
|
||||
from flask import Flask, jsonify, request, session, send_from_directory
|
||||
from flask import Flask, jsonify, request, send_from_directory
|
||||
from flask_cors import CORS
|
||||
from flask_pymongo import PyMongo
|
||||
import os
|
||||
@@ -22,6 +22,7 @@ from modules.aimodelapp import aimodelapp_bp
|
||||
|
||||
from config import Config
|
||||
|
||||
# 创建Flask应用
|
||||
def create_app():
|
||||
"""创建Flask应用实例"""
|
||||
app = Flask(__name__)
|
||||
|
||||
118
InfoGenie-backend/build_docker.sh
Executable file
118
InfoGenie-backend/build_docker.sh
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
|
||||
# InfoGenie 后端 Docker 镜像构建脚本
|
||||
# Created by: 神奇万事通
|
||||
# Date: 2025-09-16
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置
|
||||
IMAGE_NAME="infogenie-backend"
|
||||
IMAGE_TAG="latest"
|
||||
DOCKERFILE_PATH="."
|
||||
|
||||
# 函数:打印信息
|
||||
print_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查Docker是否安装
|
||||
check_docker() {
|
||||
if ! command -v docker &> /dev/null; then
|
||||
print_error "Docker 未安装,请先安装 Docker"
|
||||
exit 1
|
||||
fi
|
||||
print_info "Docker 版本: $(docker --version)"
|
||||
}
|
||||
|
||||
# 检查Dockerfile是否存在
|
||||
check_dockerfile() {
|
||||
if [ ! -f "Dockerfile" ]; then
|
||||
print_error "Dockerfile 不存在"
|
||||
exit 1
|
||||
fi
|
||||
print_info "找到 Dockerfile"
|
||||
}
|
||||
|
||||
# 构建Docker镜像
|
||||
build_image() {
|
||||
print_info "开始构建 Docker 镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
# 构建镜像
|
||||
docker build \
|
||||
--no-cache \
|
||||
-t ${IMAGE_NAME}:${IMAGE_TAG} \
|
||||
-f ${DOCKERFILE_PATH}/Dockerfile \
|
||||
${DOCKERFILE_PATH}
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
print_info "Docker 镜像构建成功!"
|
||||
print_info "镜像信息:"
|
||||
docker images ${IMAGE_NAME}:${IMAGE_TAG}
|
||||
else
|
||||
print_error "Docker 镜像构建失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示使用说明
|
||||
show_usage() {
|
||||
echo ""
|
||||
print_info "构建完成! 使用方法:"
|
||||
echo ""
|
||||
echo "1. 运行容器 (需要MongoDB):"
|
||||
echo " docker run -d \\"
|
||||
echo " --name infogenie-backend \\"
|
||||
echo " -p 5002:5002 \\"
|
||||
echo " -e MONGO_URI=mongodb://host.docker.internal:27017/InfoGenie \\"
|
||||
echo " -e SECRET_KEY=your-secret-key \\"
|
||||
echo " -e MAIL_USERNAME=your-email@qq.com \\"
|
||||
echo " -e MAIL_PASSWORD=your-app-password \\"
|
||||
echo " ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
echo ""
|
||||
echo "2. 使用 Docker Compose (推荐):"
|
||||
echo " 创建 docker-compose.yml 文件并运行:"
|
||||
echo " docker-compose up -d"
|
||||
echo ""
|
||||
echo "3. 查看日志:"
|
||||
echo " docker logs infogenie-backend"
|
||||
echo ""
|
||||
echo "4. 停止容器:"
|
||||
echo " docker stop infogenie-backend"
|
||||
echo " docker rm infogenie-backend"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
print_info "InfoGenie 后端 Docker 镜像构建脚本"
|
||||
print_info "=================================="
|
||||
|
||||
# 检查环境
|
||||
check_docker
|
||||
check_dockerfile
|
||||
|
||||
# 构建镜像
|
||||
build_image
|
||||
|
||||
# 显示使用说明
|
||||
show_usage
|
||||
|
||||
print_info "构建脚本执行完成!"
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
@@ -22,14 +22,14 @@ class Config:
|
||||
# MongoDB 配置
|
||||
MONGO_URI = os.environ.get('MONGO_URI') or 'mongodb://localhost:27017/InfoGenie'
|
||||
|
||||
# Session 配置
|
||||
PERMANENT_SESSION_LIFETIME = timedelta(days=7) # 会话持续7天
|
||||
SESSION_COOKIE_SECURE = False # 开发环境设为False,生产环境设为True
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
SESSION_COOKIE_DOMAIN = None # 开发环境设为None,生产环境设为具体域名
|
||||
SESSION_COOKIE_PATH = '/'
|
||||
SESSION_REFRESH_EACH_REQUEST = True # 每次请求刷新会话过期时间
|
||||
# hwt 配置
|
||||
HWT_LIFETIME = timedelta(days=7) # hwt持续7天
|
||||
HWT_SECURE = False # 开发环境设为False,生产环境设为True
|
||||
HWT_HTTPONLY = True
|
||||
HWT_SAMESITE = 'Lax'
|
||||
HWT_DOMAIN = None # 开发环境设为None,生产环境设为具体域名
|
||||
HWT_PATH = '/'
|
||||
HWT_REFRESH_EACH_REQUEST = True # 每次请求刷新hwt过期时间
|
||||
|
||||
# 邮件配置
|
||||
MAIL_SERVER = 'smtp.qq.com'
|
||||
@@ -68,7 +68,7 @@ class ProductionConfig(Config):
|
||||
"""生产环境配置"""
|
||||
DEBUG = False
|
||||
TESTING = False
|
||||
SESSION_COOKIE_SECURE = True
|
||||
HWT_SECURE = True
|
||||
|
||||
class TestingConfig(Config):
|
||||
"""测试环境配置"""
|
||||
|
||||
53
InfoGenie-backend/docker-compose.yml
Normal file
53
InfoGenie-backend/docker-compose.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# InfoGenie 后端服务
|
||||
infogenie-backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "5002:5002"
|
||||
environment:
|
||||
- FLASK_ENV=production
|
||||
- SECRET_KEY=${SECRET_KEY:-infogenie-secret-key-2025}
|
||||
- MONGO_URI=mongodb://mongodb:27017/InfoGenie
|
||||
- MAIL_USERNAME=${MAIL_USERNAME:-your-email@qq.com}
|
||||
- MAIL_PASSWORD=${MAIL_PASSWORD:-your-app-password}
|
||||
- HWT_SECURE=false
|
||||
depends_on:
|
||||
- mongodb
|
||||
networks:
|
||||
- infogenie-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:5002/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# MongoDB 数据库
|
||||
mongodb:
|
||||
image: mongo:6.0
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_DATABASE=InfoGenie
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
- ./mongo-init:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- infogenie-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
|
||||
networks:
|
||||
infogenie-network:
|
||||
driver: bridge
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,15 +6,120 @@ Created by: 神奇万事通
|
||||
Date: 2025-01-15
|
||||
"""
|
||||
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from bson import ObjectId
|
||||
from functools import wraps
|
||||
|
||||
# 创建蓝图
|
||||
aimodelapp_bp = Blueprint('aimodelapp', __name__)
|
||||
|
||||
# AI功能萌芽币消耗配置
|
||||
AI_COST = 100 # 每次调用AI功能消耗的萌芽币数量
|
||||
|
||||
# 验证用户萌芽币余额装饰器
|
||||
def verify_user_coins(f):
|
||||
"""验证用户萌芽币余额并在调用AI功能后扣除相应数量的萌芽币"""
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
try:
|
||||
# 获取用户认证信息
|
||||
token = request.headers.get('Authorization')
|
||||
if not token:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '未提供认证信息',
|
||||
'error_code': 'auth_required'
|
||||
}), 401
|
||||
|
||||
if token.startswith('Bearer '):
|
||||
token = token[7:]
|
||||
|
||||
# 解析JWT token
|
||||
import jwt
|
||||
try:
|
||||
payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])
|
||||
user_id = payload['user_id']
|
||||
except Exception as jwt_error:
|
||||
print(f"JWT解析错误: {str(jwt_error)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '无效的认证信息',
|
||||
'error_code': 'invalid_token'
|
||||
}), 401
|
||||
|
||||
# 查询用户萌芽币余额
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
user = users_collection.find_one({'_id': ObjectId(user_id)})
|
||||
|
||||
if not user:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '用户不存在',
|
||||
'error_code': 'user_not_found'
|
||||
}), 404
|
||||
|
||||
# 检查萌芽币余额
|
||||
current_coins = user.get('萌芽币', 0)
|
||||
if current_coins < AI_COST:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'萌芽币余额不足!当前余额: {current_coins}, 需要: {AI_COST}',
|
||||
'error_code': 'insufficient_coins',
|
||||
'current_coins': current_coins,
|
||||
'required_coins': AI_COST
|
||||
}), 402
|
||||
|
||||
# 先扣除萌芽币,确保无论服务是否成功都会扣费
|
||||
deduct_result = users_collection.update_one(
|
||||
{'_id': ObjectId(user_id)},
|
||||
{'$inc': {'萌芽币': -AI_COST}}
|
||||
)
|
||||
|
||||
if deduct_result.modified_count < 1:
|
||||
print(f"警告: 用户 {user_id} 萌芽币扣除失败")
|
||||
|
||||
# 为请求添加用户信息,以便在函数内部使用
|
||||
request.current_user = {
|
||||
'user_id': user_id,
|
||||
'username': user.get('用户名', ''),
|
||||
'email': user.get('邮箱', '')
|
||||
}
|
||||
|
||||
# 保存API调用类型
|
||||
api_type = request.path.split('/')[-1]
|
||||
|
||||
# 添加使用记录
|
||||
usage_record = {
|
||||
'api_type': api_type,
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'cost': AI_COST
|
||||
}
|
||||
|
||||
# 更新用户的AI使用历史记录
|
||||
users_collection.update_one(
|
||||
{'_id': ObjectId(user_id)},
|
||||
{'$push': {'ai_usage_history': usage_record}}
|
||||
)
|
||||
|
||||
# 调用原函数
|
||||
result = f(*args, **kwargs)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"验证萌芽币时发生错误: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '处理请求时出错',
|
||||
'error': str(e)
|
||||
}), 500
|
||||
|
||||
return decorated
|
||||
|
||||
#加载AI配置文件
|
||||
def load_ai_config():
|
||||
"""加载AI配置文件"""
|
||||
@@ -126,6 +231,7 @@ def call_kimi_api(messages, model="kimi-k2-0905-preview"):
|
||||
|
||||
#统一的AI聊天接口
|
||||
@aimodelapp_bp.route('/chat', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def ai_chat():
|
||||
"""统一的AI聊天接口"""
|
||||
try:
|
||||
@@ -166,6 +272,7 @@ def ai_chat():
|
||||
|
||||
#姓名分析专用接口
|
||||
@aimodelapp_bp.route('/name-analysis', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def name_analysis():
|
||||
"""姓名分析专用接口"""
|
||||
try:
|
||||
@@ -228,6 +335,7 @@ def name_analysis():
|
||||
|
||||
#变量命名助手接口
|
||||
@aimodelapp_bp.route('/variable-naming', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def variable_naming():
|
||||
"""变量命名助手接口"""
|
||||
try:
|
||||
@@ -329,7 +437,9 @@ def variable_naming():
|
||||
except Exception as e:
|
||||
return jsonify({'error': f'变量命名失败: {str(e)}'}), 500
|
||||
|
||||
#AI写诗助手接口
|
||||
@aimodelapp_bp.route('/poetry', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def poetry_assistant():
|
||||
"""AI写诗助手接口"""
|
||||
try:
|
||||
@@ -379,7 +489,9 @@ def poetry_assistant():
|
||||
except Exception as e:
|
||||
return jsonify({'error': f'诗歌创作失败: {str(e)}'}), 500
|
||||
|
||||
#AI语言翻译接口
|
||||
@aimodelapp_bp.route('/translation', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def translation():
|
||||
"""AI语言翻译接口"""
|
||||
try:
|
||||
@@ -468,6 +580,7 @@ def translation():
|
||||
|
||||
#现代文转文言文接口
|
||||
@aimodelapp_bp.route('/classical_conversion', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def classical_conversion():
|
||||
"""现代文转文言文接口"""
|
||||
try:
|
||||
@@ -548,6 +661,7 @@ def classical_conversion():
|
||||
|
||||
#AI表情制作器接口
|
||||
@aimodelapp_bp.route('/expression-maker', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def expression_maker():
|
||||
"""AI表情制作器接口"""
|
||||
try:
|
||||
@@ -672,6 +786,7 @@ def expression_maker():
|
||||
|
||||
#Linux命令生成接口
|
||||
@aimodelapp_bp.route('/linux-command', methods=['POST'])
|
||||
@verify_user_coins
|
||||
def linux_command_generator():
|
||||
"""Linux命令生成接口"""
|
||||
try:
|
||||
@@ -740,6 +855,80 @@ def linux_command_generator():
|
||||
except Exception as e:
|
||||
return jsonify({'error': f'Linux命令生成失败: {str(e)}'}), 500
|
||||
|
||||
#获取用户萌芽币余额
|
||||
@aimodelapp_bp.route('/coins', methods=['GET'])
|
||||
def get_user_coins():
|
||||
"""获取用户萌芽币余额"""
|
||||
try:
|
||||
# 获取用户认证信息
|
||||
token = request.headers.get('Authorization')
|
||||
if not token:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '未提供认证信息',
|
||||
'error_code': 'auth_required'
|
||||
}), 401
|
||||
|
||||
if token.startswith('Bearer '):
|
||||
token = token[7:]
|
||||
|
||||
# 解析JWT token
|
||||
import jwt
|
||||
try:
|
||||
payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])
|
||||
user_id = payload['user_id']
|
||||
except jwt.ExpiredSignatureError:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Token已过期,请重新登录',
|
||||
'error_code': 'token_expired'
|
||||
}), 401
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'无效的认证信息: {str(e)}',
|
||||
'error_code': 'invalid_token'
|
||||
}), 401
|
||||
|
||||
# 查询用户萌芽币余额
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
user = users_collection.find_one({'_id': ObjectId(user_id)})
|
||||
|
||||
if not user:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '用户不存在',
|
||||
'error_code': 'user_not_found'
|
||||
}), 404
|
||||
|
||||
# 返回萌芽币信息
|
||||
current_coins = user.get('萌芽币', 0)
|
||||
username = user.get('用户名', '用户')
|
||||
|
||||
# 增加额外有用信息
|
||||
ai_usage_history = []
|
||||
if 'ai_usage_history' in user:
|
||||
ai_usage_history = user['ai_usage_history'][-5:] # 最近5条使用记录
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': {
|
||||
'coins': current_coins,
|
||||
'ai_cost': AI_COST,
|
||||
'can_use_ai': current_coins >= AI_COST,
|
||||
'username': username,
|
||||
'usage_count': len(ai_usage_history),
|
||||
'recent_usage': ai_usage_history
|
||||
},
|
||||
'message': f'当前萌芽币余额: {current_coins}'
|
||||
}), 200
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '处理请求时出错',
|
||||
'error': str(e)
|
||||
}), 500
|
||||
|
||||
#获取可用的AI模型列表
|
||||
@aimodelapp_bp.route('/models', methods=['GET'])
|
||||
def get_available_models():
|
||||
|
||||
@@ -6,7 +6,7 @@ Created by: 神奇万事通
|
||||
Date: 2025-09-02
|
||||
"""
|
||||
|
||||
from flask import Blueprint, request, jsonify, session, current_app
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
import hashlib
|
||||
import re
|
||||
@@ -17,6 +17,7 @@ from .email_service import send_verification_email, verify_code, is_qq_email, ge
|
||||
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
|
||||
#生成JWT token
|
||||
def generate_token(user_data):
|
||||
"""生成JWT token"""
|
||||
payload = {
|
||||
@@ -28,6 +29,7 @@ def generate_token(user_data):
|
||||
}
|
||||
return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256')
|
||||
|
||||
#验证JWT token
|
||||
def verify_token(token):
|
||||
"""验证JWT token"""
|
||||
try:
|
||||
@@ -38,6 +40,7 @@ def verify_token(token):
|
||||
except jwt.InvalidTokenError:
|
||||
return {'success': False, 'message': 'Token无效'}
|
||||
|
||||
#JWT token验证装饰器
|
||||
def token_required(f):
|
||||
"""JWT token验证装饰器"""
|
||||
@wraps(f)
|
||||
@@ -57,14 +60,17 @@ def token_required(f):
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
#验证QQ邮箱格式
|
||||
def validate_qq_email(email):
|
||||
"""验证QQ邮箱格式"""
|
||||
return is_qq_email(email)
|
||||
|
||||
#验证密码格式
|
||||
def validate_password(password):
|
||||
"""验证密码格式(6-20位)"""
|
||||
return 6 <= len(password) <= 20
|
||||
|
||||
#发送验证码邮件
|
||||
@auth_bp.route('/send-verification', methods=['POST'])
|
||||
def send_verification():
|
||||
"""发送验证码邮件"""
|
||||
@@ -120,6 +126,7 @@ def send_verification():
|
||||
'message': '发送失败,请稍后重试'
|
||||
}), 500
|
||||
|
||||
#验证验证码
|
||||
@auth_bp.route('/verify-code', methods=['POST'])
|
||||
def verify_verification_code():
|
||||
"""验证验证码"""
|
||||
@@ -150,6 +157,7 @@ def verify_verification_code():
|
||||
'message': '验证失败,请稍后重试'
|
||||
}), 500
|
||||
|
||||
#用户注册
|
||||
@auth_bp.route('/register', methods=['POST'])
|
||||
def register():
|
||||
"""用户注册(需要先验证邮箱)"""
|
||||
@@ -253,43 +261,8 @@ def register():
|
||||
'success': False,
|
||||
'message': '注册失败,请稍后重试'
|
||||
}), 500
|
||||
|
||||
if existing_user:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '该账号已被注册'
|
||||
}), 409
|
||||
|
||||
# 创建新用户
|
||||
password_hash = generate_password_hash(password)
|
||||
user_data = {
|
||||
'账号': account,
|
||||
'密码': password_hash,
|
||||
'注册时间': datetime.now().isoformat(),
|
||||
'最后登录': None,
|
||||
'登录次数': 0,
|
||||
'用户状态': 'active'
|
||||
}
|
||||
|
||||
result = users_collection.insert_one(user_data)
|
||||
|
||||
if result.inserted_id:
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '注册成功!'
|
||||
}), 201
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '注册失败,请稍后重试'
|
||||
}), 500
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
#用户登录
|
||||
@auth_bp.route('/login', methods=['POST'])
|
||||
def login():
|
||||
"""用户登录(支持邮箱+验证码或邮箱+密码)"""
|
||||
@@ -392,9 +365,10 @@ def login():
|
||||
}), 500
|
||||
|
||||
# 登录成功,创建会话
|
||||
session['user_id'] = str(user['_id'])
|
||||
session['account'] = user['账号']
|
||||
session['logged_in'] = True
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
hwt['user_id'] = str(user['_id'])
|
||||
hwt['account'] = user['账号']
|
||||
hwt['logged_in'] = True
|
||||
|
||||
# 更新登录信息
|
||||
users_collection.update_one(
|
||||
@@ -421,6 +395,7 @@ def login():
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
#用户登出
|
||||
@auth_bp.route('/logout', methods=['POST'])
|
||||
def logout():
|
||||
"""用户登出"""
|
||||
@@ -437,6 +412,7 @@ def logout():
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
#检查登录状态
|
||||
@auth_bp.route('/check', methods=['GET'])
|
||||
def check_login():
|
||||
"""检查登录状态"""
|
||||
|
||||
@@ -18,15 +18,18 @@ import os
|
||||
# 验证码存储(生产环境建议使用Redis)
|
||||
verification_codes = {}
|
||||
|
||||
# 初始化日志
|
||||
def init_mail(app):
|
||||
"""初始化邮件配置"""
|
||||
# 使用smtplib直接发送,不需要Flask-Mail
|
||||
pass
|
||||
|
||||
# 生成验证码
|
||||
def generate_verification_code(length=6):
|
||||
"""生成验证码"""
|
||||
return ''.join(random.choices(string.digits, k=length))
|
||||
|
||||
# 发送验证邮件
|
||||
def send_verification_email(email, verification_type='register'):
|
||||
"""
|
||||
发送验证邮件
|
||||
@@ -168,6 +171,7 @@ def send_verification_email(email, verification_type='register'):
|
||||
'message': '邮件发送失败,请稍后重试'
|
||||
}
|
||||
|
||||
# 验证验证码
|
||||
def verify_code(email, code):
|
||||
"""
|
||||
验证验证码
|
||||
@@ -221,6 +225,7 @@ def verify_code(email, code):
|
||||
'type': verification_type
|
||||
}
|
||||
|
||||
# 验证QQ邮箱格式
|
||||
def is_qq_email(email):
|
||||
"""
|
||||
验证是否为QQ邮箱
|
||||
@@ -239,6 +244,7 @@ def is_qq_email(email):
|
||||
|
||||
return domain in qq_domains
|
||||
|
||||
# 获取QQ头像URL
|
||||
def get_qq_avatar_url(email):
|
||||
"""
|
||||
根据QQ邮箱获取QQ头像URL
|
||||
@@ -262,6 +268,7 @@ def get_qq_avatar_url(email):
|
||||
# 返回QQ头像API URL
|
||||
return f"http://q1.qlogo.cn/g?b=qq&nk={qq_number}&s=100"
|
||||
|
||||
# 清理过期验证码
|
||||
def cleanup_expired_codes():
|
||||
"""清理过期的验证码"""
|
||||
current_time = datetime.now()
|
||||
|
||||
@@ -6,7 +6,7 @@ Created by: 神奇万事通
|
||||
Date: 2025-09-02
|
||||
"""
|
||||
|
||||
from flask import Blueprint, request, jsonify, session, current_app
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
from datetime import datetime
|
||||
from bson import ObjectId
|
||||
import jwt
|
||||
@@ -14,6 +14,7 @@ from functools import wraps
|
||||
|
||||
user_bp = Blueprint('user', __name__)
|
||||
|
||||
# 验证JWT token
|
||||
def verify_token(token):
|
||||
"""验证JWT token"""
|
||||
try:
|
||||
@@ -24,8 +25,9 @@ def verify_token(token):
|
||||
except jwt.InvalidTokenError:
|
||||
return {'success': False, 'message': 'Token无效'}
|
||||
|
||||
# 登录验证装饰器(支持JWT token和hwt)
|
||||
def login_required(f):
|
||||
"""登录验证装饰器(支持JWT token和session)"""
|
||||
"""登录验证装饰器(支持JWT token和hwt)"""
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# 优先检查JWT token
|
||||
@@ -38,32 +40,32 @@ def login_required(f):
|
||||
if result['success']:
|
||||
request.current_user = result['data']
|
||||
return f(*args, **kwargs)
|
||||
|
||||
# 回退到session验证
|
||||
if not session.get('logged_in'):
|
||||
# 回退到hwt验证
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
if not hwt.get('logged_in'):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '请先登录'
|
||||
}), 401
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
return decorated_function
|
||||
|
||||
# 获取用户资料
|
||||
@user_bp.route('/profile', methods=['GET'])
|
||||
@login_required
|
||||
def get_profile():
|
||||
"""获取用户资料"""
|
||||
try:
|
||||
user_id = session.get('user_id')
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
user_id = hwt.get('user_id')
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
|
||||
user = users_collection.find_one({'_id': ObjectId(user_id)})
|
||||
|
||||
if not user:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '用户不存在'
|
||||
}), 404
|
||||
|
||||
# 返回用户信息(不包含密码)
|
||||
profile = {
|
||||
'account': user['账号'],
|
||||
@@ -72,18 +74,17 @@ def get_profile():
|
||||
'login_count': user.get('登录次数', 0),
|
||||
'status': user.get('用户状态', 'active')
|
||||
}
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': profile
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 修改密码
|
||||
@user_bp.route('/change-password', methods=['POST'])
|
||||
@login_required
|
||||
def change_password():
|
||||
@@ -105,34 +106,28 @@ def change_password():
|
||||
'message': '新密码长度必须在6-20位之间'
|
||||
}), 400
|
||||
|
||||
user_id = session.get('user_id')
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
user_id = hwt.get('user_id')
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
|
||||
user = users_collection.find_one({'_id': ObjectId(user_id)})
|
||||
|
||||
if not user:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '用户不存在'
|
||||
}), 404
|
||||
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
# 验证旧密码
|
||||
if not check_password_hash(user['密码'], old_password):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '原密码错误'
|
||||
}), 401
|
||||
|
||||
# 更新密码
|
||||
new_password_hash = generate_password_hash(new_password)
|
||||
|
||||
result = users_collection.update_one(
|
||||
{'_id': ObjectId(user_id)},
|
||||
{'$set': {'密码': new_password_hash}}
|
||||
)
|
||||
|
||||
if result.modified_count > 0:
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -143,20 +138,20 @@ def change_password():
|
||||
'success': False,
|
||||
'message': '密码修改失败'
|
||||
}), 500
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 获取用户统计信息
|
||||
@user_bp.route('/stats', methods=['GET'])
|
||||
@login_required
|
||||
def get_user_stats():
|
||||
"""获取用户统计信息"""
|
||||
try:
|
||||
user_id = session.get('user_id')
|
||||
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
user_id = hwt.get('user_id')
|
||||
# 这里可以添加更多统计信息,比如API调用次数等
|
||||
stats = {
|
||||
'login_today': 1, # 今日登录次数
|
||||
@@ -165,18 +160,17 @@ def get_user_stats():
|
||||
'join_days': 1, # 加入天数
|
||||
'last_activity': datetime.now().isoformat()
|
||||
}
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': stats
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 获取用户游戏数据
|
||||
@user_bp.route('/game-data', methods=['GET'])
|
||||
@login_required
|
||||
def get_user_game_data():
|
||||
@@ -186,7 +180,8 @@ def get_user_game_data():
|
||||
if hasattr(request, 'current_user'):
|
||||
user_id = request.current_user['user_id']
|
||||
else:
|
||||
user_id = session.get('user_id')
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
user_id = hwt.get('user_id')
|
||||
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
|
||||
@@ -221,6 +216,7 @@ def get_user_game_data():
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 每日签到
|
||||
@user_bp.route('/checkin', methods=['POST'])
|
||||
@login_required
|
||||
def daily_checkin():
|
||||
@@ -230,7 +226,8 @@ def daily_checkin():
|
||||
if hasattr(request, 'current_user'):
|
||||
user_id = request.current_user['user_id']
|
||||
else:
|
||||
user_id = session.get('user_id')
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
user_id = hwt.get('user_id')
|
||||
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
|
||||
@@ -350,6 +347,7 @@ def daily_checkin():
|
||||
'message': f'服务器错误: {str(e)}'
|
||||
}), 500
|
||||
|
||||
# 删除账户
|
||||
@user_bp.route('/delete', methods=['POST'])
|
||||
@login_required
|
||||
def delete_account():
|
||||
@@ -364,7 +362,8 @@ def delete_account():
|
||||
'message': '请输入密码确认删除'
|
||||
}), 400
|
||||
|
||||
user_id = session.get('user_id')
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
user_id = hwt.get('user_id')
|
||||
users_collection = current_app.mongo.db.userdata
|
||||
|
||||
user = users_collection.find_one({'_id': ObjectId(user_id)})
|
||||
@@ -389,7 +388,8 @@ def delete_account():
|
||||
|
||||
if result.deleted_count > 0:
|
||||
# 清除会话
|
||||
session.clear()
|
||||
hwt = getattr(request, 'hwt', {})
|
||||
hwt.clear()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
# InfoGenie 后端架构文档
|
||||
|
||||
## 项目概述
|
||||
|
||||
InfoGenie(神奇万事通)是一个基于前后端分离架构的多功能聚合软件应用。后端采用Flask框架提供RESTful API服务,前端通过HTTP请求调用后端API,实现数据交互和业务逻辑处理。
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 核心框架
|
||||
- **Web框架**: Flask 2.3.3
|
||||
- **数据库**: MongoDB (Flask-PyMongo 2.3.0)
|
||||
- **认证**: JWT (PyJWT 2.8.0)
|
||||
- **跨域**: Flask-CORS 4.0.0
|
||||
|
||||
### 辅助工具
|
||||
- **邮件服务**: Flask-Mail 0.9.1
|
||||
- **密码加密**: Werkzeug 2.3.7
|
||||
- **环境配置**: python-dotenv 1.0.0
|
||||
- **API限流**: Flask-Limiter 3.5.0
|
||||
|
||||
## 架构设计原则
|
||||
|
||||
### 前后端分离
|
||||
- 后端专注于数据处理和业务逻辑
|
||||
- 前端负责用户界面和交互体验
|
||||
- 通过RESTful API进行数据交换
|
||||
- 完全解耦,便于独立开发和部署
|
||||
|
||||
### 模块化设计
|
||||
- 按功能划分独立模块
|
||||
- 每个模块职责单一
|
||||
- 便于维护和扩展
|
||||
|
||||
## 核心模块详解
|
||||
|
||||
### 1. 认证模块 (auth.py)
|
||||
|
||||
**功能职责**:
|
||||
- 用户注册和登录
|
||||
- JWT Token生成和管理
|
||||
- 邮箱验证码验证
|
||||
- QQ邮箱格式验证
|
||||
|
||||
**API端点**:
|
||||
```
|
||||
POST /api/auth/send-verification # 发送验证码
|
||||
POST /api/auth/verify-code # 验证验证码
|
||||
POST /api/auth/register # 用户注册
|
||||
POST /api/auth/login # 用户登录
|
||||
POST /api/auth/logout # 用户登出
|
||||
GET /api/auth/check # 检查登录状态
|
||||
```
|
||||
|
||||
**数据流程**:
|
||||
1. 前端发送注册/登录请求
|
||||
2. 后端验证邮箱格式(仅支持QQ邮箱)
|
||||
3. 发送验证码邮件到用户邮箱
|
||||
4. 用户输入验证码完成验证
|
||||
5. 验证成功后生成JWT Token返回给前端
|
||||
|
||||
**安全特性**:
|
||||
- 密码使用Werkzeug进行哈希加密
|
||||
- JWT Token 7天有效期
|
||||
- 验证码5分钟有效期,限制尝试次数
|
||||
|
||||
### 2. 用户管理模块 (user_management.py)
|
||||
|
||||
**功能职责**:
|
||||
- 用户资料管理
|
||||
- 密码修改
|
||||
- 每日签到系统
|
||||
- 用户游戏数据管理
|
||||
- 账户删除
|
||||
|
||||
**API端点**:
|
||||
```
|
||||
GET /api/user/profile # 获取用户资料
|
||||
POST /api/user/change-password # 修改密码
|
||||
GET /api/user/stats # 获取用户统计
|
||||
GET /api/user/game-data # 获取游戏数据
|
||||
POST /api/user/checkin # 每日签到
|
||||
POST /api/user/delete # 删除账户
|
||||
```
|
||||
|
||||
**数据结构**:
|
||||
```json
|
||||
{
|
||||
"邮箱": "user@qq.com",
|
||||
"用户名": "用户名",
|
||||
"密码": "哈希密码",
|
||||
"头像": "QQ头像URL",
|
||||
"注册时间": "2025-01-01T00:00:00",
|
||||
"最后登录": "2025-01-01T00:00:00",
|
||||
"登录次数": 10,
|
||||
"用户状态": "active",
|
||||
"等级": 5,
|
||||
"经验": 1200,
|
||||
"萌芽币": 1500,
|
||||
"签到系统": {
|
||||
"连续签到天数": 7,
|
||||
"今日是否已签到": true,
|
||||
"签到时间": "2025-01-01"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**业务逻辑**:
|
||||
- 签到奖励:300萌芽币 + 200经验
|
||||
- 等级升级:100 × 1.2^(等级) 经验需求
|
||||
|
||||
### 3. 邮件服务模块 (email_service.py)
|
||||
|
||||
**功能职责**:
|
||||
- 验证码邮件发送
|
||||
- QQ邮箱格式验证
|
||||
- QQ头像获取
|
||||
- 邮件模板管理
|
||||
|
||||
**邮件模板**:
|
||||
- 注册验证码邮件(HTML格式)
|
||||
- 登录验证码邮件(HTML格式)
|
||||
- 支持自定义邮件内容和样式
|
||||
|
||||
**安全考虑**:
|
||||
- 仅支持QQ邮箱(qq.com、vip.qq.com、foxmail.com)
|
||||
- 使用SSL加密连接
|
||||
- 验证码存储在内存中(生产环境建议使用Redis)
|
||||
|
||||
### 4. AI模型应用模块 (aimodelapp.py)
|
||||
|
||||
**功能职责**:
|
||||
- 集成多种AI服务(DeepSeek、Kimi)
|
||||
- 提供AI功能API接口
|
||||
- 统一AI接口调用
|
||||
- 管理用户萌芽币消费(每次调用消耗100萌芽币)
|
||||
|
||||
**支持的AI功能**:
|
||||
1. **AI聊天接口** (`/api/aimodelapp/chat`)
|
||||
2. **姓名分析** (`/api/aimodelapp/name-analysis`)
|
||||
3. **变量命名助手** (`/api/aimodelapp/variable-naming`)
|
||||
4. **AI写诗助手** (`/api/aimodelapp/poetry`)
|
||||
5. **AI语言翻译** (`/api/aimodelapp/translation`)
|
||||
6. **现代文转文言文** (`/api/aimodelapp/classical_conversion`)
|
||||
7. **AI表情制作器** (`/api/aimodelapp/expression-maker`)
|
||||
8. **Linux命令生成** (`/api/aimodelapp/linux-command`)
|
||||
9. **获取可用模型** (`/api/aimodelapp/models`)
|
||||
|
||||
**AI配置**:
|
||||
```json
|
||||
{
|
||||
"deepseek": {
|
||||
"api_key": "your-api-key",
|
||||
"api_base": "https://api.deepseek.com",
|
||||
"model": ["deepseek-chat", "deepseek-reasoner"]
|
||||
},
|
||||
"kimi": {
|
||||
"api_key": "your-api-key",
|
||||
"api_base": "https://api.moonshot.cn",
|
||||
"model": ["kimi-k2-0905-preview", "kimi-k2-0711-preview"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**调用流程**:
|
||||
1. 前端发送AI请求(包含消息、模型提供商等参数)
|
||||
2. 后端加载AI配置文件
|
||||
3. 调用对应AI API(带重试机制)
|
||||
4. 返回AI响应给前端
|
||||
|
||||
## API设计规范
|
||||
|
||||
### 请求/响应格式
|
||||
|
||||
**成功响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {...},
|
||||
"message": "操作成功",
|
||||
"timestamp": "2025-01-01T00:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应**:
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "错误信息",
|
||||
"error": "错误详情"
|
||||
}
|
||||
```
|
||||
|
||||
### 认证方式
|
||||
|
||||
**JWT Token认证**:
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**支持的认证端点**:
|
||||
- 所有 `/api/user/*` 端点需要认证
|
||||
- 部分 `/api/aimodelapp/*` 端点需要认证
|
||||
|
||||
### 错误处理
|
||||
|
||||
**HTTP状态码**:
|
||||
- 200: 成功
|
||||
- 400: 请求参数错误
|
||||
- 401: 未认证/认证失败
|
||||
- 403: 权限不足
|
||||
- 404: 资源不存在
|
||||
- 409: 资源冲突
|
||||
- 500: 服务器内部错误
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### MongoDB集合
|
||||
|
||||
**主要集合**: `userdata`
|
||||
- 存储所有用户相关数据
|
||||
- 支持动态字段扩展
|
||||
- 使用ObjectId作为用户唯一标识
|
||||
|
||||
### 数据关系
|
||||
- 用户数据自包含,无复杂关联
|
||||
- 通过用户ID进行数据关联
|
||||
- 支持水平扩展
|
||||
|
||||
## 部署和配置
|
||||
|
||||
### 环境配置
|
||||
|
||||
**必需环境变量**:
|
||||
```
|
||||
SECRET_KEY=your-secret-key
|
||||
MONGO_URI=mongodb://localhost:27017/InfoGenie
|
||||
MAIL_USERNAME=your-email@qq.com
|
||||
MAIL_PASSWORD=your-app-password
|
||||
```
|
||||
|
||||
### 启动方式
|
||||
|
||||
**开发环境**:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
|
||||
**生产环境**:
|
||||
- 支持Docker部署
|
||||
- 提供docker-compose配置
|
||||
- 支持Gunicorn WSGI服务器
|
||||
|
||||
### 静态文件服务
|
||||
|
||||
**支持的前端资源**:
|
||||
- `/60sapi/*`: 60秒API相关文件
|
||||
- `/smallgame/*`: 小游戏相关文件
|
||||
- `/aimodelapp/*`: AI模型应用相关文件
|
||||
|
||||
## 安全考虑
|
||||
|
||||
### 数据安全
|
||||
- 密码哈希存储
|
||||
- JWT Token安全传输
|
||||
- 输入数据验证和过滤
|
||||
|
||||
### API安全
|
||||
- CORS配置(生产环境限制域名)
|
||||
- API限流保护
|
||||
- 请求日志记录
|
||||
|
||||
### 部署安全
|
||||
- 环境变量管理敏感信息
|
||||
- HTTPS证书配置
|
||||
- 防火墙和访问控制
|
||||
|
||||
## 前后端协作指南
|
||||
|
||||
### 前端调用示例
|
||||
|
||||
**用户登录**:
|
||||
```javascript
|
||||
// 1. 发送验证码
|
||||
fetch('/api/auth/send-verification', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email: 'user@qq.com', type: 'login' })
|
||||
});
|
||||
|
||||
// 2. 验证验证码并登录
|
||||
fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
email: 'user@qq.com',
|
||||
code: '123456'
|
||||
})
|
||||
});
|
||||
|
||||
// 3. 保存token到localStorage
|
||||
localStorage.setItem('token', response.token);
|
||||
```
|
||||
|
||||
**调用需要认证的API**:
|
||||
```javascript
|
||||
fetch('/api/user/profile', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 数据约定
|
||||
|
||||
**前端发送数据格式**:
|
||||
- 所有请求使用JSON格式
|
||||
- 必填字段验证
|
||||
- 参数命名使用snake_case
|
||||
|
||||
**后端返回数据格式**:
|
||||
- 统一响应格式
|
||||
- 时间戳使用ISO格式
|
||||
- 错误信息清晰明确
|
||||
|
||||
### 开发协作流程
|
||||
|
||||
1. **API设计阶段**:
|
||||
- 后端定义API接口规范
|
||||
- 前端根据规范开发调用代码
|
||||
- 约定数据格式和错误处理
|
||||
|
||||
2. **联调阶段**:
|
||||
- 使用统一的测试数据
|
||||
- 验证各种边界情况
|
||||
- 确认错误处理逻辑
|
||||
|
||||
3. **部署阶段**:
|
||||
- 后端部署API服务
|
||||
- 前端配置API基础URL
|
||||
- 验证跨域和认证配置
|
||||
|
||||
## 新功能添加
|
||||
|
||||
### 1. AI功能萌芽币消费系统
|
||||
|
||||
**功能描述**:
|
||||
- 用户每次调用AI模型应用(aimodelapp)需消耗100萌芽币
|
||||
- 当用户萌芽币余额不足时,无法使用AI功能
|
||||
- 记录用户的AI使用历史
|
||||
|
||||
**API端点**:
|
||||
```
|
||||
GET /api/aimodelapp/coins # 查询用户萌芽币余额和使用历史
|
||||
```
|
||||
|
||||
**技术实现**:
|
||||
- 使用装饰器模式实现请求前验证和扣除萌芽币
|
||||
- 在MongoDB中记录用户AI使用历史
|
||||
- 通过JWT Token验证用户身份
|
||||
|
||||
**业务逻辑**:
|
||||
1. 当用户请求AI功能时,首先验证JWT Token
|
||||
2. 检查用户萌芽币余额是否≥100
|
||||
3. 如余额充足,先扣除萌芽币,然后再调用AI服务
|
||||
4. 记录使用历史,包括API类型、时间和消费萌芽币数量
|
||||
5. 返回AI服务结果给用户
|
||||
|
||||
**响应示例(查询萌芽币余额)**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"coins": 200,
|
||||
"ai_cost": 100,
|
||||
"can_use_ai": true,
|
||||
"username": "用户名",
|
||||
"usage_count": 1,
|
||||
"recent_usage": [
|
||||
{
|
||||
"api_type": "chat",
|
||||
"cost": 100,
|
||||
"timestamp": "2025-09-16T11:15:47.285720"
|
||||
}
|
||||
]
|
||||
},
|
||||
"message": "当前萌芽币余额: 200"
|
||||
}
|
||||
```
|
||||
|
||||
**前端开发注意事项**:
|
||||
- 每个需要调用AI功能的页面应首先检查用户萌芽币余额
|
||||
- 当萌芽币不足时,向用户提示并引导用户通过签到等方式获取萌芽币
|
||||
- 可在UI中展示用户最近的AI使用记录和萌芽币消费情况
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user