diff --git a/.DS_Store b/.DS_Store index cd91564..f1e03aa 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/=2.0 b/=2.0 new file mode 100644 index 0000000..c11c4e2 --- /dev/null +++ b/=2.0 @@ -0,0 +1,41 @@ +Requirement already satisfied: tensorflow in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (2.13.1) +Requirement already satisfied: absl-py>=1.0.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (2.1.0) +Requirement already satisfied: astunparse>=1.6.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (1.6.3) +Requirement already satisfied: flatbuffers>=23.1.21 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (25.2.10) +Requirement already satisfied: gast<=0.4.0,>=0.2.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (0.3.3) +Requirement already satisfied: google-pasta>=0.1.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (0.2.0) +Requirement already satisfied: grpcio<2.0,>=1.24.3 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (1.70.0) +Requirement already satisfied: h5py>=2.9.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (3.11.0) +Requirement already satisfied: keras<2.14,>=2.13.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (2.13.1) +Requirement already satisfied: libclang>=13.0.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (18.1.1) +Requirement already satisfied: numpy<=1.24.3,>=1.22 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (1.24.3) +Requirement already satisfied: opt-einsum>=2.3.2 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (3.3.0) +Requirement already satisfied: packaging in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (24.2) +Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.20.3 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (4.25.6) +Requirement already satisfied: setuptools in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (75.1.0) +Requirement already satisfied: six>=1.12.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (1.15.0) +Requirement already satisfied: tensorboard<2.14,>=2.13 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (2.13.0) +Requirement already satisfied: tensorflow-estimator<2.14,>=2.13.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (2.13.0) +Requirement already satisfied: termcolor>=1.1.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (1.1.0) +Requirement already satisfied: typing-extensions<4.6.0,>=3.6.6 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (3.7.4.3) +Requirement already satisfied: wrapt>=1.11.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (1.12.1) +Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorflow) (0.34.0) +Requirement already satisfied: wheel<1.0,>=0.23.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from astunparse>=1.6.0->tensorflow) (0.44.0) +Requirement already satisfied: google-auth<3,>=1.6.3 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorboard<2.14,>=2.13->tensorflow) (2.38.0) +Requirement already satisfied: google-auth-oauthlib<1.1,>=0.5 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorboard<2.14,>=2.13->tensorflow) (1.0.0) +Requirement already satisfied: markdown>=2.6.8 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorboard<2.14,>=2.13->tensorflow) (3.7) +Requirement already satisfied: requests<3,>=2.21.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorboard<2.14,>=2.13->tensorflow) (2.32.3) +Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorboard<2.14,>=2.13->tensorflow) (0.7.2) +Requirement already satisfied: werkzeug>=1.0.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from tensorboard<2.14,>=2.13->tensorflow) (2.0.1) +Requirement already satisfied: cachetools<6.0,>=2.0.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from google-auth<3,>=1.6.3->tensorboard<2.14,>=2.13->tensorflow) (5.5.2) +Requirement already satisfied: pyasn1-modules>=0.2.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from google-auth<3,>=1.6.3->tensorboard<2.14,>=2.13->tensorflow) (0.4.1) +Requirement already satisfied: rsa<5,>=3.1.4 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from google-auth<3,>=1.6.3->tensorboard<2.14,>=2.13->tensorflow) (4.9) +Requirement already satisfied: requests-oauthlib>=0.7.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from google-auth-oauthlib<1.1,>=0.5->tensorboard<2.14,>=2.13->tensorflow) (2.0.0) +Requirement already satisfied: importlib-metadata>=4.4 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from markdown>=2.6.8->tensorboard<2.14,>=2.13->tensorflow) (8.5.0) +Requirement already satisfied: charset-normalizer<4,>=2 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard<2.14,>=2.13->tensorflow) (3.4.1) +Requirement already satisfied: idna<4,>=2.5 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard<2.14,>=2.13->tensorflow) (3.10) +Requirement already satisfied: urllib3<3,>=1.21.1 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard<2.14,>=2.13->tensorflow) (2.2.3) +Requirement already satisfied: certifi>=2017.4.17 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard<2.14,>=2.13->tensorflow) (2025.1.31) +Requirement already satisfied: zipp>=3.20 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from importlib-metadata>=4.4->markdown>=2.6.8->tensorboard<2.14,>=2.13->tensorflow) (3.20.2) +Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<2.14,>=2.13->tensorflow) (0.6.1) +Requirement already satisfied: oauthlib>=3.0.0 in /home/chenhm/anaconda3/envs/qin/lib/python3.8/site-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<1.1,>=0.5->tensorboard<2.14,>=2.13->tensorflow) (3.2.2) diff --git a/docker-compose.yml b/docker-compose.yml index e69de29..f096ee4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +# docker-compose.yml +version: '3' + +services: + web: + build: . + restart: always + ports: + - "5000:5000" + volumes: + - ./uploads:/app/uploads + - ./model:/app/model + environment: + - DB_HOST=27.124.22.104 + - DB_USER=ziyao + - DB_PASSWORD=ziyao123 + - DB_NAME=text_classification_system + - FLASK_APP=app.py + - FLASK_ENV=production + command: gunicorn --bind 0.0.0.0:5000 app:app --workers 4 --timeout 120 + + # 如果需要在本地运行MySQL,可以取消下面的注释 + # db: + # image: mysql:8.0 + # restart: always + # environment: + # MYSQL_ROOT_PASSWORD: root_password + # MYSQL_DATABASE: text_classification_system + # MYSQL_USER: ziyao + # MYSQL_PASSWORD: ziyao123 + # volumes: + # - mysql_data:/var/lib/mysql + # - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql + # ports: + # - "3306:3306" + +# volumes: +# mysql_data: \ No newline at end of file diff --git a/routes/auth.py b/routes/auth.py index 9093e04..a962f20 100644 --- a/routes/auth.py +++ b/routes/auth.py @@ -1,13 +1,11 @@ -from flask import Blueprint, request, jsonify, session +from flask import Blueprint, request, jsonify, session, redirect, url_for, render_template import random import string import re from datetime import datetime, timedelta from utils.db import get_db_connection, close_connection -from utils.password import hash_password from utils.email_sender import send_verification_email -from utils.password import hash_password, check_password - +from utils.password import hash_password, check_password # 移除了重复的 hash_password # 创建蓝图 auth = Blueprint('auth', __name__) @@ -41,48 +39,51 @@ def register(): return jsonify({'success': False, 'message': '密码长度必须至少为8个字符'}), 400 # 检查邮箱是否已注册 - conn = get_db_connection() - if not conn: - return jsonify({'success': False, 'message': '数据库连接失败'}), 500 + conn = None + cursor = None + try: + conn = get_db_connection() + if not conn: + return jsonify({'success': False, 'message': '数据库连接失败'}), 500 - cursor = conn.cursor(dictionary=True) - cursor.execute("SELECT id FROM users WHERE email = %s", (email,)) - existing_user = cursor.fetchone() + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT id FROM users WHERE email = %s", (email,)) + existing_user = cursor.fetchone() - if existing_user: - cursor.close() - close_connection(conn) - return jsonify({'success': False, 'message': '该邮箱已被注册'}), 400 + if existing_user: + return jsonify({'success': False, 'message': '该邮箱已被注册'}), 400 - # 生成验证码 - verification_code = ''.join(random.choices(string.digits, k=6)) + # 生成验证码 + verification_code = ''.join(random.choices(string.digits, k=6)) - # 存储验证码(实际项目中应使用Redis等带过期功能的存储) - verification_codes[email] = { - 'code': verification_code, - 'expires': datetime.now() + timedelta(minutes=30), - 'user_data': { - 'email': email, - 'password': password, - 'name': name, - 'gender': gender, - 'birth_date': birth_date + # 存储验证码 + verification_codes[email] = { + 'code': verification_code, + 'expires': datetime.now() + timedelta(minutes=30), + 'user_data': { + 'email': email, + 'password': password, + 'name': name, + 'gender': gender, + 'birth_date': birth_date + } } - } - # 发送验证邮件 - email_sent = send_verification_email(email, verification_code) + # 发送验证邮件 + email_sent = send_verification_email(email, verification_code) - cursor.close() - close_connection(conn) + if not email_sent: + return jsonify({'success': False, 'message': '验证邮件发送失败'}), 500 - if not email_sent: - return jsonify({'success': False, 'message': '验证邮件发送失败'}), 500 - - return jsonify({ - 'success': True, - 'message': '验证码已发送到您的邮箱,请查收并完成注册' - }) + return jsonify({ + 'success': True, + 'message': '验证码已发送到您的邮箱,请查收并完成注册' + }) + finally: + if cursor: + cursor.close() + if conn: + close_connection(conn) @auth.route('/verify', methods=['POST']) @@ -96,41 +97,32 @@ def verify(): email = data['email'] code = data['code'] - # 检查验证码 if email not in verification_codes: return jsonify({'success': False, 'message': '验证码不存在或已过期'}), 400 stored_data = verification_codes[email] - # 检查验证码是否过期 if datetime.now() > stored_data['expires']: del verification_codes[email] return jsonify({'success': False, 'message': '验证码已过期'}), 400 - # 检查验证码是否匹配 if code != stored_data['code']: return jsonify({'success': False, 'message': '验证码不正确'}), 400 - # 获取用户数据 user_data = stored_data['user_data'] - - # 处理空日期值 birth_date = user_data.get('birth_date') if birth_date == '' or not birth_date: birth_date = None - # 存储用户信息到数据库 - conn = get_db_connection() - if not conn: - return jsonify({'success': False, 'message': '数据库连接失败'}), 500 - - cursor = conn.cursor(dictionary=True) - + conn = None + cursor = None try: - # 哈希处理密码 - hashed_password = hash_password(user_data['password']) + conn = get_db_connection() + if not conn: + return jsonify({'success': False, 'message': '数据库连接失败'}), 500 - # 插入用户数据 + cursor = conn.cursor(dictionary=True) + hashed_password = hash_password(user_data['password']) query = """ INSERT INTO users (email, password, name, gender, birth_date) VALUES (%s, %s, %s, %s, %s) @@ -140,92 +132,89 @@ def verify(): hashed_password, user_data['name'], user_data['gender'], - birth_date # 使用处理过的birth_date值 + birth_date )) - conn.commit() - - # 清除验证码 del verification_codes[email] - return jsonify({ 'success': True, 'message': '注册成功,请登录系统' }) - except Exception as e: - conn.rollback() + if conn: + conn.rollback() return jsonify({'success': False, 'message': f'注册失败: {str(e)}'}), 500 - finally: - cursor.close() - close_connection(conn) + if cursor: + cursor.close() + if conn: + close_connection(conn) -# 在routes/auth.py现有代码的底部添加 - -@auth.route('/login', methods=['POST']) +@auth.route('/login', methods=['GET', 'POST']) # 支持 GET 和 POST def login(): - """用户登录接口""" - data = request.get_json() + """用户登录接口 (POST) 及登录页面 (GET)""" + if request.method == 'POST': + data = request.get_json() - if not all(k in data for k in ('email', 'password')): - return jsonify({'success': False, 'message': '请输入邮箱和密码'}), 400 + if not all(k in data for k in ('email', 'password')): + return jsonify({'success': False, 'message': '请输入邮箱和密码'}), 400 - email = data['email'] - password = data['password'] + email = data['email'] + password = data['password'] - # 连接数据库 - conn = get_db_connection() - if not conn: - return jsonify({'success': False, 'message': '数据库连接失败'}), 500 + conn = None + cursor = None + try: + conn = get_db_connection() + if not conn: + return jsonify({'success': False, 'message': '数据库连接失败'}), 500 - cursor = conn.cursor(dictionary=True) + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT id, email, password, name FROM users WHERE email = %s", (email,)) + user = cursor.fetchone() - try: - # 查询用户 - cursor.execute("SELECT id, email, password, name FROM users WHERE email = %s", (email,)) - user = cursor.fetchone() + if not user: + return jsonify({'success': False, 'message': '用户不存在'}), 404 - if not user: - return jsonify({'success': False, 'message': '用户不存在'}), 404 + if not check_password(user['password'], password): + return jsonify({'success': False, 'message': '密码错误'}), 401 - # 验证密码 - if not check_password(user['password'], password): - return jsonify({'success': False, 'message': '密码错误'}), 401 - - # 创建会话 - session['user_id'] = user['id'] - session['user_info'] = { - 'id': user['id'], - 'email': user['email'], - 'name': user['name'] - } - - return jsonify({ - 'success': True, - 'message': '登录成功', - 'user': { + session['user_id'] = user['id'] + session['user_info'] = { 'id': user['id'], 'email': user['email'], 'name': user['name'] } - }) - except Exception as e: - print(f"登录错误: {str(e)}") # 添加错误日志 - return jsonify({'success': False, 'message': f'登录失败: {str(e)}'}), 500 + return jsonify({ + 'success': True, + 'message': '登录成功', + 'user': session['user_info'] # 返回用户信息给前端JS + }) + except Exception as e: + print(f"登录错误: {str(e)}") + return jsonify({'success': False, 'message': f'登录失败: {str(e)}'}), 500 + finally: + if cursor: + cursor.close() + if conn: + close_connection(conn) - finally: - cursor.close() - close_connection(conn) + # GET 请求: 显示登录页面 + if 'user_id' in session: + # 如果用户已登录,重定向到 dashboard + # !!! 重要: 请确认你的 dashboard 路由 !!! + # 假设 dashboard 路由在 'classify' 蓝图下,且函数名为 'dashboard' + # 如果你的 dashboard 在主应用 app.py 中,可能是 url_for('dashboard_function_name') + return redirect(url_for('classify.dashboard')) # 修改这里如果你的 dashboard 路由不同 + return render_template('login.html') @auth.route('/logout') def logout(): """用户登出接口""" - from flask import session - # 清除会话 session.pop('user_id', None) session.pop('user_info', None) - return jsonify({'success': True, 'message': '已成功登出'}) + # 重定向到登录页面 (GET /login) + return redirect(url_for('auth.login')) diff --git a/static/js/dashboard.js b/static/js/dashboard.js index e1f15fb..0f33a81 100644 --- a/static/js/dashboard.js +++ b/static/js/dashboard.js @@ -925,3 +925,72 @@ function changePageSize(e) { loadDocuments(); } +// 添加示例文本功能 +document.querySelectorAll('.example-text').forEach(example => { + example.addEventListener('click', (e) => { + e.preventDefault(); + const category = example.dataset.category; + let exampleText = ''; + + // 根据类别加载不同的示例文本 + switch(category) { + case '体育': + exampleText = '北京时间9月18日,东京奥运会羽毛球男单决赛在东京体育馆举行。中国选手谌龙迎战丹麦名将安赛龙。最终安赛龙以2比0战胜谌龙,获得冠军。谌龙获得亚军,成为继林丹之后又一位在奥运会上夺得男单奖牌的中国选手。'; + break; + case '科技': + exampleText = '人工智能技术在过去十年取得了重大突破,特别是深度学习技术的应用。从语音识别到图像处理,从自动驾驶到医疗诊断,AI已经渗透到我们生活的方方面面。根据专家预测,未来五年内,AI将创造更多就业机会,而不是减少就业岗位。'; + break; + case '财经': + exampleText = '近日,中国人民银行发布2023年第三季度货币政策执行报告。报告显示,前三季度我国国内生产总值同比增长5.2%,经济运行总体回升向好。报告指出,将继续实施稳健的货币政策,保持流动性合理充裕,引导金融机构加大对实体经济的支持力度。'; + break; + case '娱乐': + exampleText = '第76届戛纳电影节昨日闭幕,华语电影《繁花》获得评审团大奖。导演王小帅在获奖感言中表示,这部电影讲述了中国改革开放以来普通人命运的变迁,希望通过电影让世界更好地了解当代中国。此前,该片已在国内收获超过10亿票房,成为年度现象级电影作品。'; + break; + default: + exampleText = '这是一段示例文本,请选择具体类别查看相关示例。'; + } + + // 填充到文本输入框 + elements.textInput.value = exampleText; + }); +}); + +// 为上传区域添加拖放功能 +const dropArea = document.getElementById('drop-area'); +if (dropArea) { + ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { + dropArea.addEventListener(eventName, preventDefaults, false); + }); + + function preventDefaults(e) { + e.preventDefault(); + e.stopPropagation(); + } + + ['dragenter', 'dragover'].forEach(eventName => { + dropArea.addEventListener(eventName, highlight, false); + }); + + ['dragleave', 'drop'].forEach(eventName => { + dropArea.addEventListener(eventName, unhighlight, false); + }); + + function highlight() { + dropArea.classList.add('highlight'); + } + + function unhighlight() { + dropArea.classList.remove('highlight'); + } + + dropArea.addEventListener('drop', handleDrop, false); + + function handleDrop(e) { + const dt = e.dataTransfer; + const files = dt.files; + + if (files.length) { + elements.fileUpload.files = files; + } + } +} diff --git a/static/js/theme.js b/static/js/theme.js index 4334eb5..34f6666 100644 --- a/static/js/theme.js +++ b/static/js/theme.js @@ -18,3 +18,5 @@ document.addEventListener('DOMContentLoaded', function() { const savedTheme = localStorage.getItem('theme') || 'light'; document.documentElement.setAttribute('data-theme', savedTheme); }); + +