init: RAG 知识库服务初始提交
- 后端 API(Flask + Gunicorn) - RAG 引擎(混合检索 + 云端 Reranker + 引用溯源) - 文档解析(MinerU + 多格式支持) - Docker 生产部署配置 - 排除前端项目、敏感配置、模型文件
This commit is contained in:
311
api/sync_routes.py
Normal file
311
api/sync_routes.py
Normal file
@@ -0,0 +1,311 @@
|
||||
"""
|
||||
知识库同步 API
|
||||
|
||||
本模块提供文档同步服务的管理接口,包括:
|
||||
- 手动触发同步
|
||||
- 同步状态查询
|
||||
- 文件监控控制
|
||||
|
||||
路由列表:
|
||||
POST /sync : 手动触发同步
|
||||
GET /sync/status : 获取同步状态
|
||||
GET /sync/history : 同步历史记录
|
||||
GET /sync/changes : 变更日志
|
||||
POST /sync/start : 启动文件监控
|
||||
POST /sync/stop : 停止文件监控
|
||||
|
||||
架构说明:
|
||||
- 同步服务负责检测文档变更并自动向量化
|
||||
- 订阅通知功能由后端服务负责
|
||||
- 权限验证由后端网关完成
|
||||
|
||||
同步流程:
|
||||
1. 扫描文档目录
|
||||
2. 计算文件哈希,与历史记录对比
|
||||
3. 检测新增、修改、删除的文件
|
||||
4. 解析变更文件并更新向量库
|
||||
|
||||
Example:
|
||||
curl -X POST http://localhost:5001/sync \\
|
||||
-H "Authorization: Bearer mock-token-admin"
|
||||
"""
|
||||
|
||||
from typing import Optional, Tuple, Any
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from auth.gateway import require_gateway_auth
|
||||
from core.status_codes import SYNC_SUCCESS, SYNC_ERROR, INTERNAL_ERROR
|
||||
from api.response_utils import success_response, error_response
|
||||
|
||||
sync_bp = Blueprint('sync', __name__)
|
||||
|
||||
|
||||
def _get_sync_service() -> Optional[Any]:
|
||||
"""
|
||||
获取同步服务实例
|
||||
|
||||
Returns:
|
||||
同步服务实例,不可用时返回 None
|
||||
"""
|
||||
try:
|
||||
return current_app.config.get('SYNC_SERVICE')
|
||||
except Exception as e:
|
||||
logger.debug(f"获取同步服务失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def _require_sync_service() -> Tuple[Optional[Any], Optional[Tuple]]:
|
||||
"""
|
||||
检查同步服务是否可用
|
||||
|
||||
Returns:
|
||||
元组 (sync_service, error_response):
|
||||
- 成功时 error_response 为 None
|
||||
- 失败时 sync_service 为 None
|
||||
"""
|
||||
service = _get_sync_service()
|
||||
if not service:
|
||||
return None, error_response(
|
||||
error="SERVICE_UNAVAILABLE",
|
||||
error_code=INTERNAL_ERROR,
|
||||
message="同步服务未启用",
|
||||
http_status=503
|
||||
)
|
||||
return service, None
|
||||
|
||||
|
||||
# ==================== 同步 API ====================
|
||||
|
||||
@sync_bp.route('/sync', methods=['POST'])
|
||||
@require_gateway_auth
|
||||
def trigger_sync() -> Tuple[Any, int]:
|
||||
"""
|
||||
手动触发知识库同步
|
||||
|
||||
扫描文档目录,检测变更并执行向量化处理。
|
||||
|
||||
请求体 (可选):
|
||||
{
|
||||
"collection": "向量库名称", // 可选,不传则同步所有
|
||||
"full_sync": false // 是否全量同步
|
||||
}
|
||||
|
||||
Returns:
|
||||
成功: {"success": true, "data": {"result": {...}}}
|
||||
失败: {"error": "...", "error_code": "..."}
|
||||
|
||||
Example:
|
||||
curl -X POST http://localhost:5001/sync \\
|
||||
-H "Authorization: Bearer mock-token-admin"
|
||||
"""
|
||||
service, err = _require_sync_service()
|
||||
if err:
|
||||
return err
|
||||
|
||||
try:
|
||||
result = service.sync_now()
|
||||
return success_response(
|
||||
data={"result": result.to_dict() if hasattr(result, 'to_dict') else result},
|
||||
status_code=SYNC_SUCCESS,
|
||||
message="同步完成"
|
||||
)
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error="SYNC_ERROR",
|
||||
error_code=SYNC_ERROR,
|
||||
message=str(e),
|
||||
http_status=500
|
||||
)
|
||||
|
||||
|
||||
@sync_bp.route('/sync/status', methods=['GET'])
|
||||
@require_gateway_auth
|
||||
def get_sync_status() -> Tuple[Any, int]:
|
||||
"""
|
||||
获取同步状态
|
||||
|
||||
返回同步服务的当前状态,包括:
|
||||
- 是否启用
|
||||
- 文件监控是否运行
|
||||
- 最后同步时间
|
||||
- 跟踪的文档数量
|
||||
|
||||
Returns:
|
||||
{
|
||||
"enabled": bool,
|
||||
"monitoring": bool,
|
||||
"last_sync": "ISO 8601",
|
||||
"documents_tracked": N
|
||||
}
|
||||
"""
|
||||
service, err = _require_sync_service()
|
||||
if err:
|
||||
return jsonify({
|
||||
"status": "failed",
|
||||
"status_code": INTERNAL_ERROR,
|
||||
"enabled": False,
|
||||
"message": "同步服务未启用"
|
||||
})
|
||||
|
||||
try:
|
||||
# 获取状态信息
|
||||
status = {
|
||||
"enabled": True,
|
||||
"monitoring": service.is_running() if hasattr(service, 'is_running') else False,
|
||||
"last_sync": None,
|
||||
"documents_tracked": 0
|
||||
}
|
||||
|
||||
# 尝试获取更多状态信息
|
||||
if hasattr(service, 'get_status'):
|
||||
status.update(service.get_status())
|
||||
|
||||
return jsonify(status)
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
"status": "failed",
|
||||
"status_code": INTERNAL_ERROR,
|
||||
"enabled": True,
|
||||
"error": str(e)
|
||||
})
|
||||
|
||||
|
||||
@sync_bp.route('/sync/history', methods=['GET'])
|
||||
@require_gateway_auth
|
||||
def get_sync_history() -> Tuple[Any, int]:
|
||||
"""
|
||||
获取同步历史
|
||||
|
||||
返回最近的同步操作记录。
|
||||
|
||||
查询参数:
|
||||
limit: 返回数量限制(默认 20)
|
||||
|
||||
Returns:
|
||||
{"history": [...]}
|
||||
"""
|
||||
service, err = _require_sync_service()
|
||||
if err:
|
||||
return err
|
||||
|
||||
limit = request.args.get('limit', 20, type=int)
|
||||
|
||||
try:
|
||||
history = service.get_sync_history(limit=limit) if hasattr(service, 'get_sync_history') else []
|
||||
return jsonify({"history": history})
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error="SYNC_ERROR",
|
||||
error_code=SYNC_ERROR,
|
||||
message=str(e),
|
||||
http_status=500
|
||||
)
|
||||
|
||||
|
||||
@sync_bp.route('/sync/changes', methods=['GET'])
|
||||
@require_gateway_auth
|
||||
def get_change_logs() -> Tuple[Any, int]:
|
||||
"""
|
||||
获取变更日志
|
||||
|
||||
返回文档变更的详细记录,包括新增、修改、删除等操作。
|
||||
|
||||
查询参数:
|
||||
limit: 返回数量限制(默认 50)
|
||||
collection: 过滤指定向量库(可选)
|
||||
|
||||
Returns:
|
||||
{"changes": [...]}
|
||||
"""
|
||||
service, err = _require_sync_service()
|
||||
if err:
|
||||
return err
|
||||
|
||||
limit = request.args.get('limit', 50, type=int)
|
||||
collection = request.args.get('collection')
|
||||
|
||||
try:
|
||||
changes = service.get_change_logs(limit=limit, collection=collection) if hasattr(service, 'get_change_logs') else []
|
||||
return jsonify({"changes": changes})
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error="SYNC_ERROR",
|
||||
error_code=SYNC_ERROR,
|
||||
message=str(e),
|
||||
http_status=500
|
||||
)
|
||||
|
||||
|
||||
@sync_bp.route('/sync/start', methods=['POST'])
|
||||
@require_gateway_auth
|
||||
def start_sync_monitor() -> Tuple[Any, int]:
|
||||
"""
|
||||
启动文件监控
|
||||
|
||||
启用实时文件监控,自动检测文档变更并触发同步。
|
||||
适用于需要实时更新的场景。
|
||||
|
||||
Returns:
|
||||
{"status": "success", "message": "文件监控已启动"}
|
||||
|
||||
Note:
|
||||
文件监控会持续运行,直到调用 /sync/stop 或服务重启
|
||||
"""
|
||||
service, err = _require_sync_service()
|
||||
if err:
|
||||
return err
|
||||
|
||||
try:
|
||||
if hasattr(service, 'is_running') and service.is_running():
|
||||
return jsonify({"status": "success", "status_code": SYNC_SUCCESS, "message": "文件监控已在运行"})
|
||||
|
||||
if hasattr(service, 'start'):
|
||||
success = service.start()
|
||||
if success:
|
||||
return jsonify({"status": "success", "status_code": SYNC_SUCCESS, "message": "文件监控已启动"})
|
||||
else:
|
||||
return error_response(
|
||||
error="SYNC_ERROR",
|
||||
error_code=SYNC_ERROR,
|
||||
message="启动文件监控失败",
|
||||
http_status=500
|
||||
)
|
||||
else:
|
||||
return jsonify({"status": "success", "message": "文件监控功能不可用"})
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error="SYNC_ERROR",
|
||||
error_code=SYNC_ERROR,
|
||||
message=str(e),
|
||||
http_status=500
|
||||
)
|
||||
|
||||
|
||||
@sync_bp.route('/sync/stop', methods=['POST'])
|
||||
@require_gateway_auth
|
||||
def stop_sync_monitor() -> Tuple[Any, int]:
|
||||
"""
|
||||
停止文件监控
|
||||
|
||||
停止实时文件监控服务。已同步的数据保持不变。
|
||||
|
||||
Returns:
|
||||
{"status": "success", "message": "文件监控已停止"}
|
||||
"""
|
||||
service, err = _require_sync_service()
|
||||
if err:
|
||||
return err
|
||||
|
||||
try:
|
||||
if hasattr(service, 'stop'):
|
||||
service.stop()
|
||||
return jsonify({"status": "success", "status_code": SYNC_SUCCESS, "message": "文件监控已停止"})
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error="SYNC_ERROR",
|
||||
error_code=SYNC_ERROR,
|
||||
message=str(e),
|
||||
http_status=500
|
||||
)
|
||||
Reference in New Issue
Block a user