mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-20 07:08:23 +03:00
Review Summary Optimizations (#22533)
* Use different association method * Clarify * Remove extra details from ollama schema * Fix Gemini Chat * Fix incorrect instructions * Improve name handling * Change order of information for llama.cpp * Simplify prompt * Fix formatting
This commit is contained in:
parent
e2bfa26719
commit
ede8b74371
@ -521,7 +521,7 @@ def run_analysis(
|
||||
for i, verified_label in enumerate(final_data["data"]["verified_objects"]):
|
||||
object_type = verified_label.replace("-verified", "").replace("_", " ")
|
||||
name = titlecase(sub_labels_list[i].replace("_", " "))
|
||||
unified_objects.append(f"{name} ({object_type})")
|
||||
unified_objects.append(f"{name} ← {object_type}")
|
||||
|
||||
for label in objects_list:
|
||||
if "-verified" in label:
|
||||
|
||||
@ -106,7 +106,7 @@ When forming your description:
|
||||
## Response Field Guidelines
|
||||
|
||||
Respond with a JSON object matching the provided schema. Field-specific guidance:
|
||||
- `scene`: Describe how the sequence begins, then the progression of events — all significant movements and actions in order. For example, if a vehicle arrives and then a person exits, describe both sequentially. Your description should align with and support the threat level you assign.
|
||||
- `scene`: Describe how the sequence begins, then the progression of events — all significant movements and actions in order. For example, if a vehicle arrives and then a person exits, describe both sequentially. Always use subject names from "Objects in Scene" — do not replace named subjects with generic terms like "a person" or "the individual". Your description should align with and support the threat level you assign.
|
||||
- `title`: Characterize **what took place and where** — interpret the overall purpose or outcome, do not simply compress the scene description into fewer words. Include the relevant location (zone, area, or entry point). Always include subject names from "Objects in Scene" — do not replace named subjects with generic terms. No editorial qualifiers like "routine" or "suspicious."
|
||||
- `potential_threat_level`: Must be consistent with your scene description and the activity patterns above.
|
||||
{get_concern_prompt()}
|
||||
@ -120,9 +120,7 @@ Respond with a JSON object matching the provided schema. Field-specific guidance
|
||||
|
||||
## Objects in Scene
|
||||
|
||||
Each line represents a detection state, not necessarily unique individuals. Parentheses indicate object type or category, use only the name/label in your response, not the parentheses.
|
||||
|
||||
**CRITICAL: When you see both recognized and unrecognized entries of the same type (e.g., "Joe (person)" and "Person"), visually count how many distinct people/objects you actually see based on appearance and clothing. If you observe only ONE person throughout the sequence, use ONLY the recognized name (e.g., "Joe"). The same person may be recognized in some frames but not others. Only describe both if you visually see MULTIPLE distinct people with clearly different appearances.**
|
||||
Each line represents a detection state, not necessarily unique individuals. The `←` symbol separates a recognized subject's name from their object type — use only the name (before the `←`) in your response, not the type after it. The same subject may appear across multiple lines if detected multiple times.
|
||||
|
||||
**Note: Unidentified objects (without names) are NOT indicators of suspicious activity—they simply mean the system hasn't identified that object.**
|
||||
{get_objects_list()}
|
||||
@ -188,8 +186,8 @@ Each line represents a detection state, not necessarily unique individuals. Pare
|
||||
if metadata.confidence > 1.0:
|
||||
metadata.confidence = min(metadata.confidence / 100.0, 1.0)
|
||||
|
||||
# If any verified objects (contain parentheses with name), set to 0
|
||||
if any("(" in obj for obj in review_data["unified_objects"]):
|
||||
# If any verified objects (contain ← separator), set to 0
|
||||
if any("←" in obj for obj in review_data["unified_objects"]):
|
||||
metadata.potential_threat_level = 0
|
||||
|
||||
metadata.time = review_data["start"]
|
||||
|
||||
@ -397,13 +397,13 @@ class GeminiClient(GenAIClient):
|
||||
tool_calls_by_index: dict[int, dict[str, Any]] = {}
|
||||
finish_reason = "stop"
|
||||
|
||||
response = self.provider.models.generate_content_stream(
|
||||
stream = await self.provider.aio.models.generate_content_stream(
|
||||
model=self.genai_config.model,
|
||||
contents=gemini_messages,
|
||||
config=types.GenerateContentConfig(**config_params),
|
||||
)
|
||||
|
||||
async for chunk in response:
|
||||
async for chunk in stream:
|
||||
if not chunk or not chunk.candidates:
|
||||
continue
|
||||
|
||||
|
||||
@ -64,7 +64,12 @@ class LlamaCppClient(GenAIClient):
|
||||
return None
|
||||
|
||||
try:
|
||||
content = []
|
||||
content = [
|
||||
{
|
||||
"type": "text",
|
||||
"text": prompt,
|
||||
}
|
||||
]
|
||||
for image in images:
|
||||
encoded_image = base64.b64encode(image).decode("utf-8")
|
||||
content.append(
|
||||
@ -75,12 +80,6 @@ class LlamaCppClient(GenAIClient):
|
||||
},
|
||||
}
|
||||
)
|
||||
content.append(
|
||||
{
|
||||
"type": "text",
|
||||
"text": prompt,
|
||||
}
|
||||
)
|
||||
|
||||
# Build request payload with llama.cpp native options
|
||||
payload = {
|
||||
|
||||
@ -53,6 +53,39 @@ class OllamaClient(GenAIClient):
|
||||
logger.warning("Error initializing Ollama: %s", str(e))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _clean_schema_for_ollama(schema: dict) -> dict:
|
||||
"""Strip Pydantic metadata from a JSON schema for Ollama compatibility.
|
||||
|
||||
Ollama's grammar-based constrained generation works best with minimal
|
||||
schemas. Pydantic adds title/description/constraint fields that can
|
||||
cause the grammar generator to silently skip required fields.
|
||||
"""
|
||||
STRIP_KEYS = {
|
||||
"title",
|
||||
"description",
|
||||
"minimum",
|
||||
"maximum",
|
||||
"exclusiveMinimum",
|
||||
"exclusiveMaximum",
|
||||
}
|
||||
result = {}
|
||||
for key, value in schema.items():
|
||||
if key in STRIP_KEYS:
|
||||
continue
|
||||
if isinstance(value, dict):
|
||||
result[key] = OllamaClient._clean_schema_for_ollama(value)
|
||||
elif isinstance(value, list):
|
||||
result[key] = [
|
||||
OllamaClient._clean_schema_for_ollama(item)
|
||||
if isinstance(item, dict)
|
||||
else item
|
||||
for item in value
|
||||
]
|
||||
else:
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
def _send(
|
||||
self,
|
||||
prompt: str,
|
||||
@ -73,7 +106,7 @@ class OllamaClient(GenAIClient):
|
||||
if response_format and response_format.get("type") == "json_schema":
|
||||
schema = response_format.get("json_schema", {}).get("schema")
|
||||
if schema:
|
||||
ollama_options["format"] = schema
|
||||
ollama_options["format"] = self._clean_schema_for_ollama(schema)
|
||||
result = self.provider.generate(
|
||||
self.genai_config.model,
|
||||
prompt,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user