forked from Github/frigate
Ability to manually create events through the API (#3184)
* Move to events package * Improve handling of external events * Handle external events in the event queue * Pass in event processor * Check event json * Fix json parsing and change defaults * Fix snapshot saving * Hide % score when not available * Correct docs and add json example * Save event png db * Adjust image * Formatting * Add catch for failure ending event * Add init to modules * Fix naming * Formatting * Fix http creation * fix test * Change to PUT and include response in docs * Add ability to set bounding box locations in snapshot * Support multiple box annotations * Cleanup docs example response Co-authored-by: Blake Blackshear <blake@frigate.video> * Cleanup docs wording Co-authored-by: Blake Blackshear <blake@frigate.video> * Store full frame for thumbnail * Formatting * Set thumbnail height to 175 * Formatting --------- Co-authored-by: Blake Blackshear <blake@frigate.video>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import base64
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import copy
|
||||
import glob
|
||||
import logging
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import subprocess as sp
|
||||
@@ -34,6 +34,7 @@ from playhouse.shortcuts import model_to_dict
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.const import CLIPS_DIR, MAX_SEGMENT_DURATION, RECORD_DIR
|
||||
from frigate.models import Event, Recordings, Timeline
|
||||
from frigate.events.external import ExternalEventProcessor
|
||||
from frigate.object_processing import TrackedObject
|
||||
from frigate.plus import PlusApi
|
||||
from frigate.ptz import OnvifController
|
||||
@@ -60,6 +61,7 @@ def create_app(
|
||||
detected_frames_processor,
|
||||
storage_maintainer: StorageMaintainer,
|
||||
onvif: OnvifController,
|
||||
external_processor: ExternalEventProcessor,
|
||||
plus_api: PlusApi,
|
||||
):
|
||||
app = Flask(__name__)
|
||||
@@ -79,6 +81,7 @@ def create_app(
|
||||
app.detected_frames_processor = detected_frames_processor
|
||||
app.storage_maintainer = storage_maintainer
|
||||
app.onvif = onvif
|
||||
app.external_processor = external_processor
|
||||
app.plus_api = plus_api
|
||||
app.camera_error_image = None
|
||||
app.hwaccel_errors = []
|
||||
@@ -195,7 +198,7 @@ def send_to_plus(id):
|
||||
return make_response(jsonify({"success": False, "message": message}), 404)
|
||||
|
||||
# events from before the conversion to relative dimensions cant include annotations
|
||||
if any(d > 1 for d in event.data["box"]):
|
||||
if any(d > 1 for d in event.box):
|
||||
include_annotation = None
|
||||
|
||||
if event.end_time is None:
|
||||
@@ -251,8 +254,8 @@ def send_to_plus(id):
|
||||
event.save()
|
||||
|
||||
if not include_annotation is None:
|
||||
region = event.data["region"]
|
||||
box = event.data["box"]
|
||||
region = event.region
|
||||
box = event.box
|
||||
|
||||
try:
|
||||
current_app.plus_api.add_annotation(
|
||||
@@ -293,7 +296,7 @@ def false_positive(id):
|
||||
return make_response(jsonify({"success": False, "message": message}), 404)
|
||||
|
||||
# events from before the conversion to relative dimensions cant include annotations
|
||||
if any(d > 1 for d in event.data["box"]):
|
||||
if any(d > 1 for d in event.box):
|
||||
message = f"Events prior to 0.13 cannot be submitted as false positives"
|
||||
logger.error(message)
|
||||
return make_response(jsonify({"success": False, "message": message}), 400)
|
||||
@@ -310,15 +313,11 @@ def false_positive(id):
|
||||
# need to refetch the event now that it has a plus_id
|
||||
event = Event.get(Event.id == id)
|
||||
|
||||
region = event.data["region"]
|
||||
box = event.data["box"]
|
||||
region = event.region
|
||||
box = event.box
|
||||
|
||||
# provide top score if score is unavailable
|
||||
score = (
|
||||
(event.data["top_score"] if event.data["top_score"] else event.top_score)
|
||||
if event.data["score"] is None
|
||||
else event.data["score"]
|
||||
)
|
||||
score = event.top_score if event.score is None else event.score
|
||||
|
||||
try:
|
||||
current_app.plus_api.add_false_positive(
|
||||
@@ -759,7 +758,6 @@ def events():
|
||||
Event.top_score,
|
||||
Event.false_positive,
|
||||
Event.box,
|
||||
Event.data,
|
||||
]
|
||||
|
||||
if camera != "all":
|
||||
@@ -848,6 +846,58 @@ def events():
|
||||
return jsonify([model_to_dict(e, exclude=excluded_fields) for e in events])
|
||||
|
||||
|
||||
@bp.route("/events/<camera_name>/<label>/create", methods=["POST"])
|
||||
def create_event(camera_name, label):
|
||||
if not camera_name or not current_app.frigate_config.cameras.get(camera_name):
|
||||
return jsonify(
|
||||
{"success": False, "message": f"{camera_name} is not a valid camera."}, 404
|
||||
)
|
||||
|
||||
if not label:
|
||||
return jsonify({"success": False, "message": f"{label} must be set."}, 404)
|
||||
|
||||
json: dict[str, any] = request.get_json(silent=True) or {}
|
||||
|
||||
try:
|
||||
frame = current_app.detected_frames_processor.get_current_frame(camera_name)
|
||||
|
||||
event_id = current_app.external_processor.create_manual_event(
|
||||
camera_name,
|
||||
label,
|
||||
json.get("sub_label", None),
|
||||
json.get("duration", 30),
|
||||
json.get("include_recording", True),
|
||||
json.get("draw", {}),
|
||||
frame,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"The error is {e}")
|
||||
return jsonify(
|
||||
{"success": False, "message": f"An unknown error occurred: {e}"}, 404
|
||||
)
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"success": True,
|
||||
"message": "Successfully created event.",
|
||||
"event_id": event_id,
|
||||
},
|
||||
200,
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/events/<event_id>/end", methods=["PUT"])
|
||||
def end_event(event_id):
|
||||
try:
|
||||
current_app.external_processor.finish_manual_event(event_id)
|
||||
except:
|
||||
return jsonify(
|
||||
{"success": False, "message": f"{event_id} must be set and valid."}, 404
|
||||
)
|
||||
|
||||
return jsonify({"success": True, "message": f"Event successfully ended."}, 200)
|
||||
|
||||
|
||||
@bp.route("/config")
|
||||
def config():
|
||||
config = current_app.frigate_config.dict()
|
||||
@@ -866,11 +916,6 @@ def config():
|
||||
|
||||
config["plus"] = {"enabled": current_app.plus_api.is_active()}
|
||||
|
||||
for detector, detector_config in config["detectors"].items():
|
||||
detector_config["model"][
|
||||
"labelmap"
|
||||
] = current_app.frigate_config.model.merged_labelmap
|
||||
|
||||
return jsonify(config)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user