Skip to content

Commit

Permalink
Merge branch 'blakeblackshear:dev' into testing
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjx authored Sep 26, 2024
2 parents d435afc + a6ccb37 commit 3d1d775
Show file tree
Hide file tree
Showing 26 changed files with 678 additions and 257 deletions.
2 changes: 1 addition & 1 deletion docker/hailo8l/user_installation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Update package list and install dependencies
sudo apt-get update
sudo apt-get install -y build-essential cmake git wget linux-modules-extra-$(uname -r)
sudo apt-get install -y build-essential cmake git wget

arch=$(uname -m)

Expand Down
2 changes: 1 addition & 1 deletion docker/main/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
ENTRYPOINT ["/init"]
CMD []

HEALTHCHECK --start-period=120s --start-interval=5s --interval=15s --timeout=5s --retries=3 \
HEALTHCHECK --start-period=300s --start-interval=5s --interval=15s --timeout=5s --retries=3 \
CMD curl --fail --silent --show-error http://127.0.0.1:5000/api/version || exit 1

# Frigate deps with Node.js and NPM for devcontainer
Expand Down
7 changes: 6 additions & 1 deletion docs/docs/configuration/genai.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ genai:
car: "Label the primary vehicle in these images with just the name of the company if it is a delivery vehicle, or the color make and model."
```

Prompts can also be overriden at the camera level to provide a more detailed prompt to the model about your specific camera, if you desire.
Prompts can also be overriden at the camera level to provide a more detailed prompt to the model about your specific camera, if you desire. By default, descriptions will be generated for all tracked objects and all zones. But you can also optionally specify `objects` and `required_zones` to only generate descriptions for certain tracked objects or zones.

```yaml
cameras:
Expand All @@ -138,6 +138,11 @@ cameras:
object_prompts:
person: "Describe the main person in these images (gender, age, clothing, activity, etc). Do not include where the activity is occurring (sidewalk, concrete, driveway, etc). If delivering a package, include the company the package is from."
cat: "Describe the cat in these images (color, size, tail). Indicate whether or not the cat is by the flower pots. If the cat is chasing a mouse, make up a name for the mouse."
objects:
- person
- cat
required_zones:
- steps
```

### Experiment with prompts
Expand Down
6 changes: 6 additions & 0 deletions docs/docs/configuration/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,12 @@ cameras:
# Format: {label}: {prompt}
object_prompts:
person: "My special person prompt."
# Optional: objects to generate descriptions for (default: all objects that are tracked)
objects:
- person
- cat
# Optional: Restrict generation to objects that entered any of the listed zones (default: none, all zones qualify)
required_zones: []

# Optional
ui:
Expand Down
12 changes: 6 additions & 6 deletions frigate/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import traceback
from datetime import datetime, timedelta
from functools import reduce
from typing import Optional
from typing import Any, Optional

import requests
from fastapi import APIRouter, Path, Request, Response
from fastapi import APIRouter, Body, Path, Request, Response
from fastapi.encoders import jsonable_encoder
from fastapi.params import Depends
from fastapi.responses import JSONResponse
from fastapi.responses import JSONResponse, PlainTextResponse
from markupsafe import escape
from peewee import operator

Expand All @@ -37,7 +37,7 @@
router = APIRouter(tags=[Tags.app])


@router.get("/")
@router.get("/", response_class=PlainTextResponse)
def is_healthy():
return "Frigate is running. Alive and healthy!"

Expand Down Expand Up @@ -82,7 +82,7 @@ def go2rtc_camera_stream(camera_name: str):
return JSONResponse(content=stream_data)


@router.get("/version")
@router.get("/version", response_class=PlainTextResponse)
def version():
return VERSION

Expand Down Expand Up @@ -166,7 +166,7 @@ def config_raw():


@router.post("/config/save")
def config_save(save_option: str, body: dict):
def config_save(save_option: str, body: Any = Body()):
new_config = body

if not new_config:
Expand Down
3 changes: 1 addition & 2 deletions frigate/api/defs/events_body.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from datetime import datetime
from typing import Optional, Union

from pydantic import BaseModel, Field
Expand Down Expand Up @@ -27,7 +26,7 @@ class EventsCreateBody(BaseModel):


class EventsEndBody(BaseModel):
end_time: Optional[int] = datetime.now().timestamp()
end_time: Optional[int] = None


class SubmitPlusBody(BaseModel):
Expand Down
9 changes: 4 additions & 5 deletions frigate/api/defs/review_query_parameters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from datetime import datetime, timedelta
from typing import Optional

from pydantic import BaseModel
Expand All @@ -11,8 +10,8 @@ class ReviewQueryParams(BaseModel):
reviewed: Optional[int] = 0
limit: Optional[int] = None
severity: Optional[str] = None
before: Optional[float] = datetime.now().timestamp()
after: Optional[float] = (datetime.now() - timedelta(hours=24)).timestamp()
before: Optional[float] = None
after: Optional[float] = None


class ReviewSummaryQueryParams(BaseModel):
Expand All @@ -24,6 +23,6 @@ class ReviewSummaryQueryParams(BaseModel):

class ReviewActivityMotionQueryParams(BaseModel):
cameras: Optional[str] = "all"
before: Optional[float] = datetime.now().timestamp()
after: Optional[float] = (datetime.now() - timedelta(hours=1)).timestamp()
before: Optional[float] = None
after: Optional[float] = None
scale: Optional[int] = 30
5 changes: 3 additions & 2 deletions frigate/api/event.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Event apis."""

import base64
import datetime
import io
import logging
import os
Expand Down Expand Up @@ -768,7 +769,7 @@ def false_positive(request: Request, event_id: str):
)

if not event.plus_id:
plus_response = send_to_plus(event_id)
plus_response = send_to_plus(request, event_id)
if plus_response.status_code != 200:
return plus_response
# need to refetch the event now that it has a plus_id
Expand Down Expand Up @@ -1073,7 +1074,7 @@ def create_event(
@router.put("/events/{event_id}/end")
def end_event(request: Request, event_id: str, body: EventsEndBody):
try:
end_time = body.end_time
end_time = body.end_time or datetime.datetime.now().timestamp()
request.app.external_processor.finish_manual_event(event_id, end_time)
except Exception:
return JSONResponse(
Expand Down
2 changes: 1 addition & 1 deletion frigate/api/fastapi_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ async def frigate_middleware(request: Request, call_next):
return response

# Rate limiter (used for login endpoint)
auth.rateLimiter.set_limit(frigate_config.auth.failed_login_rate_limit)
auth.rateLimiter.set_limit(frigate_config.auth.failed_login_rate_limit or "")
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware)
Expand Down
21 changes: 15 additions & 6 deletions frigate/api/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ def review(params: ReviewQueryParams = Depends()):
reviewed = params.reviewed
limit = params.limit
severity = params.severity
before = params.before
after = params.after
before = params.before or datetime.datetime.now().timestamp()
after = (
params.after
or (datetime.datetime.now() - datetime.timedelta(hours=24)).timestamp()
)

clauses = [
(
Expand Down Expand Up @@ -425,8 +428,11 @@ def delete_reviews(body: dict = None):
def motion_activity(params: ReviewActivityMotionQueryParams = Depends()):
"""Get motion and audio activity."""
cameras = params.cameras
before = params.before
after = params.after
before = params.before or datetime.datetime.now().timestamp()
after = (
params.after
or (datetime.datetime.now() - datetime.timedelta(hours=1)).timestamp()
)
# get scale in seconds
scale = params.scale

Expand Down Expand Up @@ -496,8 +502,11 @@ def motion_activity(params: ReviewActivityMotionQueryParams = Depends()):
def audio_activity(params: ReviewActivityMotionQueryParams = Depends()):
"""Get motion and audio activity."""
cameras = params.cameras
before = params.before
after = params.after
before = params.before or datetime.datetime.now().timestamp()
after = (
params.after
or (datetime.datetime.now() - datetime.timedelta(hours=1)).timestamp()
)
# get scale in seconds
scale = params.scale

Expand Down
16 changes: 16 additions & 0 deletions frigate/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,22 @@ class GenAICameraConfig(BaseModel):
title="Default caption prompt.",
)
object_prompts: Dict[str, str] = Field(default={}, title="Object specific prompts.")
objects: Union[str, List[str]] = Field(
default_factory=list,
title="List of objects to run generative AI for.",
)
required_zones: Union[str, List[str]] = Field(
default_factory=list,
title="List of required zones to be entered in order to run generative AI.",
)

@field_validator("required_zones", mode="before")
@classmethod
def validate_required_zones(cls, v):
if isinstance(v, str) and "," not in v:
return [v]

return v


class AudioConfig(FrigateBaseModel):
Expand Down
8 changes: 8 additions & 0 deletions frigate/embeddings/maintainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ def _process_finalized(self) -> None:
camera_config.genai.enabled
and self.genai_client is not None
and event.data.get("description") is None
and (
not camera_config.genai.objects
or event.label in camera_config.genai.objects
)
and (
not camera_config.genai.required_zones
or set(event.zones) & set(camera_config.genai.required_zones)
)
):
# Generate the description. Call happens in a thread since it is network bound.
threading.Thread(
Expand Down
22 changes: 9 additions & 13 deletions web/src/components/filter/CalendarFilterButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { DateRangePicker } from "../ui/calendar-range";
import { DateRange } from "react-day-picker";
import { useState } from "react";
import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog";

type CalendarFilterButtonProps = {
reviewSummary?: ReviewSummary;
Expand All @@ -24,6 +25,7 @@ export default function CalendarFilterButton({
day,
updateSelectedDay,
}: CalendarFilterButtonProps) {
const [open, setOpen] = useState(false);
const selectedDate = useFormattedTimestamp(
day == undefined ? 0 : day?.getTime() / 1000 + 1,
"%b %-d",
Expand Down Expand Up @@ -65,20 +67,14 @@ export default function CalendarFilterButton({
</>
);

if (isMobile) {
return (
<Drawer>
<DrawerTrigger asChild>{trigger}</DrawerTrigger>
<DrawerContent>{content}</DrawerContent>
</Drawer>
);
}

return (
<Popover>
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
<PopoverContent className="w-auto">{content}</PopoverContent>
</Popover>
<PlatformAwareDialog
trigger={trigger}
content={content}
contentClassName="w-auto"
open={open}
onOpenChange={setOpen}
/>
);
}

Expand Down
32 changes: 5 additions & 27 deletions web/src/components/filter/ReviewFilterGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Button } from "../ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { useCallback, useEffect, useMemo, useState } from "react";
Expand All @@ -8,7 +7,6 @@ import { ReviewFilter, ReviewSeverity, ReviewSummary } from "@/types/review";
import { getEndOfDayTimestamp } from "@/utils/dateUtil";
import { FaCheckCircle, FaFilter, FaRunning } from "react-icons/fa";
import { isDesktop, isMobile } from "react-device-detect";
import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer";
import { Switch } from "../ui/switch";
import { Label } from "../ui/label";
import MobileReviewSettingsDrawer, {
Expand All @@ -19,6 +17,7 @@ import FilterSwitch from "./FilterSwitch";
import { FilterList } from "@/types/filter";
import CalendarFilterButton from "./CalendarFilterButton";
import { CamerasFilterButton } from "./CamerasFilterButton";
import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog";

const REVIEW_FILTERS = [
"cameras",
Expand Down Expand Up @@ -367,28 +366,10 @@ function GeneralFilterButton({
/>
);

if (isMobile) {
return (
<Drawer
open={open}
onOpenChange={(open) => {
if (!open) {
setCurrentLabels(selectedLabels);
}

setOpen(open);
}}
>
<DrawerTrigger asChild>{trigger}</DrawerTrigger>
<DrawerContent className="max-h-[75dvh] overflow-hidden">
{content}
</DrawerContent>
</Drawer>
);
}

return (
<Popover
<PlatformAwareDialog
trigger={trigger}
content={content}
open={open}
onOpenChange={(open) => {
if (!open) {
Expand All @@ -397,10 +378,7 @@ function GeneralFilterButton({

setOpen(open);
}}
>
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
<PopoverContent>{content}</PopoverContent>
</Popover>
/>
);
}

Expand Down
Loading

0 comments on commit 3d1d775

Please sign in to comment.