feat: v1.1.0 - 图片按日期分文件夹保存、设置面板、序号显示模式、自动刷新
This commit is contained in:
108
web/app.py
108
web/app.py
@@ -3,12 +3,11 @@ Web 后端 - FastAPI
|
||||
"""
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse, HTMLResponse
|
||||
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
|
||||
from pathlib import Path
|
||||
import uvicorn
|
||||
import json
|
||||
|
||||
from config import WEB_PORT, WEB_HOST, IMAGES_DIR
|
||||
from config import WEB_PORT, WEB_HOST, config_mgr, DATA_DIR
|
||||
from database import db
|
||||
from scheduler import scheduler
|
||||
from camera import list_available_cameras, CameraCapture
|
||||
@@ -20,7 +19,17 @@ app = FastAPI(title="视觉记录系统")
|
||||
# 静态文件目录
|
||||
STATIC_DIR = Path(__file__).parent / "static"
|
||||
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
||||
app.mount("/images", StaticFiles(directory=str(IMAGES_DIR)), name="images")
|
||||
|
||||
# 图片目录 - 使用配置中的目录
|
||||
@app.get("/images/{filename}")
|
||||
async def get_image(filename: str):
|
||||
"""获取图片(需要在实际目录中查找)"""
|
||||
# 从数据库查找图片路径
|
||||
images = db.get_images(limit=1000)
|
||||
for img in images:
|
||||
if img['path'].endswith(filename):
|
||||
return FileResponse(img['path'])
|
||||
raise HTTPException(status_code=404, detail="图片不存在")
|
||||
|
||||
|
||||
# ============== 页面路由 ==============
|
||||
@@ -34,17 +43,55 @@ async def index():
|
||||
return HTMLResponse("<h1>请创建 index.html</h1>")
|
||||
|
||||
|
||||
# ============== API 路由 ==============
|
||||
# ============== 配置 API ==============
|
||||
|
||||
@app.get("/api/config")
|
||||
async def get_config():
|
||||
"""获取所有配置"""
|
||||
return config_mgr.get_all()
|
||||
|
||||
|
||||
@app.post("/api/config")
|
||||
async def update_config(data: dict):
|
||||
"""更新配置"""
|
||||
config_mgr.update(data)
|
||||
return {"success": True, "config": config_mgr.get_all()}
|
||||
|
||||
|
||||
@app.get("/api/config/images-dir")
|
||||
async def get_images_dir():
|
||||
"""获取图片保存目录"""
|
||||
return {
|
||||
"images_dir": config_mgr.get('images_dir'),
|
||||
"today_folder": str(config_mgr.get_images_dir())
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/config/images-dir")
|
||||
async def set_images_dir(path: str):
|
||||
"""设置图片保存目录"""
|
||||
from pathlib import Path
|
||||
try:
|
||||
Path(path).mkdir(parents=True, exist_ok=True)
|
||||
config_mgr.set('images_dir', path)
|
||||
return {"success": True, "images_dir": path}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
# ============== 状态 API ==============
|
||||
|
||||
@app.get("/api/status")
|
||||
async def get_status():
|
||||
"""获取系统状态"""
|
||||
stats = db.get_stats()
|
||||
scheduler_status = scheduler.get_status()
|
||||
config = config_mgr.get_all()
|
||||
|
||||
return {
|
||||
"scheduler": scheduler_status,
|
||||
"stats": stats
|
||||
"stats": stats,
|
||||
"config": config
|
||||
}
|
||||
|
||||
|
||||
@@ -54,16 +101,19 @@ async def get_cameras():
|
||||
cameras = list_available_cameras()
|
||||
details = []
|
||||
for cam_index in cameras:
|
||||
cam = CameraCapture(cam_index)
|
||||
cam = CameraCapture()
|
||||
cam.camera_index = cam_index
|
||||
details.append(cam.get_camera_info())
|
||||
cam.close()
|
||||
return {"cameras": details}
|
||||
|
||||
|
||||
# ============== 调度控制 API ==============
|
||||
|
||||
@app.post("/api/scheduler/start")
|
||||
async def start_scheduler(interval: int = None, auto_analyze: bool = None):
|
||||
async def start_scheduler():
|
||||
"""启动定时拍照"""
|
||||
result = scheduler.start(interval=interval, auto_analyze=auto_analyze)
|
||||
result = scheduler.start()
|
||||
if not result['success']:
|
||||
raise HTTPException(status_code=400, detail=result['error'])
|
||||
return result
|
||||
@@ -78,6 +128,8 @@ async def stop_scheduler():
|
||||
@app.post("/api/scheduler/interval")
|
||||
async def set_interval(interval: int):
|
||||
"""设置拍照间隔"""
|
||||
if interval < 10:
|
||||
raise HTTPException(status_code=400, detail="间隔不能小于10秒")
|
||||
return scheduler.set_interval(interval)
|
||||
|
||||
|
||||
@@ -90,6 +142,8 @@ async def capture_now():
|
||||
return result
|
||||
|
||||
|
||||
# ============== 分析 API ==============
|
||||
|
||||
@app.post("/api/analyze/{image_id}")
|
||||
async def analyze_image(image_id: int):
|
||||
"""分析指定图片"""
|
||||
@@ -106,10 +160,29 @@ async def analyze_unanalyzed():
|
||||
return {"results": results}
|
||||
|
||||
|
||||
# ============== 图片 API ==============
|
||||
|
||||
@app.get("/api/images")
|
||||
async def get_images(limit: int = 50, offset: int = 0, analyzed_only: bool = False):
|
||||
async def get_images(
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
analyzed_only: bool = False,
|
||||
date_folder: str = None
|
||||
):
|
||||
"""获取图片列表"""
|
||||
images = db.get_images(limit=limit, offset=offset, analyzed_only=analyzed_only)
|
||||
# 使用配置中的显示数量
|
||||
config_limit = config_mgr.get('display_limit', 20)
|
||||
if limit > config_limit:
|
||||
limit = config_limit
|
||||
|
||||
images = db.get_images(limit=limit, offset=offset, analyzed_only=analyzed_only, date_folder=date_folder)
|
||||
|
||||
# 为每张图片添加事件摘要
|
||||
for img in images:
|
||||
events = db.get_events_by_image(img['id'])
|
||||
img['events_summary'] = ', '.join([e['event_type'] for e in events]) if events else '无'
|
||||
img['events_count'] = len(events)
|
||||
|
||||
return {"images": images, "total": len(images)}
|
||||
|
||||
|
||||
@@ -134,9 +207,22 @@ async def delete_image(image_id: int):
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@app.get("/api/date-folders")
|
||||
async def get_date_folders():
|
||||
"""获取日期文件夹列表"""
|
||||
stats = db.get_stats()
|
||||
return {"folders": stats['date_folders']}
|
||||
|
||||
|
||||
# ============== 事件 API ==============
|
||||
|
||||
@app.get("/api/events")
|
||||
async def get_events(limit: int = 50, offset: int = 0, event_type: str = None):
|
||||
"""获取事件列表"""
|
||||
config_limit = config_mgr.get('display_limit', 20)
|
||||
if limit > config_limit:
|
||||
limit = config_limit
|
||||
|
||||
events = db.get_events(limit=limit, offset=offset, event_type=event_type)
|
||||
return {"events": events, "total": len(events)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user