Initial commit: 国土空间规划课程智能体 v1.0
单容器 Docker 架构的国土空间规划课程智能问答系统,集成 FastAPI 后端与 Next.js 前端。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
"""
|
||||
文件监控服务
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from typing import Optional, Callable
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemEventHandler, FileCreatedEvent, FileModifiedEvent, FileDeletedEvent
|
||||
|
||||
from ..core.config import get_settings
|
||||
from ..core.database import get_db
|
||||
from .knowledge_base_service import KnowledgeBaseService
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
class KnowledgeBaseHandler(FileSystemEventHandler):
|
||||
"""知识库文件监控处理器"""
|
||||
|
||||
def __init__(self, knowledge_base_service: KnowledgeBaseService):
|
||||
self.kb_service = knowledge_base_service
|
||||
self.knowledge_base_dir = Path(settings.knowledge_base_dir)
|
||||
self.supported_extensions = settings.allowed_extensions
|
||||
|
||||
def on_created(self, event):
|
||||
"""处理文件创建事件"""
|
||||
if not event.is_directory and self._is_supported_file(event.src_path):
|
||||
print(f"检测到新文件: {event.src_path}")
|
||||
self._process_file_async(event.src_path, "created")
|
||||
|
||||
def on_modified(self, event):
|
||||
"""处理文件修改事件"""
|
||||
if not event.is_directory and self._is_supported_file(event.src_path):
|
||||
print(f"检测到文件修改: {event.src_path}")
|
||||
self._process_file_async(event.src_path, "modified")
|
||||
|
||||
def on_deleted(self, event):
|
||||
"""处理文件删除事件"""
|
||||
if not event.is_directory and self._is_supported_file(event.src_path):
|
||||
print(f"检测到文件删除: {event.src_path}")
|
||||
self._handle_file_deletion(event.src_path)
|
||||
|
||||
def _is_supported_file(self, file_path: str) -> bool:
|
||||
"""检查是否为支持的文件类型"""
|
||||
return Path(file_path).suffix.lower() in self.supported_extensions
|
||||
|
||||
def _process_file_async(self, file_path: str, event_type: str):
|
||||
"""异步处理文件"""
|
||||
def process():
|
||||
try:
|
||||
# 等待文件写入完成
|
||||
time.sleep(1)
|
||||
|
||||
result = self.kb_service.process_file(file_path)
|
||||
print(f"文件处理结果 ({event_type}): {result}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理文件失败: {file_path}, 错误: {str(e)}")
|
||||
|
||||
# 在后台线程中处理
|
||||
thread = threading.Thread(target=process)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
def _handle_file_deletion(self, file_path: str):
|
||||
"""处理文件删除"""
|
||||
try:
|
||||
# 查找并删除对应的数据库记录
|
||||
from ..models.document import Document
|
||||
from sqlalchemy import and_
|
||||
|
||||
document = self.kb_service.db.query(Document).filter(
|
||||
and_(
|
||||
Document.file_path == file_path,
|
||||
Document.source_type == "knowledge_base"
|
||||
)
|
||||
).first()
|
||||
|
||||
if document:
|
||||
result = self.kb_service.delete_document(document.id)
|
||||
print(f"文件删除处理结果: {result}")
|
||||
else:
|
||||
print(f"未找到对应的数据库记录: {file_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理文件删除失败: {file_path}, 错误: {str(e)}")
|
||||
|
||||
|
||||
class FileWatcherService:
|
||||
"""文件监控服务"""
|
||||
|
||||
def __init__(self):
|
||||
self.observer: Optional[Observer] = None
|
||||
self.knowledge_base_dir = Path(settings.knowledge_base_dir)
|
||||
self.is_running = False
|
||||
|
||||
def start(self):
|
||||
"""启动文件监控"""
|
||||
if self.is_running:
|
||||
print("文件监控服务已在运行")
|
||||
return
|
||||
|
||||
if not settings.enable_file_watcher:
|
||||
print("文件监控服务已禁用")
|
||||
return
|
||||
|
||||
if not self.knowledge_base_dir.exists():
|
||||
print(f"知识库目录不存在: {self.knowledge_base_dir}")
|
||||
return
|
||||
|
||||
try:
|
||||
# 创建数据库会话
|
||||
db = next(get_db())
|
||||
kb_service = KnowledgeBaseService(db)
|
||||
|
||||
# 创建事件处理器
|
||||
event_handler = KnowledgeBaseHandler(kb_service)
|
||||
|
||||
# 创建观察者
|
||||
self.observer = Observer()
|
||||
self.observer.schedule(
|
||||
event_handler,
|
||||
str(self.knowledge_base_dir),
|
||||
recursive=True # 递归监控子目录
|
||||
)
|
||||
|
||||
# 启动观察者
|
||||
self.observer.start()
|
||||
self.is_running = True
|
||||
|
||||
print(f"文件监控服务已启动,监控目录: {self.knowledge_base_dir}")
|
||||
|
||||
# 执行初始扫描
|
||||
print("执行初始知识库扫描...")
|
||||
scan_result = kb_service.scan_directory()
|
||||
print(f"初始扫描结果: {scan_result}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"启动文件监控服务失败: {str(e)}")
|
||||
self.is_running = False
|
||||
|
||||
def stop(self):
|
||||
"""停止文件监控"""
|
||||
if self.observer and self.is_running:
|
||||
self.observer.stop()
|
||||
self.observer.join()
|
||||
self.is_running = False
|
||||
print("文件监控服务已停止")
|
||||
|
||||
def is_active(self) -> bool:
|
||||
"""检查监控服务是否活跃"""
|
||||
return self.is_running and self.observer and self.observer.is_alive()
|
||||
|
||||
def get_status(self) -> dict:
|
||||
"""获取监控服务状态"""
|
||||
return {
|
||||
"is_running": self.is_running,
|
||||
"is_active": self.is_active(),
|
||||
"knowledge_base_dir": str(self.knowledge_base_dir),
|
||||
"directory_exists": self.knowledge_base_dir.exists(),
|
||||
"enable_file_watcher": settings.enable_file_watcher
|
||||
}
|
||||
|
||||
|
||||
# 全局文件监控服务实例
|
||||
file_watcher_service: Optional[FileWatcherService] = None
|
||||
|
||||
|
||||
def get_file_watcher_service() -> FileWatcherService:
|
||||
"""获取文件监控服务实例"""
|
||||
global file_watcher_service
|
||||
if file_watcher_service is None:
|
||||
file_watcher_service = FileWatcherService()
|
||||
return file_watcher_service
|
||||
|
||||
|
||||
def start_file_watcher():
|
||||
"""启动文件监控服务"""
|
||||
watcher = get_file_watcher_service()
|
||||
watcher.start()
|
||||
|
||||
|
||||
def stop_file_watcher():
|
||||
"""停止文件监控服务"""
|
||||
watcher = get_file_watcher_service()
|
||||
watcher.stop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user