diff --git a/rag-python/app.py b/rag-python/app.py index 2e952195..7b4b26ad 100644 --- a/rag-python/app.py +++ b/rag-python/app.py @@ -5,15 +5,46 @@ RAG 知识库服务 - Flask API """ import os import sys +import logging +from logging.handlers import RotatingFileHandler from flask import Flask, request, jsonify from flask_cors import CORS from config import HOST, PORT, KNOWLEDGE_DIR, BASE_DIR from knowledge_service import knowledge_service from file_watcher import FileWatcher +from event_store import get_events, record_event app = Flask(__name__) CORS(app) # 允许跨域请求 + +def _setup_logging(): + log_dir = os.path.join(BASE_DIR, "logs") + os.makedirs(log_dir, exist_ok=True) + log_path = os.path.join(log_dir, "rag-python.log") + + root = logging.getLogger() + if root.handlers: + return + + root.setLevel(logging.INFO) + file_handler = RotatingFileHandler( + log_path, + maxBytes=10 * 1024 * 1024, + backupCount=10, + encoding="utf-8", + ) + formatter = logging.Formatter( + fmt="%(asctime)s [%(levelname)s] %(name)s - %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + file_handler.setFormatter(formatter) + root.addHandler(file_handler) + + +_setup_logging() +log = logging.getLogger("rag.app") + # 文件监控器 file_watcher = None @@ -27,6 +58,18 @@ def health_check(): 'base_dir': BASE_DIR }) + +@app.route('/api/events', methods=['GET']) +def list_events(): + """返回最近的索引事件(用于隐藏窗口时查看索引更新情况)""" + try: + limit = request.args.get('limit', default=None, type=int) + events = get_events(limit=limit, newest_first=True) + return jsonify({'success': True, 'data': events}) + except Exception as e: + log.exception("Failed to list events") + return jsonify({'success': False, 'error': str(e)}), 500 + @app.route('/api/documents', methods=['GET']) def list_documents(): """列出所有文档""" @@ -210,25 +253,31 @@ def rag_analyze(): def init_service(): """初始化服务""" - print("=" * 50) - print("RAG 知识库服务启动中...") - print("=" * 50) + log.info("%s", "=" * 50) + log.info("RAG 知识库服务启动中...") + log.info("%s", "=" * 50) + record_event("service_start", knowledge_dir=KNOWLEDGE_DIR, base_dir=BASE_DIR) # 初始化知识库服务 knowledge_service.init() + record_event("index_loaded") # 扫描并索引新文件 - knowledge_service.scan_and_index_folder() + scan_result = knowledge_service.scan_and_index_folder() + record_event("startup_scan", result=scan_result) # 启动文件监控 global file_watcher file_watcher = FileWatcher(knowledge_service) file_watcher.start() + + record_event("watcher_started", path=KNOWLEDGE_DIR) - print("=" * 50) - print(f"服务已启动: http://{HOST}:{PORT}") - print(f"知识库文件夹: {KNOWLEDGE_DIR}") - print("=" * 50) + log.info("%s", "=" * 50) + log.info("服务已启动: http://%s:%s", HOST, PORT) + log.info("知识库文件夹: %s", KNOWLEDGE_DIR) + log.info("%s", "=" * 50) + record_event("service_ready", host=HOST, port=PORT) if __name__ == '__main__': init_service() diff --git a/rag-python/event_store.py b/rag-python/event_store.py new file mode 100644 index 00000000..c2337989 --- /dev/null +++ b/rag-python/event_store.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from collections import deque +from datetime import datetime, timezone +from threading import Lock +from typing import Any, Dict, List, Optional + +_events: "deque[Dict[str, Any]]" = deque(maxlen=2000) +_lock = Lock() + + +def record_event(event_type: str, **payload: Any) -> None: + event = { + "ts": datetime.now(timezone.utc).isoformat(), + "type": event_type, + "payload": payload, + } + with _lock: + _events.append(event) + + +def get_events(limit: Optional[int] = None, newest_first: bool = True) -> List[Dict[str, Any]]: + with _lock: + items = list(_events) + if newest_first: + items.reverse() + if limit is not None: + return items[: max(0, limit)] + return items diff --git a/xinli-ui/src/views/psychology/permission/index.vue b/xinli-ui/src/views/psychology/permission/index.vue index 66c739ae..b92e8f96 100644 --- a/xinli-ui/src/views/psychology/permission/index.vue +++ b/xinli-ui/src/views/psychology/permission/index.vue @@ -62,9 +62,6 @@ 新增 - - 删除 -