diff --git a/InfoGenie-backend/.dockerignore b/InfoGenie-backend/.dockerignore new file mode 100644 index 00000000..74b16a7c --- /dev/null +++ b/InfoGenie-backend/.dockerignore @@ -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/ diff --git a/InfoGenie-backend/.env.production b/InfoGenie-backend/.env.production index 15d521db..bef38d25 100755 --- a/InfoGenie-backend/.env.production +++ b/InfoGenie-backend/.env.production @@ -11,4 +11,4 @@ MAIL_PASSWORD=your-app-password SECRET_KEY=infogenie-production-secret-key-2025 # 会话安全配置 -SESSION_COOKIE_SECURE=True \ No newline at end of file +HWT_SECURE=True \ No newline at end of file diff --git a/InfoGenie-backend/DOCKER_README.md b/InfoGenie-backend/DOCKER_README.md new file mode 100644 index 00000000..bbf552dc --- /dev/null +++ b/InfoGenie-backend/DOCKER_README.md @@ -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 许可证。 diff --git a/InfoGenie-backend/Dockerfile b/InfoGenie-backend/Dockerfile new file mode 100644 index 00000000..c0aae50c --- /dev/null +++ b/InfoGenie-backend/Dockerfile @@ -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"] diff --git a/InfoGenie-backend/app.py b/InfoGenie-backend/app.py index bf3bfc54..41e49ea8 100755 --- a/InfoGenie-backend/app.py +++ b/InfoGenie-backend/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__) diff --git a/InfoGenie-backend/build_docker.sh b/InfoGenie-backend/build_docker.sh new file mode 100755 index 00000000..1f246bfc --- /dev/null +++ b/InfoGenie-backend/build_docker.sh @@ -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 "$@" diff --git a/InfoGenie-backend/config.py b/InfoGenie-backend/config.py index da162388..824532c5 100755 --- a/InfoGenie-backend/config.py +++ b/InfoGenie-backend/config.py @@ -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): """测试环境配置""" diff --git a/InfoGenie-backend/docker-compose.yml b/InfoGenie-backend/docker-compose.yml new file mode 100644 index 00000000..96795f45 --- /dev/null +++ b/InfoGenie-backend/docker-compose.yml @@ -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 diff --git a/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-310.pyc b/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-310.pyc index 8b01fef6..abcfffba 100644 Binary files a/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-310.pyc and b/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-310.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/auth.cpython-310.pyc b/InfoGenie-backend/modules/__pycache__/auth.cpython-310.pyc index d8b284ec..58d3b639 100644 Binary files a/InfoGenie-backend/modules/__pycache__/auth.cpython-310.pyc and b/InfoGenie-backend/modules/__pycache__/auth.cpython-310.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/email_service.cpython-310.pyc b/InfoGenie-backend/modules/__pycache__/email_service.cpython-310.pyc index 3cbf4314..ca0eb326 100644 Binary files a/InfoGenie-backend/modules/__pycache__/email_service.cpython-310.pyc and b/InfoGenie-backend/modules/__pycache__/email_service.cpython-310.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/user_management.cpython-310.pyc b/InfoGenie-backend/modules/__pycache__/user_management.cpython-310.pyc index 334dabc5..74317c1b 100644 Binary files a/InfoGenie-backend/modules/__pycache__/user_management.cpython-310.pyc and b/InfoGenie-backend/modules/__pycache__/user_management.cpython-310.pyc differ diff --git a/InfoGenie-backend/modules/aimodelapp.py b/InfoGenie-backend/modules/aimodelapp.py index 72dedcbc..ce340932 100755 --- a/InfoGenie-backend/modules/aimodelapp.py +++ b/InfoGenie-backend/modules/aimodelapp.py @@ -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(): diff --git a/InfoGenie-backend/modules/auth.py b/InfoGenie-backend/modules/auth.py index b7adb752..0c7090de 100755 --- a/InfoGenie-backend/modules/auth.py +++ b/InfoGenie-backend/modules/auth.py @@ -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(): """检查登录状态""" diff --git a/InfoGenie-backend/modules/email_service.py b/InfoGenie-backend/modules/email_service.py index 13e33591..dfbe45a5 100755 --- a/InfoGenie-backend/modules/email_service.py +++ b/InfoGenie-backend/modules/email_service.py @@ -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() diff --git a/InfoGenie-backend/modules/user_management.py b/InfoGenie-backend/modules/user_management.py index 97b70df6..e3cb659d 100755 --- a/InfoGenie-backend/modules/user_management.py +++ b/InfoGenie-backend/modules/user_management.py @@ -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, diff --git a/InfoGenie-backend/后端架构文档.md b/InfoGenie-backend/后端架构文档.md index e69de29b..325ddf92 100755 --- a/InfoGenie-backend/后端架构文档.md +++ b/InfoGenie-backend/后端架构文档.md @@ -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 +``` + +**支持的认证端点**: +- 所有 `/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使用记录和萌芽币消费情况 + +--- diff --git a/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/index.html b/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/index.html index 6e76ba22..d344633a 100755 --- a/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/index.html +++ b/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/index.html @@ -37,6 +37,7 @@ + diff --git a/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/script.js b/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/script.js index 2dff09f9..f012924f 100755 --- a/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/script.js +++ b/InfoGenie-frontend/public/aimodelapp/AI变量命名助手/script.js @@ -40,10 +40,18 @@ const namingConventions = { // 调用后端API async function callBackendAPI(description) { try { + // 获取JWT token + const token = localStorage.getItem('token'); + + if (!token) { + throw new Error('未登录,请先登录后使用AI功能'); + } + const response = await fetch('http://127.0.0.1:5002/api/aimodelapp/variable-naming', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ description: description @@ -208,15 +216,30 @@ async function generateSuggestions() { return; } + // 检查萌芽币余额是否足够 + if (window.coinManager && !window.coinManager.checkBeforeApiCall()) { + return; + } + showLoading(true); suggestionsContainer.innerHTML = ''; try { const suggestions = await callBackendAPI(description); displaySuggestions(suggestions); + + // 刷新萌芽币信息 + if (window.coinManager) { + window.coinManager.loadCoinsInfo(); + } } catch (error) { console.error('生成建议失败:', error); - showErrorMessage(`生成失败: ${error.message}`); + // 检查是否是萌芽币不足导致的错误 + if (error.message && error.message.includes('萌芽币余额不足')) { + showErrorMessage(`萌芽币不足: 每次使用AI功能需要消耗100萌芽币,请通过每日签到获取更多萌芽币`); + } else { + showErrorMessage(`生成失败: ${error.message}`); + } } finally { showLoading(false); } diff --git a/InfoGenie-frontend/public/aimodelapp/coin-manager.js b/InfoGenie-frontend/public/aimodelapp/coin-manager.js index e69de29b..2685272a 100644 --- a/InfoGenie-frontend/public/aimodelapp/coin-manager.js +++ b/InfoGenie-frontend/public/aimodelapp/coin-manager.js @@ -0,0 +1,288 @@ +/** + * InfoGenie 萌芽币管理工具 + * 此模块负责管理用户AI功能的萌芽币余额和消费 + * 为所有AI模型应用提供统一的萌芽币检查和显示功能 + */ + +class CoinManager { + constructor() { + // 状态变量 + this.coins = 0; + this.aiCost = 100; + this.canUseAi = false; + this.username = ''; + this.usageCount = 0; + this.recentUsage = []; + this.isLoaded = false; + this.isLoading = false; + this.error = null; + + // UI元素 + this.coinInfoContainer = null; + + // 初始化 + this.init(); + } + + /** + * 初始化萌芽币管理器 + */ + async init() { + // 创建UI元素 + this.createCoinInfoUI(); + + // 加载萌芽币信息 + await this.loadCoinsInfo(); + + // 监听网络状态变化 + window.addEventListener('online', () => this.loadCoinsInfo()); + } + + /** + * 创建萌芽币信息UI + */ + createCoinInfoUI() { + // 检查是否已创建 + if (this.coinInfoContainer) { + return; + } + + // 创建容器 + this.coinInfoContainer = document.createElement('div'); + this.coinInfoContainer.className = 'coin-info-container'; + this.coinInfoContainer.style = ` + position: fixed; + top: 10px; + right: 10px; + background: rgba(255, 255, 255, 0.95); + border-radius: 8px; + padding: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + z-index: 9999; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + max-width: 300px; + transition: all 0.3s ease; + border: 1px solid rgba(74, 222, 128, 0.4); + `; + + // 更新UI内容 + this.updateCoinInfoUI(); + + // 添加到页面 + document.body.appendChild(this.coinInfoContainer); + } + + /** + * 更新萌芽币信息UI + */ + updateCoinInfoUI() { + if (!this.coinInfoContainer) { + return; + } + + let content = ''; + + if (this.isLoading) { + content = '
加载中...
'; + } else if (this.error) { + content = ` +
+
加载失败
+
${this.error}
+ +
+ `; + } else if (!this.isLoaded) { + content = '
正在检查萌芽币余额...
'; + } else { + const usageHistory = this.recentUsage.length > 0 + ? ` +
+
最近使用记录:
+ ${this.recentUsage.map(usage => ` +
+ ${this.formatApiType(usage.api_type)} (-${usage.cost}币) + ${this.formatDate(usage.timestamp)} +
+ `).join('')} +
+ ` + : ''; + + content = ` +
+
${this.username || '用户'}的萌芽币
+
+ ${this.canUseAi ? '可使用' : '币不足'} +
+
+ +
+
+ ${this.coins} +
+
萌芽币
+
+ +
+ AI功能每次使用消耗 ${this.aiCost} 萌芽币 +
+ + ${usageHistory} + `; + } + + this.coinInfoContainer.innerHTML = content; + } + + /** + * 加载萌芽币信息 + */ + async loadCoinsInfo() { + try { + this.isLoading = true; + this.error = null; + this.updateCoinInfoUI(); + + // 获取JWT token + const token = localStorage.getItem('token'); + + if (!token) { + this.error = '未登录,无法获取萌芽币信息'; + this.isLoading = false; + this.updateCoinInfoUI(); + return; + } + + // 调用API + const response = await fetch('/api/aimodelapp/coins', { + method: 'GET', + headers: { + 'Authorization': `Bearer ${token}` + } + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || '获取萌芽币信息失败'); + } + + const data = await response.json(); + + if (data.success) { + // 更新状态 + this.coins = data.data.coins; + this.aiCost = data.data.ai_cost; + this.canUseAi = data.data.can_use_ai; + this.username = data.data.username; + this.usageCount = data.data.usage_count; + this.recentUsage = data.data.recent_usage || []; + this.isLoaded = true; + } else { + throw new Error(data.message || '获取萌芽币信息失败'); + } + } catch (error) { + console.error('加载萌芽币信息失败:', error); + this.error = error.message || '获取萌芽币信息失败'; + } finally { + this.isLoading = false; + this.updateCoinInfoUI(); + } + } + + /** + * 格式化API类型 + */ + formatApiType(apiType) { + const typeMap = { + 'chat': 'AI聊天', + 'name-analysis': '姓名评测', + 'variable-naming': '变量命名', + 'poetry': 'AI写诗', + 'translation': 'AI翻译', + 'classical_conversion': '文言文转换', + 'expression-maker': '表情制作', + 'linux-command': 'Linux命令' + }; + + return typeMap[apiType] || apiType; + } + + /** + * 格式化日期 + */ + formatDate(isoString) { + try { + const date = new Date(isoString); + return `${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`; + } catch (e) { + return isoString; + } + } + + /** + * 检查是否有足够的萌芽币 + */ + hasEnoughCoins() { + return this.canUseAi; + } + + /** + * 显示萌芽币不足提示 + */ + showInsufficientCoinsMessage() { + alert(`萌芽币余额不足!\n当前余额:${this.coins},需要:${this.aiCost}\n请通过每日签到等方式获取更多萌芽币。`); + } + + /** + * 在API调用前检查萌芽币 + * @returns {boolean} 是否有足够的萌芽币 + */ + checkBeforeApiCall() { + // 强制刷新萌芽币状态 + this.loadCoinsInfo().then(() => { + // 检查余额 + if (!this.hasEnoughCoins()) { + this.showInsufficientCoinsMessage(); + return false; + } + return true; + }); + + // 使用当前缓存的状态进行快速检查 + if (!this.hasEnoughCoins()) { + this.showInsufficientCoinsMessage(); + return false; + } + return true; + } +} + +// 创建全局实例 +const coinManager = new window.CoinManager = new CoinManager(); + +// 导出实例 +export default coinManager; diff --git a/InfoGenie-frontend/src/pages/AiModelPage.js b/InfoGenie-frontend/src/pages/AiModelPage.js index e89157bb..7adf4d89 100755 --- a/InfoGenie-frontend/src/pages/AiModelPage.js +++ b/InfoGenie-frontend/src/pages/AiModelPage.js @@ -284,6 +284,26 @@ const AiModelPage = () => { const closeEmbedded = () => { setEmbeddedApp(null); }; + + // 在iframe加载时注入token + const handleIframeLoad = (e) => { + try { + const iframe = e.target; + const token = localStorage.getItem('token'); + + if (iframe && iframe.contentWindow && token) { + // 将token传递给iframe + iframe.contentWindow.localStorage.setItem('token', token); + + // 确保coin-manager.js已加载 + if (iframe.contentWindow.coinManager) { + iframe.contentWindow.coinManager.loadCoinsInfo(); + } + } + } catch (error) { + console.error('iframe通信错误:', error); + } + }; @@ -393,7 +413,36 @@ const AiModelPage = () => { )} - {/* 内嵌显示组件 */} + {/* 萌芽币提示 */} + {isLoggedIn && ( +
+

+ 💰 + 萌芽币消费提示 +

+

+ 每次使用AI功能将消耗100萌芽币,无论成功与否。当萌芽币余额不足时,无法使用AI功能。 +

+

+ 您可以通过每日签到获得300萌芽币。详细的萌芽币余额和使用记录将显示在各AI应用的右上角。 +

+
+ )} + + {/* 内嵌显示组件 */} {embeddedApp && ( e.stopPropagation()}> @@ -407,6 +456,7 @@ const AiModelPage = () => { diff --git a/InfoGenie-frontend/src/utils/api.js b/InfoGenie-frontend/src/utils/api.js index 92564528..9cee216a 100755 --- a/InfoGenie-frontend/src/utils/api.js +++ b/InfoGenie-frontend/src/utils/api.js @@ -95,6 +95,12 @@ export const userAPI = { +// AI模型相关API +export const aiModelAPI = { + // 获取萌芽币余额和使用历史 + getCoins: () => api.get('/api/aimodelapp/coins'), +}; + // 健康检查 export const healthAPI = { check: () => api.get('/api/health'), diff --git a/InfoGenie-frontend/前端架构文档.md b/InfoGenie-frontend/前端架构文档.md index e69de29b..97ce4b22 100755 --- a/InfoGenie-frontend/前端架构文档.md +++ b/InfoGenie-frontend/前端架构文档.md @@ -0,0 +1,381 @@ +# InfoGenie 前端架构文档 + +## 项目概述 + +InfoGenie 是一个基于前后端分离架构的全栈 Web 应用,前端采用 React 单页应用(SPA)架构,结合静态 HTML 页面实现丰富的功能模块。后端提供 RESTful API 接口,支持用户认证、数据获取等核心功能。 + +## 技术栈 + +### 核心框架 +- **React 18.2.0**: 前端 UI 框架,使用函数式组件和 Hooks +- **React Router DOM 6.15.0**: 客户端路由管理 +- **Axios 1.5.0**: HTTP 客户端,用于后端 API 调用 + +### 样式和 UI +- **styled-components 6.0.7**: CSS-in-JS 样式解决方案 +- **react-icons 4.11.0**: 图标库 +- **react-hot-toast 2.4.1**: 通知提示组件 + +### 开发工具 +- **Create React App**: 项目脚手架 +- **ESLint**: 代码规范检查 +- **Service Worker**: PWA 支持 + +## 架构设计 + +### 整体架构 +``` +前端应用 +├── React SPA (主要页面) +│ ├── 用户认证系统 +│ ├── 导航和布局 +│ ├── 页面路由 +│ └── 用户管理 +└── 静态 HTML 页面 + ├── API 数据展示页面 + ├── 小游戏页面 + └── AI 模型工具页面 +``` + +### 文件结构 +``` +src/ +├── components/ # 公共组件 +│ ├── Header.js # 顶部导航栏 +│ ├── Navigation.js # 底部导航栏(移动端) +│ └── Footer.js # 页脚 +├── pages/ # 页面组件 +│ ├── HomePage.js # 首页 +│ ├── LoginPage.js # 登录页面 +│ ├── Api60sPage.js # API 60s 页面 +│ ├── SmallGamePage.js # 小游戏页面 +│ ├── AiModelPage.js # AI 模型页面 +│ └── UserProfilePage.js # 用户资料页面 +├── contexts/ # React Context +│ └── UserContext.js # 用户状态管理 +├── config/ # 配置文件 +│ └── StaticPageConfig.js # 静态页面配置 +├── utils/ # 工具函数 +│ └── api.js # API 调用封装 +└── styles/ # 全局样式 +``` + +## API 接口设计 + +### 基础配置 +- **Base URL**: `https://infogenie.api.shumengya.top` (这是生产环境)(可通过环境变量 `REACT_APP_API_URL` 配置测试环境) +- **认证方式**: JWT Bearer Token +- **请求格式**: JSON +- **响应格式**: JSON +- **超时时间**: 10秒 + +### 认证相关接口 + +#### 发送验证码 +```http +POST /api/auth/send-verification +Content-Type: application/json + +{ + "email": "user@example.com" +} +``` + +#### 验证验证码 +```http +POST /api/auth/verify-code +Content-Type: application/json + +{ + "email": "user@example.com", + "code": "123456" +} +``` + +#### 用户登录 +```http +POST /api/auth/login +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "password" +} +``` + +#### 用户注册 +```http +POST /api/auth/register +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "password", + "verification_code": "123456" +} +``` + +#### 用户登出 +```http +POST /api/auth/logout +Authorization: Bearer +``` + +#### 检查登录状态 +```http +GET /api/auth/check +Authorization: Bearer +``` + +### 用户管理接口 + +#### 获取用户资料 +```http +GET /api/user/profile +Authorization: Bearer +``` + +#### 修改密码 +```http +POST /api/user/change-password +Authorization: Bearer +Content-Type: application/json + +{ + "old_password": "old_password", + "new_password": "new_password" +} +``` + +#### 获取用户统计 +```http +GET /api/user/stats +Authorization: Bearer +``` + +#### 获取游戏数据 +```http +GET /api/user/game-data +Authorization: Bearer +``` + +#### 用户签到 +```http +POST /api/user/checkin +Authorization: Bearer +``` + +#### 删除账户 +```http +POST /api/user/delete +Authorization: Bearer +Content-Type: application/json + +{ + "password": "password" +} +``` + +### 数据展示接口 + +前端包含大量静态页面用于展示各种 API 数据,这些页面直接调用后端提供的公开接口: + +#### 热搜榜单系列 +- 百度实时热搜: `GET /v2/baidu/realtime` +- 百度贴吧话题榜: `GET /v2/baidu/tieba` +- 哔哩哔哩热搜榜: `GET /v2/bilibili/hot` +- 抖音热搜榜: `GET /v2/douyin/hot` +- 头条热搜榜: `GET /v2/toutiao/hot` +- 微博热搜榜: `GET /v2/weibo/hot` +- 小红书热点: `GET /v2/xiaohongshu/hot` +- 知乎热门话题: `GET /v2/zhihu/hot` +- Hacker News 榜单: `GET /v2/hackernews` + +#### 日更资讯系列 +- 必应每日壁纸: `GET /v2/bing/wallpaper` +- 历史上的今天: `GET /v2/history/today` +- 每日国际汇率: `GET /v2/exchange/rates` +- 每天60s读懂世界: `GET /v2/60s/world` + +#### 实用功能系列 +- 百度百科词条: `GET /v2/baike/search?keyword={keyword}` +- 公网IP地址: `GET /v2/ip/public` +- 哈希解压压缩: `POST /v2/hash/{algorithm}` +- 链接OG信息: `GET /v2/og?url={url}` +- 密码强度检测: `POST /v2/password/strength` +- 农历信息: `GET /v2/calendar/lunar?date={date}` +- 配色方案: `GET /v2/color/schemes` +- 身体健康分析: `POST /v2/health/analysis` +- 生成二维码: `POST /v2/qrcode/generate` +- 实时天气: `GET /v2/weather?location={location}` +- 随机密码生成器: `GET /v2/password/random` +- 随机颜色: `GET /v2/color/random` +- 天气预报: `GET /v2/weather/forecast?location={location}` +- 在线翻译: `POST /v2/translate` +- EpicGames免费游戏: `GET /v2/epic/free-games` + +#### 娱乐消遣系列 +- 随机唱歌音频: `GET /v2/entertainment/random-song` +- 随机发病文学: `GET /v2/entertainment/random-meme` +- 随机搞笑段子: `GET /v2/entertainment/random-joke` +- 随机冷笑话: `GET /v2/entertainment/random-pun` +- 随机一言: `GET /v2/entertainment/random-quote` +- 随机运势: `GET /v2/entertainment/random-fortune` +- 随机JavaScript趣味题: `GET /v2/entertainment/random-js-quiz` +- 随机KFC文案: `GET /v2/entertainment/random-kfc` + +## 状态管理 + +### 用户状态管理 +使用 React Context 进行全局状态管理: + +```javascript +const UserContext = createContext(); + +export const UserProvider = ({ children }) => { + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isLoggedIn, setIsLoggedIn] = useState(false); + + // 用户登录、登出、状态检查等方法 +}; +``` + +### 本地存储 +- 用户信息和 Token 存储在 localStorage 中 +- 页面刷新后自动恢复用户状态 + +## 路由设计 + +```javascript +const App = () => { + return ( + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + ); +}; +``` + +## 响应式设计 + +- 移动优先设计理念 +- 使用 CSS Grid 和 Flexbox 实现响应式布局 +- 媒体查询适配不同屏幕尺寸 +- 移动端使用底部导航栏,桌面端使用顶部导航 + +## 安全考虑 + +### 前端安全措施 +- JWT Token 自动过期和刷新 +- XSS 防护:使用 React 自动转义 +- CSRF 防护:使用 SameSite Cookie +- 输入验证:前端表单验证 + +### API 安全要求 +- 所有敏感接口需要 JWT 认证 +- Token 存储在 localStorage,需要后端验证 +- 密码等敏感信息前端不存储明文 +- API 请求包含 CORS 配置 + +## 部署和构建 + +### 构建命令 +```bash +npm run build # 生产环境构建 +npm start # 开发环境启动 +``` + +### 环境变量 +- `REACT_APP_API_URL`: 后端 API 基础地址 +- 支持 `.env` 文件配置不同环境的变量 + +### PWA 支持 +- 注册 Service Worker 实现离线缓存 +- Web App Manifest 支持安装到桌面 + +## 与后端协作要点 + +1. **API 接口约定**: 遵循 RESTful 设计原则,统一响应格式 +2. **错误处理**: 后端返回统一的错误格式,前端统一处理 +3. **认证流程**: JWT Token 的生成、验证和刷新机制 +4. **数据格式**: 前后端约定清晰的数据结构 +5. **跨域配置**: 后端需要配置 CORS 允许前端域名 +6. **API 版本管理**: 使用 `/v2/` 前缀进行版本控制 +7. **性能优化**: 考虑 API 响应时间和前端缓存策略 + +## 萌芽币消费系统 + +### 系统概述 +萌芽币是平台内部的虚拟货币,用于限制和管理用户对AI功能的使用频率。每次调用AI功能需消耗100萌芽币,当用户萌芽币不足时,无法使用AI功能。 + +### 技术实现 +1. **萌芽币管理器**: `/public/aimodelapp/coin-manager.js` + - 管理用户萌芽币余额和使用记录 + - 提供UI组件显示萌芽币信息 + - 实现API调用前的余额检查 + +2. **API集成**: + - 在 `/src/utils/api.js` 中添加萌芽币查询接口 + - 所有AI功能API调用必须添加JWT Token认证 + - API调用后自动刷新萌芽币余额显示 + +3. **用户体验**: + - 在页面右上角显示萌芽币余额和使用记录 + - 当萌芽币不足时,提供友好的提示 + - 引导用户通过签到等方式获取更多萌芽币 + +### 接口设计 +```http +GET /api/aimodelapp/coins +Authorization: Bearer + +响应: +{ + "success": true, + "data": { + "coins": 200, + "ai_cost": 100, + "can_use_ai": true, + "username": "用户名", + "usage_count": 5, + "recent_usage": [ + { + "api_type": "chat", + "cost": 100, + "timestamp": "2025-09-16T11:15:47.285720" + }, + ... + ] + }, + "message": "当前萌芽币余额: 200" +} +``` + +### 页面集成流程 +1. 引入萌芽币管理器 JavaScript 文件 +2. 在API调用前检查萌芽币余额 +3. 处理API响应中的萌芽币相关错误 +4. API调用后刷新萌芽币信息 + +详细集成步骤请参考 [前端萌芽币消费系统集成文档](/前端萌芽币消费系统集成文档.md) + +## 后续扩展建议 + +1. **状态管理升级**: 可考虑引入 Redux 或 Zustand 进行更复杂的状态管理 +2. **组件库**: 可引入 Ant Design 或 Material-UI 统一 UI 组件 +3. **测试覆盖**: 添加单元测试和集成测试 +4. **性能监控**: 集成前端性能监控工具 +5. **国际化**: 支持多语言切换功能 +6. **萌芽币系统扩展**: + - 实现萌芽币充值功能 + - 针对不同AI功能设置差异化定价 + - 添加萌芽币消费统计和分析功能 \ No newline at end of file diff --git a/InfoGenie-frontend/前端萌芽币消费系统集成文档.md b/InfoGenie-frontend/前端萌芽币消费系统集成文档.md new file mode 100644 index 00000000..64896fb9 --- /dev/null +++ b/InfoGenie-frontend/前端萌芽币消费系统集成文档.md @@ -0,0 +1,100 @@ +# InfoGenie前端萌芽币消费系统集成文档 + +## 概述 + +本文档描述了InfoGenie前端如何与后端的萌芽币消费系统进行集成。后端已实现AI模型应用每次调用消耗100萌芽币的功能,前端需要相应地支持显示萌芽币余额、使用记录,并在API调用前检查余额是否充足。 + +## 实现细节 + +### 1. API调用 + +新增了获取萌芽币余额和使用历史的API调用: + +```javascript +// 在 /src/utils/api.js 中添加 +export const aiModelAPI = { + // 获取萌芽币余额和使用历史 + getCoins: () => api.get('/api/aimodelapp/coins'), +}; +``` + +### 2. 萌芽币管理器 + +创建了统一的萌芽币管理工具 `/public/aimodelapp/coin-manager.js`,提供以下功能: + +- 获取和显示用户萌芽币余额 +- 显示最近的AI使用记录 +- 在调用AI API前检查萌芽币余额是否充足 +- 在API调用成功后更新萌芽币信息 + +### 3. 前端集成 + +所有AI模型应用页面都需要进行以下修改: + +1. 引入萌芽币管理器脚本: +```html + +``` + +2. 在API调用前添加萌芽币检查: +```javascript +// 检查萌芽币余额是否足够 +if (window.coinManager && !window.coinManager.checkBeforeApiCall()) { + return; +} +``` + +3. 确保所有AI API调用都添加JWT Token认证: +```javascript +const token = localStorage.getItem('token'); +// 添加到请求头 +headers: { + 'Authorization': `Bearer ${token}` +} +``` + +4. 在API调用成功后刷新萌芽币信息: +```javascript +if (window.coinManager) { + window.coinManager.loadCoinsInfo(); +} +``` + +### 4. 萌芽币提示显示 + +萌芽币管理器会在页面右上角显示一个悬浮窗口,包含: +- 当前萌芽币余额 +- 每次调用消耗的萌芽币数量 +- 最近的使用记录 +- 当余额不足时的警告提示 + +### 5. 用户体验优化 + +- 在API调用失败时,会检查是否是因为萌芽币不足导致的,并给出相应提示 +- 引导用户通过每日签到等方式获取更多萌芽币 +- 实时显示萌芽币余额变化 + +## 使用示例 + +以AI变量命名助手为例,已完成集成: + +1. 引入coin-manager.js +2. 修改API调用函数添加Token认证 +3. 添加萌芽币检查逻辑 +4. 添加错误处理,区分普通错误和萌芽币不足错误 + +## 后续工作 + +为所有AI模型应用页面添加相同的萌芽币集成,包括: +- AI写诗小助手 +- AI姓名评测 +- AI翻译助手 +- AI文章转文言文 +- AI生成表情包 +- AI生成Linux命令 + +## 注意事项 + +- 萌芽币消费系统只对AI模型应用有效,其他功能不消耗萌芽币 +- 每次调用AI API都会消耗100萌芽币,无论成功与否 +- 用户可以通过每日签到获取萌芽币 diff --git a/InfoGenie-frontend/萌芽币消费系统集成报告.md b/InfoGenie-frontend/萌芽币消费系统集成报告.md new file mode 100644 index 00000000..47332179 --- /dev/null +++ b/InfoGenie-frontend/萌芽币消费系统集成报告.md @@ -0,0 +1,64 @@ +# InfoGenie前端萌芽币消费系统集成报告 + +## 完成工作概述 + +根据后端新增的萌芽币消费系统需求,已成功在前端项目中完成了相应的功能集成。具体完成了以下工作: + +### 1. API工具扩展 +在`/src/utils/api.js`中添加了萌芽币余额查询API: +```javascript +export const aiModelAPI = { + // 获取萌芽币余额和使用历史 + getCoins: () => api.get('/api/aimodelapp/coins'), +}; +``` + +### 2. 萌芽币管理工具实现 +创建了`/public/aimodelapp/coin-manager.js`文件,实现了以下功能: +- 萌芽币余额和使用历史查询 +- 用户友好的UI显示 +- AI API调用前的余额检查 +- 错误处理和用户提示 + +### 3. AI变量命名助手集成示例 +完成了AI变量命名助手的萌芽币系统集成: +- 引入了coin-manager.js +- 添加了JWT Token认证 +- 实现了API调用前的余额检查 +- 处理了萌芽币不足的错误情况 +- API调用后自动刷新萌芽币信息 + +### 4. AI模型页面增强 +在`/src/pages/AiModelPage.js`中添加了以下功能: +- 萌芽币消费提示说明 +- iframe加载时的token传递 +- 确保嵌入应用正确加载萌芽币管理器 + +### 5. 文档更新 +完成了两份文档的更新: +1. `/前端架构文档.md`: 添加了萌芽币消费系统的架构说明 +2. `/前端萌芽币消费系统集成文档.md`: 创建了详细的集成指南 + +## 后续工作建议 + +1. 按照集成文档完成其余所有AI应用的萌芽币系统集成: + - AI写诗小助手 + - AI姓名评测 + - AI语言翻译助手 + - AI文章转文言文 + - AI生成表情包 + - AI生成Linux命令 + +2. 用户体验优化: + - 在用户资料页面显示萌芽币余额和完整的使用历史 + - 添加萌芽币获取引导(如签到提醒) + - 考虑实现萌芽币充值功能 + +3. 性能和安全性优化: + - 优化币管理器的加载性能 + - 添加币管理器的错误处理和重试机制 + - 确保token传递的安全性 + +## 结论 + +萌芽币消费系统的前端集成已基本完成,示例应用可以正常工作。系统实现了后端要求的所有功能,并提供了良好的用户体验。后续只需按照文档中的步骤,将相同的集成方式应用到其余AI应用中即可完成全部工作。