Spaces:
Sleeping
Sleeping
| import os | |
| import uuid | |
| import json | |
| import numpy as np | |
| from services.embedding_service import get_embedding_model | |
| from kb_docs import KB_DOCS | |
| from supabase import create_client, Client | |
| from config import SUPABASE_URL, SUPABASE_KEY | |
| from services.observability import setup_logger | |
| logger = setup_logger(__name__) | |
| def ensure_ingested(): | |
| """ | |
| Idempotent function that seeds both the local numpy embeddings and the remote Supabase database. | |
| """ | |
| logger.info("Verifying ingestion state...") | |
| embedder = get_embedding_model() | |
| # 1. Local Numpy KB for Amara (Idempotent) | |
| if not os.path.exists("kb_embeddings.npy"): | |
| logger.info("kb_embeddings.npy not found, generating local embeddings...") | |
| texts = [d["text"] for d in KB_DOCS] | |
| kb_embeddings = embedder.encode(texts, normalize_embeddings=True) | |
| np.save("kb_embeddings.npy", kb_embeddings) | |
| logger.info(f"Embedded {len(texts)} KB docs and saved to kb_embeddings.npy") | |
| else: | |
| # Check shape to ensure it's valid, otherwise overwrite | |
| try: | |
| arr = np.load("kb_embeddings.npy") | |
| if len(arr) != len(KB_DOCS): | |
| raise ValueError("Mismatch length") | |
| except Exception: | |
| logger.info("kb_embeddings.npy is corrupted or outdated. Regenerating...") | |
| texts = [d["text"] for d in KB_DOCS] | |
| kb_embeddings = embedder.encode(texts, normalize_embeddings=True) | |
| np.save("kb_embeddings.npy", kb_embeddings) | |
| logger.info(f"Embedded {len(texts)} KB docs and saved to kb_embeddings.npy") | |
| # 2. Read Real Estate Methodology KB | |
| methodology_docs = [] | |
| if os.path.exists("methodology_kb.json"): | |
| with open("methodology_kb.json", "r", encoding="utf-8") as f: | |
| methodology_docs = json.load(f) | |
| # 3. Remote Supabase KB for Real Estate (Idempotent) | |
| supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) | |
| try: | |
| existing_res = supabase.table("re_knowledge_base").select("section_title").execute() | |
| existing_titles = {row["section_title"] for row in existing_res.data} | |
| except Exception as e: | |
| logger.error(f"Failed to query Supabase: {e}") | |
| existing_titles = set() | |
| for doc in methodology_docs: | |
| if "section_title" not in doc or "chunk_content" not in doc: | |
| continue | |
| if doc["section_title"] not in existing_titles: | |
| logger.info(f"Seeding missing chunk to Supabase: {doc['section_title']}") | |
| vector = embedder.encode(doc["chunk_content"]).tolist() | |
| payload = { | |
| "id": str(uuid.uuid4()), | |
| "section_title": doc["section_title"], | |
| "chunk_content": doc["chunk_content"], | |
| "embedding": vector, | |
| } | |
| try: | |
| supabase.table("re_knowledge_base").insert(payload).execute() | |
| logger.info(f"Successfully seeded: {doc['section_title']}") | |
| except Exception as e: | |
| logger.error(f"Failed to seed {doc['section_title']}: {e}") | |
| # 4. Local Pre-Router Embeddings for section_titles (Idempotent) | |
| section_titles = [doc["section_title"] for doc in methodology_docs if "section_title" in doc] | |
| regenerate_titles = False | |
| if not os.path.exists("section_title_embeddings.npy") or not os.path.exists("section_titles.json"): | |
| regenerate_titles = True | |
| else: | |
| try: | |
| with open("section_titles.json", "r", encoding="utf-8") as f: | |
| saved_titles = json.load(f) | |
| if saved_titles != section_titles: | |
| regenerate_titles = True | |
| except Exception: | |
| regenerate_titles = True | |
| if regenerate_titles and section_titles: | |
| logger.info("Generating section_title_embeddings.npy...") | |
| title_embeddings = embedder.encode(section_titles, normalize_embeddings=True) | |
| np.save("section_title_embeddings.npy", title_embeddings) | |
| with open("section_titles.json", "w", encoding="utf-8") as f: | |
| json.dump(section_titles, f, indent=2) | |
| logger.info(f"Saved {len(section_titles)} section title embeddings for pre-routing.") | |
| if __name__ == "__main__": | |
| ensure_ingested() | |