Spaces:
Sleeping
Sleeping
File size: 4,634 Bytes
41604f6 889b393 41604f6 | 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 | """
Rebuild the Qdrant ``interview_questions`` collection from the local dataset.
This recreates, byte-for-byte, the vector database the original app used:
* collection name : interview_questions
* vector size : 384 (all-MiniLM-L6-v2)
* distance : COSINE
* payload : {"job_role": <lower>, "question": ..., "answer": ...}
The original cluster was deleted after inactivity, but every question is
preserved in ``data/shuffled_questions.json`` (4233 Q&A pairs, 26 roles),
which is exactly what populated Qdrant in the first place.
Usage:
export QDRANT_API_URL="https://<your-cluster>.qdrant.io:6333"
export QDRANT_API_KEY="<your-key>"
python scripts/rebuild_qdrant.py
It is safe to re-run: the collection is recreated from scratch each time.
"""
import json
import logging
import os
import sys
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
COLLECTION_NAME = "interview_questions"
VECTOR_SIZE = 384
DATA_FILE = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"data",
"shuffled_questions.json",
)
def main() -> int:
url = os.getenv("QDRANT_API_URL")
key = os.getenv("QDRANT_API_KEY")
if not url or not key:
logging.error(
"Set QDRANT_API_URL and QDRANT_API_KEY environment variables first."
)
return 1
# Qdrant cloud URLs need the :6333 REST port; add it if the user pasted
# the bare hostname from the dashboard.
if url.endswith("/"):
url = url[:-1]
if ".qdrant.io" in url and not url.rsplit(":", 1)[-1].isdigit():
url = url + ":6333"
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, PointStruct, VectorParams
from sentence_transformers import SentenceTransformer
logging.info("Loading dataset from %s", DATA_FILE)
with open(DATA_FILE, "r", encoding="utf-8") as f:
rows = json.load(f)
logging.info("Loaded %d Q&A rows", len(rows))
logging.info("Loading embedding model all-MiniLM-L6-v2 (first run downloads it)")
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
client = QdrantClient(url=url, api_key=key, check_compatibility=False, timeout=120)
logging.info("Recreating collection '%s' (size=%d, COSINE)", COLLECTION_NAME, VECTOR_SIZE)
client.recreate_collection(
collection_name=COLLECTION_NAME,
vectors_config=VectorParams(size=VECTOR_SIZE, distance=Distance.COSINE),
)
# The app filters questions by job_role, which requires a keyword payload
# index — without it Qdrant returns HTTP 400 and the interview silently
# falls back to generic default questions.
client.create_payload_index(
collection_name=COLLECTION_NAME,
field_name="job_role",
field_schema="keyword",
)
logging.info("Created keyword payload index on 'job_role'")
# Build the points. We embed the QUESTION text, exactly like the original
# notebook, and store role/question/answer in the payload.
questions, payloads = [], []
for item in rows:
try:
role = item["Job Role"].lower().strip()
question = item["Questions"].strip()
answer = item["Answers"].strip()
except (KeyError, AttributeError):
continue
if not question:
continue
questions.append(question)
payloads.append({"job_role": role, "question": question, "answer": answer})
logging.info("Embedding %d questions...", len(questions))
vectors = model.encode(questions, batch_size=128, show_progress_bar=True)
batch_size = 64
total = len(questions)
for start in range(0, total, batch_size):
end = min(start + batch_size, total)
points = [
PointStruct(id=i, vector=vectors[i].tolist(), payload=payloads[i])
for i in range(start, end)
]
for attempt in range(1, 4):
try:
client.upsert(collection_name=COLLECTION_NAME, points=points, wait=True)
break
except Exception as exc:
logging.warning("Batch %d-%d attempt %d failed: %s", start, end, attempt, exc)
if attempt == 3:
raise
logging.info("Uploaded %d/%d", end, total)
info = client.get_collection(COLLECTION_NAME)
logging.info(
"Done. Collection '%s' now has %s points (distance=%s).",
COLLECTION_NAME,
info.points_count,
info.config.params.vectors.distance,
)
return 0
if __name__ == "__main__":
sys.exit(main())
|