| import ctypes |
| import numpy as np |
| import time |
| import sys |
| import os |
|
|
| |
| |
| |
|
|
| class OVHybridManager: |
| def __init__(self): |
| print("⚙️ Initializing OV-Hybrid Engine (Production v2)...") |
| self.lib = None |
| self._load_library() |
| |
| |
| self.doc_vectors = None |
| self.metadata = None |
| self.count = 0 |
| self.dim = 0 |
|
|
| def _load_library(self): |
| |
| |
| try: |
| |
| self.lib = ctypes.CDLL("./ov_hybrid_core.so") |
| except: |
| |
| import glob |
| files = glob.glob("build/**/*.so", recursive=True) |
| if files: |
| self.lib = ctypes.CDLL(files[0]) |
| else: |
| print("⚠️ Warning: C++ Extension not found. Run 'python3 setup.py build_ext --inplace'") |
| return |
|
|
| |
| self.lib.ov_hybrid_search.argtypes = [ |
| ctypes.POINTER(ctypes.c_float), |
| ctypes.POINTER(ctypes.c_float), |
| ctypes.POINTER(ctypes.c_float), |
| ctypes.c_int, |
| ctypes.c_int, |
| ctypes.POINTER(ctypes.c_int), |
| ctypes.POINTER(ctypes.c_float) |
| ] |
|
|
| def load_memory(self, vectors: np.ndarray, metadata_list: list): |
| """ |
| Load data into C++ accessible memory (Numpy). |
| metadata_list: List of dicts {'centrality', 'recency', 'weight'} |
| """ |
| self.count, self.dim = vectors.shape |
| |
| |
| self.doc_vectors = np.ascontiguousarray(vectors, dtype=np.float32) |
| |
| |
| meta_flat = [] |
| for m in metadata_list: |
| meta_flat.extend([m['centrality'], m['recency'], m['weight']]) |
| |
| self.metadata = np.ascontiguousarray(np.array(meta_flat, dtype=np.float32)) |
| |
| print(f"✅ Loaded {self.count} vectors (Dim: {self.dim}) into Hybrid Memory.") |
|
|
| def search(self, query_vector: np.ndarray): |
| if not self.lib: |
| raise RuntimeError("C++ Library not loaded.") |
| |
| q_vec = np.ascontiguousarray(query_vector, dtype=np.float32) |
| |
| best_idx = ctypes.c_int(-1) |
| best_score = ctypes.c_float(0.0) |
| |
| |
| q_ptr = q_vec.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) |
| db_ptr = self.doc_vectors.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) |
| meta_ptr = self.metadata.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) |
| |
| |
| self.lib.ov_hybrid_search( |
| q_ptr, db_ptr, meta_ptr, |
| self.count, self.dim, |
| ctypes.byref(best_idx), ctypes.byref(best_score) |
| ) |
| |
| return best_idx.value, best_score.value |
|
|