added data saving feature

This commit is contained in:
Ayzen
2026-06-23 12:19:31 +03:00
parent 716fd0b07a
commit 8db14b9482
20 changed files with 1192 additions and 63 deletions
+36 -12
View File
@@ -14,7 +14,7 @@ import logging
from fastapi import APIRouter, Body, HTTPException, Request, WebSocket, WebSocketDisconnect
from python_app.webui.controller import WebController
from python_app.webui.controller import WebActionError, WebController
from python_app.webui.streaming import RingBroadcaster
logger = logging.getLogger(__name__)
@@ -26,6 +26,21 @@ def _controller(request: Request) -> WebController:
return request.app.state.controller
async def _run_action(func, *args) -> None:
"""Run a (blocking) controller control call off the event loop, mapping failures to 400.
The control methods run the desktop action synchronously and raise ``ValueError``
(rejected input) or ``WebActionError`` (the action itself failed) — both become a
400 the browser shows, instead of the old silent "ok". Running in a worker thread
keeps the async event loop free while the GUI thread does the work.
"""
try:
await asyncio.to_thread(func, *args)
except (ValueError, WebActionError) as exc:
logger.warning("Web UI action failed: %s", exc)
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/api/status")
async def get_status(request: Request) -> dict:
return _controller(request).status()
@@ -35,7 +50,7 @@ async def get_status(request: Request) -> dict:
async def post_start(request: Request) -> dict:
logger.info("Web UI request: start")
controller = _controller(request)
controller.start()
await _run_action(controller.start)
return controller.status()
@@ -43,7 +58,7 @@ async def post_start(request: Request) -> dict:
async def post_single_capture(request: Request) -> dict:
logger.info("Web UI request: single capture")
controller = _controller(request)
controller.single_capture()
await _run_action(controller.single_capture)
return controller.status()
@@ -51,7 +66,20 @@ async def post_single_capture(request: Request) -> dict:
async def post_stop(request: Request) -> dict:
logger.info("Web UI request: stop")
controller = _controller(request)
controller.stop()
await _run_action(controller.stop)
return controller.status()
@router.post("/api/start_recording")
async def post_start_recording(
request: Request,
path: str = Body("", embed=True),
name: str = Body("", embed=True),
count: int = Body(..., embed=True),
) -> dict:
logger.info("Web UI request: start with disk recording (count=%s)", count)
controller = _controller(request)
await _run_action(controller.start_recording, path, name, count)
return controller.status()
@@ -59,7 +87,7 @@ async def post_stop(request: Request) -> dict:
async def post_tmp_reference(request: Request) -> dict:
logger.info("Web UI request: capture temporary reference")
controller = _controller(request)
controller.capture_tmp_reference()
await _run_action(controller.capture_tmp_reference)
return controller.status()
@@ -67,7 +95,7 @@ async def post_tmp_reference(request: Request) -> dict:
async def post_remove_last(request: Request) -> dict:
logger.info("Web UI request: remove last measurement")
controller = _controller(request)
controller.remove_last_measurement()
await _run_action(controller.remove_last_measurement)
return controller.status()
@@ -80,11 +108,7 @@ async def get_configs(request: Request) -> dict:
async def post_load_config(request: Request, name: str = Body(..., embed=True)) -> dict:
logger.info("Web UI request: load config %r", name)
controller = _controller(request)
try:
controller.load_config(name)
except ValueError as exc:
logger.warning("Web UI rejected config load: %s", exc)
raise HTTPException(status_code=400, detail=str(exc)) from exc
await _run_action(controller.load_config, name)
return controller.status()
@@ -96,7 +120,7 @@ async def post_save_dataset(
) -> dict:
logger.info("Web UI request: save dataset")
controller = _controller(request)
controller.save_dataset(path, name)
await _run_action(controller.save_dataset, path, name)
return controller.status()