feat: add Qdrant _faces collection embedding push
- Add qdrant_faces.py utility module for _faces collection operations - Modify face_processor.py to push embeddings to Qdrant (CoreML extraction re-enabled) - Modify store_traced_faces.py to update trace_id in Qdrant after face tracking - Collection schema: 512D vectors, Cosine distance, fixed name '_faces' - Payload: file_uuid, frame, trace_id, bbox, confidence, identity_id/uuid, stranger_id - Batch size: 100 (default), configurable via QDRANT_BATCH_SIZE env var - Error handling: face_processor.py exits with error if Qdrant push fails
This commit is contained in:
@@ -30,7 +30,9 @@ from pathlib import Path
|
||||
import coremltools as ct
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "utils"))
|
||||
from redis_publisher import RedisPublisher
|
||||
from qdrant_faces import push_face_embeddings_batch
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
SWIFT_BIN = os.path.join(SCRIPT_DIR, "swift_processors", ".build", "debug", "swift_face_pose")
|
||||
@@ -199,6 +201,7 @@ class FaceProcessorVision:
|
||||
embed_count = 0
|
||||
total_face_count = 0
|
||||
last_pct = -1
|
||||
all_embeddings = [] # Collect embeddings for Qdrant push
|
||||
|
||||
for frame_info in frames:
|
||||
frame_num = frame_info["frame"]
|
||||
@@ -225,11 +228,18 @@ class FaceProcessorVision:
|
||||
if face_img.size == 0:
|
||||
continue
|
||||
|
||||
# CoreML embedding - TODO: push to Qdrant _faces collection instead
|
||||
# emb = self.extract_face_embedding(face_img)
|
||||
emb = None
|
||||
# CoreML embedding - push to Qdrant _faces collection
|
||||
emb = self.extract_face_embedding(face_img)
|
||||
if emb is not None:
|
||||
embed_count += 1
|
||||
# Collect for batch Qdrant push
|
||||
all_embeddings.append({
|
||||
"frame": frame_num,
|
||||
"trace_id": 0, # Initial, updated by face_tracker
|
||||
"bbox": {"x": x, "y": y, "width": w, "height": h},
|
||||
"confidence": face.get("confidence", 0.5),
|
||||
"embedding": emb,
|
||||
})
|
||||
|
||||
# Pose classification
|
||||
pose_info = face.get("pose", {})
|
||||
@@ -292,6 +302,18 @@ class FaceProcessorVision:
|
||||
with open(self.output_path, "w") as f:
|
||||
json.dump(output, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# Push embeddings to Qdrant _faces collection
|
||||
if all_embeddings:
|
||||
try:
|
||||
pushed = push_face_embeddings_batch(self.uuid, all_embeddings, self.publisher)
|
||||
if pushed != len(all_embeddings):
|
||||
raise RuntimeError(
|
||||
f"Qdrant push incomplete: {pushed}/{len(all_embeddings)} embeddings pushed"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[FACE_V2] ERROR: Qdrant push failed: {e}", file=sys.stderr)
|
||||
raise RuntimeError(f"Qdrant push failed: {e}")
|
||||
|
||||
elapsed = time.time() - t0
|
||||
print(f"[FACE_V2] Done: {len(frames_list)} frames, {embed_count} embeddings, {elapsed:.0f}s")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user