File size: 4,231 Bytes
0ddd1d3
 
17de32a
0ddd1d3
 
 
 
 
7021daf
 
 
0ddd1d3
 
 
 
 
7021daf
0ddd1d3
17de32a
0ddd1d3
 
7021daf
0ddd1d3
 
 
7021daf
0ddd1d3
 
 
 
 
 
 
7021daf
0ddd1d3
 
 
7021daf
17de32a
 
 
 
 
 
 
 
0ddd1d3
 
 
 
 
7021daf
0ddd1d3
17de32a
 
 
 
0ddd1d3
7021daf
0ddd1d3
 
 
 
 
17de32a
0ddd1d3
 
 
7021daf
0ddd1d3
7021daf
0ddd1d3
17de32a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7021daf
17de32a
 
 
 
7021daf
17de32a
0ddd1d3
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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()