camera.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. from datetime import datetime
  2. from fastapi import APIRouter, HTTPException, Query, Response
  3. from app.services import (
  4. CameraCaptureError,
  5. CameraUnavailableError,
  6. MqttCaptureBusyError,
  7. MqttCaptureError,
  8. get_camera_service,
  9. get_mqtt_capture_service,
  10. )
  11. router = APIRouter(
  12. prefix="/camera",
  13. tags=["camera"],
  14. )
  15. @router.api_route("/capture", methods=["GET"], summary="拍照并直接返回图片")
  16. def capture_image(
  17. download: bool = Query(
  18. default=False,
  19. description="是否以附件下载方式返回图片。默认 False,浏览器会直接预览。",
  20. ),
  21. ) -> Response:
  22. """
  23. 拍照接口。
  24. 调用这个接口时,服务会即时触发树莓派相机拍照,
  25. 然后把最新拍到的图片直接作为 HTTP 响应返回。
  26. """
  27. camera_service = get_camera_service()
  28. try:
  29. image_bytes = camera_service.capture_jpeg()
  30. except (CameraUnavailableError, CameraCaptureError) as exc:
  31. raise HTTPException(status_code=503, detail=str(exc)) from exc
  32. filename = f"capture_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
  33. disposition = "attachment" if download else "inline"
  34. return Response(
  35. content=image_bytes,
  36. media_type="image/jpeg",
  37. headers={
  38. "Content-Disposition": f'{disposition}; filename="{filename}"',
  39. "Cache-Control": "no-store",
  40. },
  41. )
  42. @router.api_route(
  43. "/capture-pair",
  44. methods=["GET", "POST"],
  45. summary="通过 MQTT 联动拍摄正反两张图片",
  46. )
  47. def capture_pair_via_mqtt() -> dict[str, object]:
  48. """
  49. 机械臂联动拍照接口。
  50. 调用流程:
  51. 1. 本接口收到请求后,临时连接 MQTT。
  52. 2. 发送 start 指令给机械臂。
  53. 3. 收到 `id=1` / `id=2` 的拍照指令后,分别覆盖保存到静态目录。
  54. 4. 第一张图保存后,调用识别接口获取卡牌信息。
  55. 5. 等待 `status=4` 作为流程结束信号。
  56. 6. 上传两张图到 MinIO,并返回 MinIO URL 和识别结果。
  57. """
  58. mqtt_capture_service = get_mqtt_capture_service()
  59. try:
  60. result = mqtt_capture_service.capture_pair()
  61. except MqttCaptureBusyError as exc:
  62. raise HTTPException(status_code=409, detail=str(exc)) from exc
  63. except MqttCaptureError as exc:
  64. raise HTTPException(status_code=503, detail=str(exc)) from exc
  65. return result