search API
Search APIs
POST /api/v1/search/smart
Auth: Required
Scope: global / file-level
Semantic vector search using EmbeddingGemma-300m. Generates a query embedding via EmbeddingGemma (port 11436), then searches pgvector story_parent and llm_parent chunks by cosine similarity.
Request Parameters
| Field |
Type |
Required |
Default |
Description |
query |
string |
Yes |
— |
Search text |
file_uuid |
string |
No |
— |
File UUID to search within. If omitted, searches all files (global search) |
limit |
integer |
No |
5 |
Max results to return |
page |
integer |
No |
1 |
Page number |
page_size |
integer |
No |
5 |
Items per page |
Example (Global Search)
curl -s -X POST "$API/api/v1/search/smart" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT" \
-d '{"query": "Audrey Hepburn"}'
Example (File-specific Search)
curl -s -X POST "$API/api/v1/search/smart" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT" \
-d '{"file_uuid": "'"$FILE_UUID"'", "query": "Audrey Hepburn"}'
Response (200)
{
"query": "Audrey Hepburn",
"results": [
{
"file_uuid": "a6fb22eebefaef17e62af874997c5944",
"parent_id": 1087822,
"scene_order": 1087822,
"start_frame": 104438,
"end_frame": 104538,
"fps": 24.0,
"start_time": 4351.6,
"end_time": 4355.76,
"summary": "[4352s-4356s, 4s] Cast: Audrey Hepburn. Total: 2 lines, 10 words. Speakers: Audrey Hepburn (2 lines)",
"similarity": 0.67
}
],
"page": 1,
"page_size": 5,
"strategy": "semantic_vector_search"
}
| Field |
Type |
Description |
results[].file_uuid |
string |
File UUID where result was found |
POST /api/v1/search/universal
Auth: Required
Scope: global / file-level
Multi-type BM25 full-text search across chunks, frames, and persons. Uses PostgreSQL tsvector.
Request Parameters
| Field |
Type |
Required |
Default |
Description |
query |
string |
Yes |
— |
Search text |
file_uuid |
string |
No |
— |
Restrict to specific file. If omitted, searches all files (global search) |
types |
string[] |
No |
["chunk","frame","person"] |
Search types |
limit |
integer |
No |
10 |
Max results per type |
page |
integer |
No |
1 |
Page number |
page_size |
integer |
No |
20 |
Items per page |
Example (Global Search)
curl -s -X POST "$API/api/v1/search/universal" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT" \
-d '{"query": "Cary Grant"}'
Example (File-specific Search)
curl -s -X POST "$API/api/v1/search/universal" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT" \
-d '{"file_uuid": "'"$FILE_UUID"'", "query": "Cary Grant"}'
Response (200)
{
"results": [
{
"type": "chunk",
"file_uuid": "a6fb22eebefaef17e62af874997c5944",
"chunk_id": "bd80fec92b0b6963d177a2c55bf713e2_2",
"chunk_type": "story_child",
"start_frame": 5103,
"end_frame": 5127,
"start_time": 212.64,
"end_time": 213.64,
"text": "[213s-214s] Cary Grant: \"Olá!\"",
"score": 0.9
},
{
"type": "frame",
"file_uuid": "a6fb22eebefaef17e62af874997c5944",
"frame_number": 5105,
"timestamp": 212.72,
"score": 0.7,
"objects": null,
"ocr_texts": null,
"faces": null
},
{
"type": "person",
"file_uuid": "a6fb22eebefaef17e62af874997c5944",
"identity_id": 12,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"name": "Cary Grant",
"appearance_count": 542,
"score": 0.95
}
],
"total": 20,
"took_ms": 18
}
| Field |
Type |
Description |
results[].type |
string |
Result type: chunk, frame, or person |
results[].file_uuid |
string |
File UUID where result was found (all types) |
POST /api/v1/search/frames
Auth: Required
Scope: global / file-level
Search frames by YOLO objects, OCR text, face IDs, or pose detections. Filters frames based on visual content detected during processing.
Request Parameters
| Field |
Type |
Required |
Default |
Description |
file_uuid |
string |
No |
— |
Restrict to specific file |
object_class |
string |
No |
— |
Filter by YOLO object class (e.g., person, car, dog) |
ocr_text |
string |
No |
— |
Filter by OCR text content (ILIKE match) |
face_id |
string |
No |
— |
Filter by face detection ID |
time_range |
[float, float] |
No |
— |
Filter by time range [start_secs, end_secs] |
limit |
integer |
No |
100 |
Max results |
Example
# Search for frames containing "person" objects
curl -s -X POST "$API/api/v1/search/frames" \
-H "Content-Type: application/json" \
-H "X-API-Key: $KEY" \
-d '{"file_uuid": "'"$FILE_UUID"'", "object_class": "person", "limit": 20}'
# Search for frames with specific OCR text
curl -s -X POST "$API/api/v1/search/frames" \
-H "Content-Type: application/json" \
-H "X-API-Key: $KEY" \
-d '{"file_uuid": "'"$FILE_UUID"'", "ocr_text": "hello", "time_range": [10.0, 30.0]}'
Response (200)
{
"frames": [
{
"frame_number": 1200,
"timestamp": 50.0,
"file_uuid": "d3f9ae8e471a1fc4d47022c66091b920",
"objects": [{"class": "person", "confidence": 0.95, "bbox": [100, 50, 300, 400]}],
"ocr_texts": ["Hello World"],
"faces": [{"face_id": "face_42", "confidence": 0.88}],
"pose_persons": [{"trace_id": 2, "bbox": [120, 60, 280, 380]}]
}
],
"total": 15
}
| Field |
Type |
Description |
frames |
array |
Array of matching frame objects |
frames[].frame_number |
integer |
Frame number in video |
frames[].timestamp |
float |
Timestamp in seconds |
frames[].file_uuid |
string |
File UUID |
frames[].objects |
array/null |
YOLO detections in this frame |
frames[].ocr_texts |
array/null |
OCR text strings in this frame |
frames[].faces |
array/null |
Face detections in this frame |
frames[].pose_persons |
array/null |
Pose-detected persons in this frame |
total |
integer |
Total matching frame count |
POST /api/v1/search/llm-smart
Auth: Required
Scope: global / file-level
Smart search with LLM re-ranking. First fetches candidate results via RRF (Reciprocal Rank Fusion) using the existing smart search, then uses an LLM (Gemma4 on port 8000) to re-rank candidates by relevance to the query.
Request Parameters
| Field |
Type |
Required |
Default |
Description |
query |
string |
Yes |
— |
Search text |
file_uuid |
string |
No |
— |
File UUID to search within |
limit |
integer |
No |
10 |
Max results to return |
Pipeline
1. smart_search → fetch N candidates (limit × 3, clamped 10-20)
2. LLM rerank → re-order by relevance using Gemma4
3. trim → return top `limit` results
Example
curl -s -X POST "$API/api/v1/search/llm-smart" \
-H "Content-Type: application/json" \
-H "X-API-Key: $KEY" \
-d '{"query": "two people having a conversation about business", "limit": 5}'
Response (200)
{
"query": "two people having a conversation about business",
"results": [
{
"file_uuid": "d3f9ae8e471a1fc4d47022c66091b920",
"parent_id": 1234,
"scene_order": 1234,
"start_frame": 5000,
"end_frame": 5200,
"fps": 24.0,
"start_time": 208.3,
"end_time": 216.7,
"summary": "[208s-217s, 9s] Two people discussing project timeline...",
"similarity": 0.72
}
],
"page": 1,
"page_size": 5,
"strategy": "llm_reranked"
}
| Field |
Type |
Description |
strategy |
string |
Always "llm_reranked" for this endpoint |
results |
array |
Re-ranked search results (same format as smart search) |
Fallback
If LLM reranking fails (model unavailable, timeout), falls back to RRF order without error.
Visual Search
Auth: Required
Scope: global / file-level
Search text chunks → find associated identities. Returns chunks where face detections overlap with text content.
Query Parameters
| Field |
Type |
Required |
Default |
Description |
q |
string |
Yes |
— |
Search text (ILIKE match) |
file_uuid |
string |
No |
— |
Restrict to specific file. If omitted, searches all files (global search) |
limit |
integer |
No |
50 |
Max results |
page |
integer |
No |
1 |
Page number |
page_size |
integer |
No |
50 |
Items per page |
Example (Global Search)
curl -s "$API/api/v1/search/identity_text?q=love" -H "X-API-Key: $KEY"
Example (File-specific Search)
curl -s "$API/api/v1/search/identity_text?file_uuid=$FILE_UUID&q=love" -H "X-API-Key: $KEY"
Response (200)
{
"success": true,
"total": 5,
"results": [
{
"file_uuid": "a6fb22eebefaef17e62af874997c5944",
"chunk_id": "llm_parent_..._256_270",
"start_time": 256.256,
"end_time": 270.228,
"text_content": "...lack of affection...",
"identity_id": 9,
"identity_name": "Audrey Hepburn",
"identity_source": "tmdb",
"trace_id": 94
}
]
}
| Field |
Type |
Description |
results[].file_uuid |
string |
File UUID where chunk was found |
results[].identity_id |
integer |
Identity ID if face was detected |
results[].trace_id |
integer |
Face trace ID |
Visual Search (Planned)
| Method |
Endpoint |
Status |
Description |
| POST |
/api/v1/search/visual |
Not implemented |
Search visual chunks |
| POST |
/api/v1/search/visual/class |
Not implemented |
Search by object class |
| POST |
/api/v1/search/visual/density |
Not implemented |
Search by object density |
| POST |
/api/v1/search/visual/combination |
Not implemented |
Search by object combination |
| POST |
/api/v1/search/visual/stats |
Not implemented |
Visual chunk statistics |
Embedding Model
| Detail |
Value |
| Model |
EmbeddingGemma-300m |
| Endpoint |
POST /api/v1/embeddings on port 11436 |
| Dimension |
768 |
| Storage |
pgvector (chunk.embedding column) |
Updated: 2026-06-20 — Added llm-smart search, completed frames search documentation, marked visual search as planned
Version History
| Version |
Date |
Changes |
| 1.0 |
2026-10-24 |
Initial documentation |