mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-09 04:35:25 +03:00
fix api so last24 hours has its own review summary
This commit is contained in:
parent
33e98b4043
commit
a1dac63e51
@ -76,11 +76,112 @@ def review():
|
|||||||
def review_summary():
|
def review_summary():
|
||||||
tz_name = request.args.get("timezone", default="utc", type=str)
|
tz_name = request.args.get("timezone", default="utc", type=str)
|
||||||
hour_modifier, minute_modifier, seconds_offset = get_tz_modifiers(tz_name)
|
hour_modifier, minute_modifier, seconds_offset = get_tz_modifiers(tz_name)
|
||||||
|
day_ago = (datetime.now() - timedelta(hours=24)).timestamp()
|
||||||
month_ago = (datetime.now() - timedelta(days=30)).timestamp()
|
month_ago = (datetime.now() - timedelta(days=30)).timestamp()
|
||||||
|
|
||||||
cameras = request.args.get("cameras", "all")
|
cameras = request.args.get("cameras", "all")
|
||||||
labels = request.args.get("labels", "all")
|
labels = request.args.get("labels", "all")
|
||||||
|
|
||||||
|
clauses = [(ReviewSegment.start_time > day_ago)]
|
||||||
|
|
||||||
|
if cameras != "all":
|
||||||
|
camera_list = cameras.split(",")
|
||||||
|
clauses.append((ReviewSegment.camera << camera_list))
|
||||||
|
|
||||||
|
if labels != "all":
|
||||||
|
# use matching so segments with multiple labels
|
||||||
|
# still match on a search where any label matches
|
||||||
|
label_clauses = []
|
||||||
|
filtered_labels = labels.split(",")
|
||||||
|
|
||||||
|
for label in filtered_labels:
|
||||||
|
label_clauses.append(
|
||||||
|
(ReviewSegment.data["objects"].cast("text") % f'*"{label}"*')
|
||||||
|
)
|
||||||
|
|
||||||
|
label_clause = reduce(operator.or_, label_clauses)
|
||||||
|
clauses.append((label_clause))
|
||||||
|
|
||||||
|
last_24 = (
|
||||||
|
ReviewSegment.select(
|
||||||
|
fn.SUM(
|
||||||
|
Case(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(ReviewSegment.severity == "alert"),
|
||||||
|
ReviewSegment.has_been_reviewed,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
).alias("reviewed_alert"),
|
||||||
|
fn.SUM(
|
||||||
|
Case(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(ReviewSegment.severity == "detection"),
|
||||||
|
ReviewSegment.has_been_reviewed,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
).alias("reviewed_detection"),
|
||||||
|
fn.SUM(
|
||||||
|
Case(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(ReviewSegment.severity == "significant_motion"),
|
||||||
|
ReviewSegment.has_been_reviewed,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
).alias("reviewed_motion"),
|
||||||
|
fn.SUM(
|
||||||
|
Case(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(ReviewSegment.severity == "alert"),
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
).alias("total_alert"),
|
||||||
|
fn.SUM(
|
||||||
|
Case(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(ReviewSegment.severity == "detection"),
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
).alias("total_detection"),
|
||||||
|
fn.SUM(
|
||||||
|
Case(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(ReviewSegment.severity == "significant_motion"),
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
).alias("total_motion"),
|
||||||
|
)
|
||||||
|
.where(reduce(operator.and_, clauses))
|
||||||
|
.dicts()
|
||||||
|
.get()
|
||||||
|
)
|
||||||
|
|
||||||
clauses = [(ReviewSegment.start_time > month_ago)]
|
clauses = [(ReviewSegment.start_time > month_ago)]
|
||||||
|
|
||||||
if cameras != "all":
|
if cameras != "all":
|
||||||
@ -101,7 +202,7 @@ def review_summary():
|
|||||||
label_clause = reduce(operator.or_, label_clauses)
|
label_clause = reduce(operator.or_, label_clauses)
|
||||||
clauses.append((label_clause))
|
clauses.append((label_clause))
|
||||||
|
|
||||||
groups = (
|
last_month = (
|
||||||
ReviewSegment.select(
|
ReviewSegment.select(
|
||||||
fn.strftime(
|
fn.strftime(
|
||||||
"%Y-%m-%d",
|
"%Y-%m-%d",
|
||||||
@ -192,7 +293,15 @@ def review_summary():
|
|||||||
.order_by(ReviewSegment.start_time.desc())
|
.order_by(ReviewSegment.start_time.desc())
|
||||||
)
|
)
|
||||||
|
|
||||||
return jsonify([e for e in groups.dicts().iterator()])
|
data = {
|
||||||
|
"last24Hours": last_24,
|
||||||
|
}
|
||||||
|
|
||||||
|
for e in last_month.dicts().iterator():
|
||||||
|
data[e["day"]] = e
|
||||||
|
|
||||||
|
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
|
||||||
@ReviewBp.route("/reviews/viewed", methods=("POST",))
|
@ReviewBp.route("/reviews/viewed", methods=("POST",))
|
||||||
|
|||||||
@ -115,9 +115,7 @@ export default function Events() {
|
|||||||
|
|
||||||
// review summary
|
// review summary
|
||||||
|
|
||||||
const { data: reviewSummary, mutate: updateSummary } = useSWR<
|
const { data: reviewSummary, mutate: updateSummary } = useSWR<ReviewSummary>([
|
||||||
ReviewSummary[]
|
|
||||||
>([
|
|
||||||
"review/summary",
|
"review/summary",
|
||||||
{
|
{
|
||||||
timezone: timezone,
|
timezone: timezone,
|
||||||
@ -197,23 +195,30 @@ export default function Events() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
updateSummary(
|
updateSummary(
|
||||||
(data: ReviewSummary[] | undefined) => {
|
(data: ReviewSummary | undefined) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const day = new Date(review.start_time * 1000);
|
const day = new Date(review.start_time * 1000);
|
||||||
const key = `${day.getFullYear()}-${("0" + (day.getMonth() + 1)).slice(-2)}-${("0" + day.getDate()).slice(-2)}`;
|
const today = new Date();
|
||||||
const index = data.findIndex((summary) => summary.day == key);
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
if (index == -1) {
|
let key;
|
||||||
|
if (day.getTime() > today.getTime()) {
|
||||||
|
key = "last24Hours";
|
||||||
|
} else {
|
||||||
|
key = `${day.getFullYear()}-${("0" + (day.getMonth() + 1)).slice(-2)}-${("0" + day.getDate()).slice(-2)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.keys(data).includes(key)) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const item = data[index];
|
const item = data[key];
|
||||||
return [
|
return {
|
||||||
...data.slice(0, index),
|
...data,
|
||||||
{
|
[key]: {
|
||||||
...item,
|
...item,
|
||||||
reviewed_alert:
|
reviewed_alert:
|
||||||
review.severity == "alert"
|
review.severity == "alert"
|
||||||
@ -228,8 +233,7 @@ export default function Events() {
|
|||||||
? item.reviewed_motion + 1
|
? item.reviewed_motion + 1
|
||||||
: item.reviewed_motion,
|
: item.reviewed_motion,
|
||||||
},
|
},
|
||||||
...data.slice(index + 1),
|
};
|
||||||
];
|
|
||||||
},
|
},
|
||||||
{ revalidate: false, populateCache: true },
|
{ revalidate: false, populateCache: true },
|
||||||
);
|
);
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export type ReviewFilter = {
|
|||||||
showReviewed?: 0 | 1;
|
showReviewed?: 0 | 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReviewSummary = {
|
type ReviewSummaryDay = {
|
||||||
day: string;
|
day: string;
|
||||||
reviewed_alert: number;
|
reviewed_alert: number;
|
||||||
reviewed_detection: number;
|
reviewed_detection: number;
|
||||||
@ -38,6 +38,10 @@ export type ReviewSummary = {
|
|||||||
total_motion: number;
|
total_motion: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ReviewSummary = {
|
||||||
|
[day: string]: ReviewSummaryDay;
|
||||||
|
};
|
||||||
|
|
||||||
export type MotionData = {
|
export type MotionData = {
|
||||||
start_time: number;
|
start_time: number;
|
||||||
motion: number;
|
motion: number;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
|
|
||||||
type EventViewProps = {
|
type EventViewProps = {
|
||||||
reviewPages?: ReviewSegment[][];
|
reviewPages?: ReviewSegment[][];
|
||||||
reviewSummary?: ReviewSummary[];
|
reviewSummary?: ReviewSummary;
|
||||||
relevantPreviews?: Preview[];
|
relevantPreviews?: Preview[];
|
||||||
timeRange: { before: number; after: number };
|
timeRange: { before: number; after: number };
|
||||||
reachedEnd: boolean;
|
reachedEnd: boolean;
|
||||||
@ -75,17 +75,17 @@ export default function EventView({
|
|||||||
// review counts
|
// review counts
|
||||||
|
|
||||||
const reviewCounts = useMemo(() => {
|
const reviewCounts = useMemo(() => {
|
||||||
if (!reviewSummary || reviewSummary.length == 0) {
|
if (!reviewSummary) {
|
||||||
return { alert: 0, detection: 0, significant_motion: 0 };
|
return { alert: 0, detection: 0, significant_motion: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
let summary;
|
let summary;
|
||||||
if (filter?.before == undefined) {
|
if (filter?.before == undefined) {
|
||||||
summary = reviewSummary[0];
|
summary = reviewSummary["last24Hours"];
|
||||||
} else {
|
} else {
|
||||||
const day = new Date(filter.before * 1000);
|
const day = new Date(filter.before * 1000);
|
||||||
const key = `${day.getFullYear()}-${("0" + (day.getMonth() + 1)).slice(-2)}-${("0" + day.getDate()).slice(-2)}`;
|
const key = `${day.getFullYear()}-${("0" + (day.getMonth() + 1)).slice(-2)}-${("0" + day.getDate()).slice(-2)}`;
|
||||||
summary = reviewSummary.find((check) => check.day == key);
|
summary = reviewSummary[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!summary) {
|
if (!summary) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user