Spaces:
Sleeping
Sleeping
| """ | |
| Vector Store yönetimi - FAISS kullanarak. | |
| FAISS (Facebook AI Similarity Search): | |
| Vektörler arasında çok hızlı benzerlik araması yapan kütüphane. | |
| """ | |
| import faiss | |
| import numpy as np | |
| import pickle | |
| import os | |
| from typing import List, Tuple | |
| class FAISSVectorStore: | |
| """FAISS tabanlı vektör veritabanı.""" | |
| def __init__(self, embedding_dim=768): | |
| """ | |
| Args: | |
| embedding_dim: Embedding vektörlerinin boyutu | |
| """ | |
| self.embedding_dim = embedding_dim | |
| self.index = None | |
| self.documents = [] | |
| self.is_trained = False | |
| def create_index(self, embeddings, documents): | |
| """ | |
| FAISS index'i oluşturur ve embedding'leri ekler. | |
| Args: | |
| embeddings: numpy array (n_docs, embedding_dim) | |
| documents: Doküman listesi | |
| """ | |
| print(f"🔨 FAISS index oluşturuluyor...") | |
| print(f"Embedding shape: {embeddings.shape}") | |
| # Boyut kontrolü | |
| if embeddings.shape[1] != self.embedding_dim: | |
| self.embedding_dim = embeddings.shape[1] | |
| print(f"⚙️ Embedding boyutu güncellendi: {self.embedding_dim}") | |
| # L2 (Euclidean) mesafe kullanarak index oluştur | |
| # IndexFlatL2: En basit ve en doğru index tipi | |
| self.index = faiss.IndexFlatL2(self.embedding_dim) | |
| # Embedding'leri float32'ye çevir (FAISS zorunluluğu) | |
| embeddings = embeddings.astype('float32') | |
| # Index'e embedding'leri ekle | |
| self.index.add(embeddings) | |
| self.documents = documents | |
| self.is_trained = True | |
| print(f"Index oluşturuldu!") | |
| print(f"Toplam doküman sayısı: {self.index.ntotal}") | |
| def search(self, query_embedding, top_k=5): | |
| """ | |
| Sorgu embedding'ine en benzer dokümanları bulur. | |
| Args: | |
| query_embedding: Sorgu vektörü | |
| top_k: Kaç sonuç döndürülecek | |
| Returns: | |
| list: (skor, doküman) tuple'larının listesi | |
| """ | |
| if not self.is_trained: | |
| print("Index henüz oluşturulmamış!") | |
| return [] | |
| # Query'yi doğru formata çevir | |
| query_embedding = np.array([query_embedding]).astype('float32') | |
| # Arama yap | |
| distances, indices = self.index.search(query_embedding, top_k) | |
| # Sonuçları hazırla | |
| results = [] | |
| for dist, idx in zip(distances[0], indices[0]): | |
| if idx < len(self.documents): | |
| # Mesafeyi benzerlik skoruna çevir (düşük mesafe = yüksek benzerlik) | |
| similarity = 1 / (1 + dist) | |
| results.append({ | |
| 'score': float(similarity), | |
| 'document': self.documents[idx], | |
| 'distance': float(dist) | |
| }) | |
| return results | |
| def save(self, filepath): | |
| """ | |
| Index ve dokümanları kaydeder. | |
| Args: | |
| filepath: Kayıt yolu (uzantısız) | |
| """ | |
| if not self.is_trained: | |
| print("Kaydedilecek bir index yok!") | |
| return | |
| # Klasör yoksa oluştur | |
| os.makedirs(os.path.dirname(filepath) if os.path.dirname(filepath) else '.', exist_ok=True) | |
| # FAISS index'i kaydet | |
| index_path = f"{filepath}.index" | |
| faiss.write_index(self.index, index_path) | |
| # Dokümanları kaydet | |
| docs_path = f"{filepath}.pkl" | |
| with open(docs_path, 'wb') as f: | |
| pickle.dump({ | |
| 'documents': self.documents, | |
| 'embedding_dim': self.embedding_dim | |
| }, f) | |
| print(f"Vector store kaydedildi:") | |
| print(f" - Index: {index_path}") | |
| print(f" - Dokümanlar: {docs_path}") | |
| def load(self, filepath): | |
| """ | |
| Kaydedilmiş index ve dokümanları yükler. | |
| Args: | |
| filepath: Dosya yolu (uzantısız) | |
| """ | |
| index_path = f"{filepath}.index" | |
| docs_path = f"{filepath}.pkl" | |
| # Dosya kontrolü | |
| if not os.path.exists(index_path) or not os.path.exists(docs_path): | |
| print("Dosyalar bulunamadı!") | |
| return False | |
| # Index'i yükle | |
| self.index = faiss.read_index(index_path) | |
| # Dokümanları yükle | |
| with open(docs_path, 'rb') as f: | |
| data = pickle.load(f) | |
| self.documents = data['documents'] | |
| self.embedding_dim = data['embedding_dim'] | |
| self.is_trained = True | |
| print(f"Vector store yüklendi:") | |
| print(f"Doküman sayısı: {len(self.documents)}") | |
| print(f"Embedding boyutu: {self.embedding_dim}") | |
| return True | |
| def get_stats(self): | |
| """Index istatistiklerini gösterir.""" | |
| if not self.is_trained: | |
| print("Index henüz oluşturulmamış!") | |
| return | |
| print("\n" + "=" * 60) | |
| print("VECTOR STORE İSTATİSTİKLERİ") | |
| print("=" * 60) | |
| print(f"Toplam doküman: {self.index.ntotal}") | |
| print(f"Embedding boyutu: {self.embedding_dim}") | |
| print(f"Index tipi: {type(self.index).__name__}") | |
| print("=" * 60) | |
| # Test için main fonksiyonu | |
| if __name__ == "__main__": | |
| print("Vector Store Test Başlıyor...\n") | |
| # Test için sahte veri oluştur | |
| n_docs = 100 | |
| embedding_dim = 768 | |
| # Rastgele embedding'ler | |
| test_embeddings = np.random.rand(n_docs, embedding_dim).astype('float32') | |
| # Test dokümanları | |
| test_documents = [ | |
| {'text': f'Test doküman {i}', 'id': i} | |
| for i in range(n_docs) | |
| ] | |
| # Vector store oluştur | |
| store = FAISSVectorStore(embedding_dim=embedding_dim) | |
| store.create_index(test_embeddings, test_documents) | |
| # İstatistikleri göster | |
| store.get_stats() | |
| # Arama testi | |
| print("\nArama testi yapılıyor...") | |
| query = np.random.rand(embedding_dim).astype('float32') | |
| results = store.search(query, top_k=3) | |
| print(f"\nEn benzer {len(results)} doküman:") | |
| for i, result in enumerate(results, 1): | |
| print(f"{i}. Skor: {result['score']:.4f} - {result['document']['text']}") | |
| # Kaydetme testi | |
| print("\nKaydetme testi...") | |
| store.save("./data/test_store") | |
| # Yükleme testi | |
| print("\nYükleme testi...") | |
| new_store = FAISSVectorStore() | |
| new_store.load("./data/test_store") | |
| print("\n✨ Test tamamlandı!") |