Spaces:
Running
Running
Download src/lib/postgresql/vectors.py from Leon4gr45/brain: direct link, hf CLI and curl.
- Browser
- Download file 18.1 kB
-
https://huggingface.co/spaces/Leon4gr45/brain/resolve/main/src/lib/postgresql/vectors.py
- Command line
-
hf download hf://spaces/Leon4gr45/brain/src/lib/postgresql/vectors.py
-
curl -L -o vectors.py https://huggingface.co/spaces/Leon4gr45/brain/resolve/main/src/lib/postgresql/vectors.py
18.1 kB
| """ | |
| File: /vectors.py | |
| Project: postgresql | |
| Created Date: Sunday May 24th 2026 | |
| Author: Christian Nonis <alch.infoemail@gmail.com> | |
| """ | |
| from __future__ import annotations | |
| from contextlib import contextmanager | |
| import hashlib | |
| import json | |
| import logging | |
| import re | |
| import threading | |
| from typing import Any, Iterator, Optional | |
| import psycopg2 | |
| import psycopg2.extras | |
| from pgvector.psycopg2 import register_vector | |
| from src.adapters.interfaces.embeddings import VectorStoreClient | |
| from src.config import config | |
| from src.constants.embeddings import EMBEDDING_STORES_SIZES, Vector | |
| from src.lib.embeddings.profile import EmbeddingProfileError, index_profile, require_matching_profile | |
| from ._provisioning import ( | |
| borrow, | |
| clear_brain_database, | |
| require_registered_brain, | |
| get_brain_pool, | |
| ) | |
| logger = logging.getLogger(__name__) | |
| _STORE_NAME_RE = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$") | |
| def string_to_int64(s: str) -> int: | |
| sha256 = hashlib.sha256(s.encode()).digest() | |
| return int.from_bytes(sha256[:8], byteorder="big") % (2**63) | |
| def _to_int_id(value: Any) -> int: | |
| if isinstance(value, int): | |
| return value | |
| if isinstance(value, str): | |
| try: | |
| return int(value) | |
| except ValueError: | |
| return string_to_int64(value) | |
| return string_to_int64(str(value)) | |
| def _safe_store(store: str) -> str: | |
| if not _STORE_NAME_RE.match(store): | |
| raise ValueError(f"Invalid store name: {store}") | |
| return store | |
| def _table_name(store: str) -> str: | |
| return f"vectors_{_safe_store(store)}" | |
| def _vector_index_ddl( | |
| table: str, dimension: int, *, search_enabled: bool | None = None | |
| ) -> str: | |
| dim = int(dimension) | |
| if search_enabled is None: | |
| search_enabled = bool(config.search_enabled) | |
| if dim <= 2000: | |
| return f""" | |
| CREATE INDEX IF NOT EXISTS idx_{table}_embeddings | |
| ON {table} USING hnsw (embeddings vector_cosine_ops); | |
| """ | |
| if not search_enabled: | |
| return "" | |
| return f""" | |
| CREATE INDEX IF NOT EXISTS idx_{table}_embeddings_halfvec | |
| ON {table} USING hnsw | |
| ((embeddings::halfvec({dim})) halfvec_cosine_ops); | |
| """ | |
| def _uses_halfvec_ann(dimension: int, *, search_enabled: bool | None = None) -> bool: | |
| if search_enabled is None: | |
| search_enabled = bool(config.search_enabled) | |
| try: | |
| dim = int(dimension) | |
| except (TypeError, ValueError): | |
| return False | |
| return search_enabled and dim > 2000 | |
| def _table_vector_dimension(cur: psycopg2.extensions.cursor, table: str) -> Optional[int]: | |
| cur.execute( | |
| """ | |
| SELECT a.atttypmod | |
| FROM pg_attribute a | |
| JOIN pg_class c ON a.attrelid = c.oid | |
| JOIN pg_namespace n ON c.relnamespace = n.oid | |
| WHERE c.relname = %s | |
| AND a.attname = 'embeddings' | |
| AND NOT a.attisdropped | |
| AND n.nspname = current_schema() | |
| """, | |
| (table,), | |
| ) | |
| row = cur.fetchone() | |
| if not row or row[0] is None or row[0] < 1: | |
| return None | |
| return int(row[0]) | |
| class PostgreSQLVectorStoreClient(VectorStoreClient): | |
| """ | |
| Vector store backed by PostgreSQL with the pgvector extension. | |
| Each brain owns its own database (`brain_<sanitized_id>`); per-store tables | |
| live inside that database with no `brain_id` column. The `vector` extension | |
| is enabled lazily, once per brain database. | |
| """ | |
| def __init__(self): | |
| self._lock = threading.RLock() | |
| self._brain_extensions_ready: set[str] = set() | |
| self._initialized_stores: set[str] = set() | |
| def _connection(self, brain_id: str) -> Iterator[psycopg2.extensions.connection]: | |
| self._ensure_extension(brain_id) | |
| with borrow(get_brain_pool(brain_id)) as conn: | |
| register_vector(conn) | |
| yield conn | |
| def _ensure_extension(self, brain_id: str) -> None: | |
| require_registered_brain(brain_id) | |
| if brain_id in self._brain_extensions_ready: | |
| return | |
| with self._lock: | |
| if brain_id in self._brain_extensions_ready: | |
| return | |
| with borrow(get_brain_pool(brain_id)) as conn: | |
| with conn.cursor() as cur: | |
| cur.execute("CREATE EXTENSION IF NOT EXISTS vector") | |
| conn.commit() | |
| self._brain_extensions_ready.add(brain_id) | |
| def clear_brain_data(self, brain_id: str) -> None: | |
| clear_brain_database(brain_id, table_prefixes=("vectors_",)) | |
| self._brain_extensions_ready.discard(brain_id) | |
| self._initialized_stores = { | |
| key for key in self._initialized_stores if not key.startswith(f"{brain_id}:") | |
| } | |
| def _ensure_store(self, store: str, brain_id: str) -> None: | |
| require_registered_brain(brain_id) | |
| if store not in EMBEDDING_STORES_SIZES: | |
| raise ValueError(f"Store {store} not available") | |
| dimension = EMBEDDING_STORES_SIZES[store] | |
| profile = index_profile(config, dimension) | |
| key = f"{brain_id}:{store}:{json.dumps(profile, sort_keys=True)}" | |
| if key in self._initialized_stores: | |
| return | |
| with self._lock: | |
| if key in self._initialized_stores: | |
| return | |
| table = _table_name(store) | |
| index_ddl = _vector_index_ddl(table, dimension) | |
| ddl = f""" | |
| CREATE TABLE IF NOT EXISTS {table} ( | |
| id BIGINT PRIMARY KEY, | |
| uuid TEXT NOT NULL, | |
| embeddings vector({dimension}), | |
| metadata JSONB NOT NULL DEFAULT '{{}}'::jsonb | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_{table}_uuid | |
| ON {table} (uuid); | |
| {index_ddl} | |
| """ | |
| with self._connection(brain_id) as conn: | |
| # Roll back on any mismatch, including pooled connections. | |
| with conn, conn.cursor() as cur: | |
| cur.execute("SELECT pg_advisory_xact_lock(hashtext(%s))", ("brainapi-embedding-profiles",)) | |
| existing_dim = _table_vector_dimension(cur, table) | |
| if existing_dim is not None and existing_dim != dimension: | |
| raise EmbeddingProfileError( | |
| f"Embedding index/profile mismatch for {table}: existing dimension " | |
| f"{existing_dim}, configured {dimension}. Use a new empty brain/index " | |
| "or explicitly re-index; existing vectors will not be deleted." | |
| ) | |
| cur.execute(""" | |
| CREATE TABLE IF NOT EXISTS embedding_profiles ( | |
| store TEXT PRIMARY KEY, | |
| profile JSONB NOT NULL | |
| ) | |
| """) | |
| cur.execute("SELECT profile FROM embedding_profiles WHERE store = %s", (store,)) | |
| row = cur.fetchone() | |
| require_matching_profile(row[0] if row else None, profile, legacy_index=existing_dim is not None) | |
| try: | |
| cur.execute(ddl) | |
| except Exception as exc: | |
| if _uses_halfvec_ann(dimension): | |
| raise RuntimeError( | |
| "SEARCH_ENABLED=true requires a halfvec HNSW index " | |
| f"on {table} (dimension {dimension} > 2000). " | |
| "The vector backend could not create it: " | |
| f"{exc}" | |
| ) from exc | |
| raise | |
| cur.execute( | |
| "INSERT INTO embedding_profiles (store, profile) VALUES (%s, %s::jsonb) ON CONFLICT (store) DO NOTHING", | |
| (store, json.dumps(profile)), | |
| ) | |
| conn.commit() | |
| self._initialized_stores.add(key) | |
| def add_vectors( | |
| self, vectors: list[Vector], store: str, brain_id: str | |
| ) -> list[str]: | |
| if not vectors: | |
| return [] | |
| self._ensure_store(store, brain_id) | |
| table = _table_name(store) | |
| rows = [] | |
| ids: list[int] = [] | |
| for vector in vectors: | |
| int_id = string_to_int64(vector.id) | |
| ids.append(int_id) | |
| metadata = dict(vector.metadata or {}) | |
| metadata.pop("id", None) | |
| metadata.pop("embeddings", None) | |
| metadata.pop("distance", None) | |
| rows.append( | |
| ( | |
| int_id, | |
| vector.id, | |
| vector.embeddings, | |
| json.dumps(metadata, default=str), | |
| ) | |
| ) | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor() as cur: | |
| psycopg2.extras.execute_values( | |
| cur, | |
| f""" | |
| INSERT INTO {table} | |
| (id, uuid, embeddings, metadata) | |
| VALUES %s | |
| ON CONFLICT (id) DO UPDATE SET | |
| uuid = EXCLUDED.uuid, | |
| embeddings = EXCLUDED.embeddings, | |
| metadata = EXCLUDED.metadata | |
| """, | |
| rows, | |
| template="(%s, %s, %s, %s::jsonb)", | |
| ) | |
| conn.commit() | |
| return ids | |
| def search_vectors( | |
| self, data_vector: list[float], brain_id: str, store: str, k: int = 10 | |
| ) -> list[Vector]: | |
| from src.utils.vector_search import ann_overfetch_k, stable_top_k_vectors | |
| self._ensure_store(store, brain_id) | |
| if k <= 0: | |
| return [] | |
| table = _table_name(store) | |
| fetch_k = ann_overfetch_k(k) | |
| dimension = EMBEDDING_STORES_SIZES[store] | |
| use_halfvec = _uses_halfvec_ann(dimension) | |
| if use_halfvec: | |
| order_sql = ( | |
| f"embeddings::halfvec({dimension}) " | |
| f"<=> (%s::vector)::halfvec({dimension})" | |
| ) | |
| else: | |
| order_sql = "embeddings <=> %s::vector" | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: | |
| cur.execute( | |
| "SELECT set_config('hnsw.ef_search', %s, true)", | |
| (str(max(100, fetch_k)),), | |
| ) | |
| cur.execute( | |
| f""" | |
| SELECT id, uuid, metadata, | |
| (embeddings <=> %s::vector) AS distance | |
| FROM {table} | |
| ORDER BY {order_sql}, uuid ASC, id ASC | |
| LIMIT %s | |
| """, | |
| (data_vector, data_vector, fetch_k), | |
| ) | |
| rows = cur.fetchall() | |
| results: list[Vector] = [] | |
| for row in rows: | |
| metadata = dict(row["metadata"] or {}) | |
| row_uuid = row.get("uuid") | |
| if row_uuid and not metadata.get("uuid"): | |
| metadata["uuid"] = str(row_uuid) | |
| results.append( | |
| Vector( | |
| id=str(row_uuid or row["id"]), | |
| metadata=metadata, | |
| distance=float(row["distance"]), | |
| ) | |
| ) | |
| return stable_top_k_vectors(results, k) | |
| def get_by_ids(self, ids: list[str], store: str, brain_id: str) -> list[Vector]: | |
| if not ids: | |
| return [] | |
| self._ensure_store(store, brain_id) | |
| table = _table_name(store) | |
| int_ids = [_to_int_id(i) for i in ids] | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: | |
| cur.execute( | |
| f""" | |
| SELECT id, uuid, embeddings, metadata | |
| FROM {table} | |
| WHERE id = ANY(%s) | |
| """, | |
| (int_ids,), | |
| ) | |
| rows = cur.fetchall() | |
| results: list[Vector] = [] | |
| for row in rows: | |
| embeddings = row["embeddings"] | |
| if embeddings is not None and not isinstance(embeddings, list): | |
| embeddings = list(embeddings) | |
| results.append( | |
| Vector( | |
| id=row["uuid"] or str(row["id"]), | |
| embeddings=embeddings, | |
| metadata=dict(row["metadata"] or {}), | |
| ) | |
| ) | |
| return results | |
| def search_similar_by_ids( | |
| self, | |
| vector_ids: list[str], | |
| brain_id: str, | |
| store: str, | |
| min_similarity: float, | |
| limit: int = 10, | |
| ) -> dict[str, list[Vector]]: | |
| if not vector_ids: | |
| return {} | |
| self._ensure_store(store, brain_id) | |
| table = _table_name(store) | |
| int_ids = [_to_int_id(i) for i in vector_ids] | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: | |
| cur.execute( | |
| f""" | |
| SELECT id, uuid, embeddings | |
| FROM {table} | |
| WHERE id = ANY(%s) | |
| """, | |
| (int_ids,), | |
| ) | |
| origin_rows = cur.fetchall() | |
| embeddings_by_id: dict[int, list[float]] = {} | |
| for row in origin_rows: | |
| embedding = row["embeddings"] | |
| if embedding is None: | |
| continue | |
| if not isinstance(embedding, list): | |
| embedding = list(embedding) | |
| embeddings_by_id[row["id"]] = embedding | |
| out: dict[str, list[Vector]] = {str(v_id): [] for v_id in vector_ids} | |
| if not embeddings_by_id: | |
| return out | |
| fetch_limit = max(limit * 5, limit) + 1 | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: | |
| for origin_id, embedding in embeddings_by_id.items(): | |
| cur.execute( | |
| f""" | |
| SELECT id, uuid, metadata, | |
| (embeddings <=> %s::vector) AS distance | |
| FROM {table} | |
| ORDER BY embeddings <=> %s::vector | |
| LIMIT %s | |
| """, | |
| (embedding, embedding, fetch_limit), | |
| ) | |
| rows = cur.fetchall() | |
| collected: list[Vector] = [] | |
| for row in rows: | |
| if row["id"] == origin_id: | |
| continue | |
| distance = float(row["distance"]) | |
| similarity = 1.0 - distance | |
| if similarity < min_similarity: | |
| continue | |
| collected.append( | |
| Vector( | |
| id=str(row["id"]), | |
| metadata=dict(row["metadata"] or {}), | |
| distance=distance, | |
| ) | |
| ) | |
| if len(collected) >= limit: | |
| break | |
| out[str(origin_id)] = collected | |
| return out | |
| def remove_vectors(self, ids: list[str], store: str, brain_id: str) -> None: | |
| if not ids: | |
| return | |
| self._ensure_store(store, brain_id) | |
| table = _table_name(store) | |
| int_ids = [_to_int_id(i) for i in ids] | |
| try: | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor() as cur: | |
| cur.execute( | |
| f""" | |
| DELETE FROM {table} | |
| WHERE id = ANY(%s) | |
| """, | |
| (int_ids,), | |
| ) | |
| conn.commit() | |
| except Exception as exc: | |
| print(f"[PostgreSQLVectorStore] Failed to remove vectors from {store}: {exc}") | |
| def list_vectors( | |
| self, | |
| store: str, | |
| brain_id: str, | |
| limit: int = 10, | |
| skip: int = 0, | |
| include_embeddings: bool = False, | |
| ) -> tuple[list[Vector], int]: | |
| self._ensure_store(store, brain_id) | |
| table = _table_name(store) | |
| embedding_col = ", embeddings" if include_embeddings else "" | |
| with self._connection(brain_id) as conn: | |
| with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: | |
| cur.execute(f"SELECT COUNT(*) AS total FROM {table}") | |
| total = int(cur.fetchone()["total"]) | |
| cur.execute( | |
| f""" | |
| SELECT id, uuid, metadata{embedding_col} | |
| FROM {table} | |
| ORDER BY id | |
| LIMIT %s OFFSET %s | |
| """, | |
| (limit, skip), | |
| ) | |
| rows = cur.fetchall() | |
| results: list[Vector] = [] | |
| for row in rows: | |
| embeddings = None | |
| if include_embeddings: | |
| embeddings = row.get("embeddings") | |
| if embeddings is not None and not isinstance(embeddings, list): | |
| embeddings = list(embeddings) | |
| results.append( | |
| Vector( | |
| id=row["uuid"] or str(row["id"]), | |
| embeddings=embeddings, | |
| metadata=dict(row["metadata"] or {}), | |
| ) | |
| ) | |
| return results, total | |
| _postgresql_vector_store_client: Optional[PostgreSQLVectorStoreClient] = None | |
| def get_postgresql_vector_store_client() -> PostgreSQLVectorStoreClient: | |
| global _postgresql_vector_store_client | |
| if _postgresql_vector_store_client is None: | |
| _postgresql_vector_store_client = PostgreSQLVectorStoreClient() | |
| return _postgresql_vector_store_client | |