Spaces:
Running
Running
File size: 6,475 Bytes
e561008 | 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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | """
"Built on Rock" β Pinecone Ingestion Script
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Run this ONCE after setting up your Pinecone index to populate it with
content from "Built on Rock" by Iyanuoluwa Joseph Akinnusi.
Prerequisites:
1. Create a Pinecone index named 'venthrive-bff' with:
- Dimensions: 1024
- Metric: Cosine
- Cloud: AWS us-east-1 (Serverless, free tier)
2. Set PINECONE_API_KEY in backend/.env
3. Ensure the PDF is in the APEX folder (path configured below)
Usage (from the VenThrive/backend/ directory):
python scripts/ingest_book.py
No local ML library needed β embeddings are generated by Pinecone's
hosted multilingual-e5-large model (1024 dimensions).
"""
import os
import sys
import time
# Load backend env
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env"))
from pinecone import Pinecone
import pypdf
# βββ Config βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Absolute path β the PDF lives in the sibling APEX project folder
_BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
PDF_PATH = os.path.join(_BASE, "APEX", "Built On Rock by Iyanuoluwa Joseph Akinnusi-1.pdf")
CHUNK_WORDS = 400
OVERLAP_WORDS = 50
BATCH_SIZE = 90 # Pinecone Inference allows up to 96 inputs per request
EMBED_MODEL = "multilingual-e5-large"
def extract_pdf_text(path: str) -> str:
if not os.path.exists(path):
raise FileNotFoundError(
f"\n[ERR] PDF not found: {path}\n"
"Ensure 'Built On Rock by Iyanuoluwa Joseph Akinnusi-1.pdf' "
"is in the APEX folder."
)
reader = pypdf.PdfReader(path)
return "\n".join(page.extract_text() or "" for page in reader.pages)
def chunk_text(text: str, chunk_words: int, overlap_words: int) -> list[dict]:
words = text.split()
chunks = []
i = 0
while i < len(words):
chunk_text_str = " ".join(words[i : i + chunk_words])
chunks.append({
"id": f"chunk_{len(chunks):04d}",
"text": chunk_text_str,
"meta": {
"source": "built_on_rock",
"chunk_id": len(chunks),
"word_start": i,
"word_end": min(i + chunk_words, len(words)),
},
})
i += chunk_words - overlap_words
return chunks
def main():
api_key = os.environ.get("PINECONE_API_KEY", "")
index_name = os.environ.get("PINECONE_INDEX_NAME", "venthrive-bff")
if not api_key:
print("[ERR] PINECONE_API_KEY not set in backend/.env")
return
# ββ Extract text ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
print(f"[PDF] Reading: {os.path.basename(PDF_PATH)}")
text = extract_pdf_text(PDF_PATH)
words = len(text.split())
print(f" {words:,} words extracted from PDF")
# ββ Chunk βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
chunks = chunk_text(text, CHUNK_WORDS, OVERLAP_WORDS)
print(f" {len(chunks)} chunks ({CHUNK_WORDS} words each, {OVERLAP_WORDS} overlap)")
# ββ Connect to Pinecone βββββββββββββββββββββββββββββββββββββββββββββββββββ
print(f"\n[PIN] Connecting to Pinecone index '{index_name}'...")
pc = Pinecone(api_key=api_key)
index = pc.Index(index_name)
stats = index.describe_index_stats()
existing = stats.get("total_vector_count", 0)
print(f" Existing vectors: {existing}")
if existing > 0:
print(f" Index already has {existing} vectors.")
ans = input(" Clear and re-ingest? (y/N): ").strip().lower()
if ans == 'y':
index.delete(delete_all=True)
print(" β Cleared")
else:
print(" Skipping ingestion.")
return
# ββ Embed + upsert in batches βββββββββββββββββββββββββββββββββββββββββββββ
print(f"\n[AI] Embedding + uploading {len(chunks)} chunks via Pinecone Inference...")
print(" (Model: multilingual-e5-large, 1024 dims β no local ML needed)")
for i in range(0, len(chunks), BATCH_SIZE):
batch = chunks[i : i + BATCH_SIZE]
texts = [c["text"] for c in batch]
# Generate embeddings via Pinecone Inference API
embedding_result = pc.inference.embed(
model=EMBED_MODEL,
inputs=texts,
parameters={"input_type": "passage", "truncate": "END"},
)
embeddings = [e.values for e in embedding_result]
# Upsert vectors
vectors = [
{
"id": chunk["id"],
"values": embeddings[j],
"metadata": {**chunk["meta"], "text": chunk["text"]},
}
for j, chunk in enumerate(batch)
]
index.upsert(vectors=vectors)
done = min(i + BATCH_SIZE, len(chunks))
print(f" {done}/{len(chunks)} chunks uploaded")
# Small pause to stay within Pinecone rate limits
if done < len(chunks):
time.sleep(0.5)
# ββ Done ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
final = index.describe_index_stats()
total = final.get("total_vector_count", "?")
print(f"\n[OK] Ingestion complete! Index '{index_name}' now has {total} vectors.")
print(" VenThrive AI will now draw from 'Built on Rock' for every relevant query.")
if __name__ == "__main__":
main()
|