fix api so last24 hours has its own review summary

This commit is contained in:
Nicolas Mowen 2024-03-05 14:48:30 -07:00
parent 33e98b4043
commit a1dac63e51
4 changed files with 137 additions and 20 deletions

View File

@ -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",))

View File

@ -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 },
); );

View File

@ -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;

View File

@ -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) {