添加令牌验证和推荐系统接口

Change-Id: I2d318c167683a5106ced96047ab9f39b33b75bd1
diff --git a/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc b/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc
index 29c786d..75ccdab 100644
--- a/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc
+++ b/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc b/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc
new file mode 100644
index 0000000..ae84b70
--- /dev/null
+++ b/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/blueprints/scheduler.py b/Merge/back_rhj/app/blueprints/scheduler.py
new file mode 100644
index 0000000..038f8f4
--- /dev/null
+++ b/Merge/back_rhj/app/blueprints/scheduler.py
@@ -0,0 +1,165 @@
+"""
+定时任务管理API蓝图
+提供定时任务的启动、停止、状态查询等接口
+"""
+from flask import Blueprint, jsonify, request, current_app
+from functools import wraps
+
+scheduler_bp = Blueprint('scheduler', __name__, url_prefix='/api/scheduler')
+
+def admin_required(f):
+    """装饰器:需要管理员权限"""
+    @wraps(f)
+    def decorated(*args, **kwargs):
+        # 这里可以添加管理员权限验证逻辑
+        # 暂时允许所有请求通过
+        return f(*args, **kwargs)
+    return decorated
+
+@scheduler_bp.route('/status', methods=['GET'])
+def get_scheduler_status():
+    """获取定时任务状态"""
+    try:
+        scheduler_manager = current_app.scheduler_manager
+        status = scheduler_manager.get_task_status()
+        
+        return jsonify({
+            'success': True,
+            'data': status,
+            'message': '获取定时任务状态成功'
+        })
+    except Exception as e:
+        return jsonify({
+            'success': False,
+            'message': f'获取定时任务状态失败: {str(e)}'
+        }), 500
+
+@scheduler_bp.route('/start', methods=['POST'])
+@admin_required
+def start_scheduler():
+    """启动定时任务"""
+    try:
+        data = request.get_json() or {}
+        interval_minutes = data.get('interval_minutes', 1)
+        
+        # 验证间隔时间
+        if not isinstance(interval_minutes, (int, float)) or interval_minutes <= 0:
+            return jsonify({
+                'success': False,
+                'message': '无效的间隔时间,必须是大于0的数字'
+            }), 400
+            
+        scheduler_manager = current_app.scheduler_manager
+        scheduler_manager.start_graph_rebuild_task(interval_minutes)
+        
+        return jsonify({
+            'success': True,
+            'message': f'定时任务已启动,间隔: {interval_minutes}分钟'
+        })
+    except Exception as e:
+        return jsonify({
+            'success': False,
+            'message': f'启动定时任务失败: {str(e)}'
+        }), 500
+
+@scheduler_bp.route('/stop', methods=['POST'])
+@admin_required
+def stop_scheduler():
+    """停止定时任务"""
+    try:
+        scheduler_manager = current_app.scheduler_manager
+        scheduler_manager.stop_graph_rebuild_task()
+        
+        return jsonify({
+            'success': True,
+            'message': '定时任务已停止'
+        })
+    except Exception as e:
+        return jsonify({
+            'success': False,
+            'message': f'停止定时任务失败: {str(e)}'
+        }), 500
+
+@scheduler_bp.route('/update-interval', methods=['POST'])
+@admin_required
+def update_interval():
+    """更新任务间隔"""
+    try:
+        data = request.get_json()
+        if not data or 'interval_minutes' not in data:
+            return jsonify({
+                'success': False,
+                'message': '缺少interval_minutes参数'
+            }), 400
+            
+        interval_minutes = data['interval_minutes']
+        
+        # 验证间隔时间
+        if not isinstance(interval_minutes, (int, float)) or interval_minutes <= 0:
+            return jsonify({
+                'success': False,
+                'message': '无效的间隔时间,必须是大于0的数字'
+            }), 400
+            
+        scheduler_manager = current_app.scheduler_manager
+        scheduler_manager.update_task_interval(interval_minutes)
+        
+        return jsonify({
+            'success': True,
+            'message': f'任务间隔已更新为 {interval_minutes}分钟'
+        })
+    except Exception as e:
+        return jsonify({
+            'success': False,
+            'message': f'更新任务间隔失败: {str(e)}'
+        }), 500
+
+@scheduler_bp.route('/rebuild-now', methods=['POST'])
+@admin_required
+def rebuild_graph_now():
+    """立即执行一次图重建"""
+    try:
+        scheduler_manager = current_app.scheduler_manager
+        
+        # 在新线程中执行,避免阻塞请求
+        import threading
+        thread = threading.Thread(target=scheduler_manager.rebuild_graph_job)
+        thread.start()
+        
+        return jsonify({
+            'success': True,
+            'message': '图重建任务已开始执行'
+        })
+    except Exception as e:
+        return jsonify({
+            'success': False,
+            'message': f'执行图重建失败: {str(e)}'
+        }), 500
+
+@scheduler_bp.route('/logs', methods=['GET'])
+def get_rebuild_logs():
+    """获取重建日志统计"""
+    try:
+        scheduler_manager = current_app.scheduler_manager
+        status = scheduler_manager.get_task_status()
+        
+        log_info = {
+            'rebuild_count': status['rebuild_count'],
+            'error_count': status['error_count'],
+            'last_rebuild_time': status['last_rebuild_time'],
+            'success_rate': (
+                ((status['rebuild_count'] - status['error_count']) / status['rebuild_count'] * 100)
+                if status['rebuild_count'] > 0 else 0
+            )
+        }
+        
+        return jsonify({
+            'success': True,
+            'data': log_info,
+            'message': '获取重建日志成功'
+        })
+    except Exception as e:
+        return jsonify({
+            'success': False,
+            'message': f'获取重建日志失败: {str(e)}'
+        }), 500