mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-23 00:28:22 +03:00
Compare commits
No commits in common. "13209090f23ff1c55e265b6645c73036cc91b2e7" and "7bc2ef731b3d145d6cf0427ea4e2dd6ca837a3d4" have entirely different histories.
13209090f2
...
7bc2ef731b
@ -47,7 +47,7 @@ onnxruntime == 1.22.*
|
||||
# Embeddings
|
||||
transformers == 4.45.*
|
||||
# Generative AI
|
||||
google-genai == 1.58.*
|
||||
google-generativeai == 0.8.*
|
||||
ollama == 0.6.*
|
||||
openai == 1.65.*
|
||||
# push notifications
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
import warnings
|
||||
|
||||
from transformers import AutoFeatureExtractor, AutoTokenizer
|
||||
@ -55,7 +54,6 @@ class JinaV1TextEmbedding(BaseEmbedding):
|
||||
self.tokenizer = None
|
||||
self.feature_extractor = None
|
||||
self.runner = None
|
||||
self._lock = threading.Lock()
|
||||
files_names = list(self.download_urls.keys()) + [self.tokenizer_file]
|
||||
|
||||
if not all(
|
||||
@ -136,18 +134,17 @@ class JinaV1TextEmbedding(BaseEmbedding):
|
||||
)
|
||||
|
||||
def _preprocess_inputs(self, raw_inputs):
|
||||
with self._lock:
|
||||
max_length = max(len(self.tokenizer.encode(text)) for text in raw_inputs)
|
||||
return [
|
||||
self.tokenizer(
|
||||
text,
|
||||
padding="max_length",
|
||||
truncation=True,
|
||||
max_length=max_length,
|
||||
return_tensors="np",
|
||||
)
|
||||
for text in raw_inputs
|
||||
]
|
||||
max_length = max(len(self.tokenizer.encode(text)) for text in raw_inputs)
|
||||
return [
|
||||
self.tokenizer(
|
||||
text,
|
||||
padding="max_length",
|
||||
truncation=True,
|
||||
max_length=max_length,
|
||||
return_tensors="np",
|
||||
)
|
||||
for text in raw_inputs
|
||||
]
|
||||
|
||||
|
||||
class JinaV1ImageEmbedding(BaseEmbedding):
|
||||
@ -177,7 +174,6 @@ class JinaV1ImageEmbedding(BaseEmbedding):
|
||||
self.download_path = os.path.join(MODEL_CACHE_DIR, self.model_name)
|
||||
self.feature_extractor = None
|
||||
self.runner: BaseModelRunner | None = None
|
||||
self._lock = threading.Lock()
|
||||
files_names = list(self.download_urls.keys())
|
||||
if not all(
|
||||
os.path.exists(os.path.join(self.download_path, n)) for n in files_names
|
||||
@ -220,9 +216,8 @@ class JinaV1ImageEmbedding(BaseEmbedding):
|
||||
)
|
||||
|
||||
def _preprocess_inputs(self, raw_inputs):
|
||||
with self._lock:
|
||||
processed_images = [self._process_image(img) for img in raw_inputs]
|
||||
return [
|
||||
self.feature_extractor(images=image, return_tensors="np")
|
||||
for image in processed_images
|
||||
]
|
||||
processed_images = [self._process_image(img) for img in raw_inputs]
|
||||
return [
|
||||
self.feature_extractor(images=image, return_tensors="np")
|
||||
for image in processed_images
|
||||
]
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from google import genai
|
||||
from google.genai import errors, types
|
||||
import google.generativeai as genai
|
||||
from google.api_core.exceptions import GoogleAPICallError
|
||||
|
||||
from frigate.config import GenAIProviderEnum
|
||||
from frigate.genai import GenAIClient, register_genai_provider
|
||||
@ -16,51 +16,44 @@ logger = logging.getLogger(__name__)
|
||||
class GeminiClient(GenAIClient):
|
||||
"""Generative AI client for Frigate using Gemini."""
|
||||
|
||||
provider: genai.Client
|
||||
provider: genai.GenerativeModel
|
||||
|
||||
def _init_provider(self):
|
||||
"""Initialize the client."""
|
||||
# Merge provider_options into HttpOptions
|
||||
http_options_dict = {
|
||||
"api_version": "v1",
|
||||
"timeout": int(self.timeout * 1000), # requires milliseconds
|
||||
}
|
||||
|
||||
if isinstance(self.genai_config.provider_options, dict):
|
||||
http_options_dict.update(self.genai_config.provider_options)
|
||||
|
||||
return genai.Client(
|
||||
api_key=self.genai_config.api_key,
|
||||
http_options=types.HttpOptions(**http_options_dict),
|
||||
genai.configure(api_key=self.genai_config.api_key)
|
||||
return genai.GenerativeModel(
|
||||
self.genai_config.model, **self.genai_config.provider_options
|
||||
)
|
||||
|
||||
def _send(self, prompt: str, images: list[bytes]) -> Optional[str]:
|
||||
"""Submit a request to Gemini."""
|
||||
contents = [
|
||||
types.Part.from_bytes(data=img, mime_type="image/jpeg") for img in images
|
||||
data = [
|
||||
{
|
||||
"mime_type": "image/jpeg",
|
||||
"data": img,
|
||||
}
|
||||
for img in images
|
||||
] + [prompt]
|
||||
try:
|
||||
# Merge runtime_options into generation_config if provided
|
||||
generation_config_dict = {"candidate_count": 1}
|
||||
generation_config_dict.update(self.genai_config.runtime_options)
|
||||
|
||||
response = self.provider.models.generate_content(
|
||||
model=self.genai_config.model,
|
||||
contents=contents,
|
||||
config=types.GenerateContentConfig(
|
||||
**generation_config_dict,
|
||||
response = self.provider.generate_content(
|
||||
data,
|
||||
generation_config=genai.types.GenerationConfig(
|
||||
**generation_config_dict
|
||||
),
|
||||
request_options=genai.types.RequestOptions(
|
||||
timeout=self.timeout,
|
||||
),
|
||||
)
|
||||
except errors.APIError as e:
|
||||
except GoogleAPICallError as e:
|
||||
logger.warning("Gemini returned an error: %s", str(e))
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.warning("An unexpected error occurred with Gemini: %s", str(e))
|
||||
return None
|
||||
|
||||
try:
|
||||
description = response.text.strip()
|
||||
except (ValueError, AttributeError):
|
||||
except ValueError:
|
||||
# No description was generated
|
||||
return None
|
||||
return description
|
||||
|
||||
@ -89,7 +89,6 @@ def apply_log_levels(default: str, log_levels: dict[str, LogLevel]) -> None:
|
||||
"ws4py": LogLevel.error,
|
||||
"PIL": LogLevel.warning,
|
||||
"numba": LogLevel.warning,
|
||||
"google_genai.models": LogLevel.warning,
|
||||
**log_levels,
|
||||
}
|
||||
|
||||
|
||||
@ -887,10 +887,7 @@ function LifecycleItem({
|
||||
</span>
|
||||
<span className="font-medium text-foreground">
|
||||
{attributeAreaPx}{" "}
|
||||
{t("information.pixels", {
|
||||
ns: "common",
|
||||
area: attributeAreaPx,
|
||||
})}{" "}
|
||||
{t("information.pixels", { ns: "common" })}{" "}
|
||||
<span className="text-secondary-foreground">·</span>{" "}
|
||||
{attributeAreaPct}%
|
||||
</span>
|
||||
|
||||
@ -75,7 +75,6 @@ import SearchDetailDialog, {
|
||||
} from "@/components/overlay/detail/SearchDetailDialog";
|
||||
import { SearchResult } from "@/types/search";
|
||||
import { HiSparkles } from "react-icons/hi";
|
||||
import { capitalizeFirstLetter } from "@/utils/stringUtil";
|
||||
|
||||
type ModelTrainingViewProps = {
|
||||
model: CustomClassificationModelConfig;
|
||||
@ -89,7 +88,7 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
||||
// title
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${capitalizeFirstLetter(model.name)} - ${t("documentTitle")}`;
|
||||
document.title = `${model.name.toUpperCase()} - ${t("documentTitle")}`;
|
||||
}, [model.name, t]);
|
||||
|
||||
// model state
|
||||
|
||||
Loading…
Reference in New Issue
Block a user