feat: 视觉记录系统 v1.0.0 - 摄像头定时拍照+智能分析+Web界面
This commit is contained in:
223
scheduler.py
Normal file
223
scheduler.py
Normal file
@@ -0,0 +1,223 @@
|
||||
"""
|
||||
定时任务调度模块
|
||||
"""
|
||||
import threading
|
||||
import time
|
||||
import datetime
|
||||
from camera import CameraCapture
|
||||
from analyzer import ImageAnalyzer
|
||||
from database import db
|
||||
from config import CAPTURE_INTERVAL
|
||||
|
||||
|
||||
class VisionScheduler:
|
||||
"""视觉记录调度器"""
|
||||
|
||||
def __init__(self):
|
||||
self.camera = CameraCapture()
|
||||
self.analyzer = ImageAnalyzer()
|
||||
self.running = False
|
||||
self.interval = CAPTURE_INTERVAL
|
||||
self.timer = None
|
||||
self.auto_analyze = True # 自动分析
|
||||
|
||||
# 统计
|
||||
self.capture_count = 0
|
||||
self.last_capture_time = None
|
||||
self.last_analyze_time = None
|
||||
self.errors = []
|
||||
|
||||
def start(self, interval=None, auto_analyze=None):
|
||||
"""启动定时拍照
|
||||
|
||||
Args:
|
||||
interval: 拍照间隔(秒)
|
||||
auto_analyze: 是否自动分析
|
||||
"""
|
||||
if self.running:
|
||||
return {'success': False, 'error': '已在运行中'}
|
||||
|
||||
if interval:
|
||||
self.interval = interval
|
||||
if auto_analyze is not None:
|
||||
self.auto_analyze = auto_analyze
|
||||
|
||||
self.running = True
|
||||
self._schedule_next()
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'interval': self.interval,
|
||||
'auto_analyze': self.auto_analyze
|
||||
}
|
||||
|
||||
def stop(self):
|
||||
"""停止定时拍照"""
|
||||
self.running = False
|
||||
if self.timer:
|
||||
self.timer.cancel()
|
||||
self.timer = None
|
||||
self.camera.close()
|
||||
return {'success': True}
|
||||
|
||||
def _schedule_next(self):
|
||||
"""安排下一次拍照"""
|
||||
if not self.running:
|
||||
return
|
||||
self.timer = threading.Timer(self.interval, self._capture_task)
|
||||
self.timer.start()
|
||||
|
||||
def _capture_task(self):
|
||||
"""拍照任务"""
|
||||
if not self.running:
|
||||
return
|
||||
|
||||
try:
|
||||
# 拍照
|
||||
result = self.camera.capture()
|
||||
|
||||
if result['success']:
|
||||
# 记录到数据库
|
||||
image_id = db.add_image(result['path'])
|
||||
self.capture_count += 1
|
||||
self.last_capture_time = datetime.datetime.now().isoformat()
|
||||
|
||||
# 自动分析
|
||||
if self.auto_analyze:
|
||||
self._analyze_task(image_id, result['path'])
|
||||
else:
|
||||
self.errors.append({
|
||||
'time': datetime.datetime.now().isoformat(),
|
||||
'error': result['error']
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
self.errors.append({
|
||||
'time': datetime.datetime.now().isoformat(),
|
||||
'error': str(e)
|
||||
})
|
||||
|
||||
# 安排下一次
|
||||
self._schedule_next()
|
||||
|
||||
def _analyze_task(self, image_id, image_path):
|
||||
"""分析任务"""
|
||||
try:
|
||||
result = self.analyzer.analyze(image_path)
|
||||
|
||||
if result['success']:
|
||||
# 记录事件
|
||||
for event in result['events']:
|
||||
db.add_event(
|
||||
image_id,
|
||||
event['event_type'],
|
||||
event['description'],
|
||||
event['confidence']
|
||||
)
|
||||
# 标记已分析
|
||||
db.mark_image_analyzed(image_id)
|
||||
self.last_analyze_time = datetime.datetime.now().isoformat()
|
||||
else:
|
||||
self.errors.append({
|
||||
'time': datetime.datetime.now().isoformat(),
|
||||
'error': f"分析失败: {result['error']}"
|
||||
})
|
||||
except Exception as e:
|
||||
self.errors.append({
|
||||
'time': datetime.datetime.now().isoformat(),
|
||||
'error': str(e)
|
||||
})
|
||||
|
||||
def capture_now(self):
|
||||
"""立即拍照"""
|
||||
result = self.camera.capture()
|
||||
|
||||
if result['success']:
|
||||
image_id = db.add_image(result['path'])
|
||||
self.capture_count += 1
|
||||
self.last_capture_time = datetime.datetime.now().isoformat()
|
||||
|
||||
# 如果自动分析开启,立即分析
|
||||
if self.auto_analyze:
|
||||
threading.Thread(
|
||||
target=self._analyze_task,
|
||||
args=(image_id, result['path'])
|
||||
).start()
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'image_id': image_id,
|
||||
'path': result['path'],
|
||||
'timestamp': result['timestamp']
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
def analyze_now(self, image_id):
|
||||
"""立即分析指定图片"""
|
||||
image = db.get_image_by_id(image_id)
|
||||
if not image:
|
||||
return {'success': False, 'error': '图片不存在'}
|
||||
|
||||
result = self.analyzer.analyze(image['path'])
|
||||
|
||||
if result['success']:
|
||||
for event in result['events']:
|
||||
db.add_event(
|
||||
image_id,
|
||||
event['event_type'],
|
||||
event['description'],
|
||||
event['confidence']
|
||||
)
|
||||
db.mark_image_analyzed(image_id)
|
||||
self.last_analyze_time = datetime.datetime.now().isoformat()
|
||||
|
||||
return result
|
||||
|
||||
def analyze_unanalyzed(self):
|
||||
"""分析所有未分析的图片"""
|
||||
images = db.get_unanalyzed_images(limit=10)
|
||||
results = []
|
||||
|
||||
for image in images:
|
||||
result = self.analyzer.analyze(image['path'])
|
||||
|
||||
if result['success']:
|
||||
for event in result['events']:
|
||||
db.add_event(
|
||||
image['id'],
|
||||
event['event_type'],
|
||||
event['description'],
|
||||
event['confidence']
|
||||
)
|
||||
db.mark_image_analyzed(image['id'])
|
||||
results.append({'image_id': image['id'], 'success': True})
|
||||
else:
|
||||
results.append({'image_id': image['id'], 'success': False, 'error': result['error']})
|
||||
|
||||
return results
|
||||
|
||||
def get_status(self):
|
||||
"""获取调度器状态"""
|
||||
return {
|
||||
'running': self.running,
|
||||
'interval': self.interval,
|
||||
'auto_analyze': self.auto_analyze,
|
||||
'capture_count': self.capture_count,
|
||||
'last_capture_time': self.last_capture_time,
|
||||
'last_analyze_time': self.last_analyze_time,
|
||||
'recent_errors': self.errors[-5:] if self.errors else []
|
||||
}
|
||||
|
||||
def set_interval(self, interval):
|
||||
"""设置拍照间隔"""
|
||||
self.interval = interval
|
||||
if self.running:
|
||||
# 重启定时器
|
||||
self.stop()
|
||||
self.start()
|
||||
return {'success': True, 'interval': interval}
|
||||
|
||||
|
||||
# 全局实例
|
||||
scheduler = VisionScheduler()
|
||||
Reference in New Issue
Block a user