diff --git a/qdrant/main.py b/qdrant/main.py index 389cd9f..5cb40e0 100644 --- a/qdrant/main.py +++ b/qdrant/main.py @@ -148,7 +148,27 @@ def _build_filter(metadata: Dict[str, Any]) -> Optional[Filter]: def _point_id(raw: Optional[str]) -> str: - return raw or uuid.uuid4().hex + """Return a Qdrant-compatible point id. + + Qdrant accepts either an unsigned integer or a UUID string (with hyphens). + If the provided `raw` value is an int or valid UUID we return it (as int or str). + Otherwise we generate a new UUID string and the caller should store the + original `raw` value in the point payload under `_original_id`. + """ + if not raw: + return str(uuid.uuid4()) + # allow integer ids + try: + return int(raw) + except Exception: + pass + # allow UUID strings + try: + u = uuid.UUID(raw) + return str(u) + except Exception: + # fallback: generate a UUID + return str(uuid.uuid4()) # --------------------------------------------------------------------------- @@ -223,12 +243,19 @@ async def upsert_url(req: UpsertUrlRequest): vector = await _embed_url(req.url) pid = _point_id(req.id) payload = {**req.metadata, "source_url": req.url} + # preserve original user-provided id if it wasn't usable as a point id + if req.id is not None and str(pid) != str(req.id): + payload["_original_id"] = req.id col = _col(req.collection) - client.upsert( - collection_name=col, - points=[PointStruct(id=pid, vector=vector, payload=payload)], - ) + try: + client.upsert( + collection_name=col, + points=[PointStruct(id=pid, vector=vector, payload=payload)], + ) + except Exception as e: + raise HTTPException(500, str(e)) + return {"id": pid, "collection": col, "dim": len(vector)} @@ -252,12 +279,19 @@ async def upsert_file( payload = json.loads(metadata_json) except json.JSONDecodeError: raise HTTPException(400, "metadata_json must be valid JSON") + # preserve original user-provided id if it wasn't usable as a point id + if id is not None and str(pid) != str(id): + payload["_original_id"] = id col = _col(collection) - client.upsert( - collection_name=col, - points=[PointStruct(id=pid, vector=vector, payload=payload)], - ) + try: + client.upsert( + collection_name=col, + points=[PointStruct(id=pid, vector=vector, payload=payload)], + ) + except Exception as e: + raise HTTPException(500, str(e)) + return {"id": pid, "collection": col, "dim": len(vector)} @@ -266,10 +300,16 @@ def upsert_vector(req: UpsertVectorRequest): """Store a pre-computed vector directly (skip CLIP embedding).""" pid = _point_id(req.id) col = _col(req.collection) - client.upsert( - collection_name=col, - points=[PointStruct(id=pid, vector=req.vector, payload=req.metadata)], - ) + payload = dict(req.metadata or {}) + if req.id is not None and str(pid) != str(req.id): + payload["_original_id"] = req.id + try: + client.upsert( + collection_name=col, + points=[PointStruct(id=pid, vector=req.vector, payload=payload)], + ) + except Exception as e: + raise HTTPException(500, str(e)) return {"id": pid, "collection": col, "dim": len(req.vector)}