hope it works
Browse files- app.py +5 -3
- service/data_loader_service.py +3 -6
- service/rag_service.py +27 -38
- service/vector_store_service.py +5 -8
app.py
CHANGED
|
@@ -155,9 +155,6 @@ def query_endpoint(req: QueryRequest):
|
|
| 155 |
answer = generate_answer(req.query,"1")
|
| 156 |
|
| 157 |
# Update conversation memory
|
| 158 |
-
add_message(req.user_id, "user", req.query)
|
| 159 |
-
add_message(req.user_id, "assistant", answer)
|
| 160 |
-
|
| 161 |
return QueryResponse(
|
| 162 |
user_id=req.user_id,
|
| 163 |
query=req.query,
|
|
@@ -180,6 +177,11 @@ def classify_endpoint(req: QueryRequest):
|
|
| 180 |
"urgency": urgency
|
| 181 |
}
|
| 182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
|
| 184 |
if __name__ == "__main__":
|
| 185 |
import uvicorn
|
|
|
|
| 155 |
answer = generate_answer(req.query,"1")
|
| 156 |
|
| 157 |
# Update conversation memory
|
|
|
|
|
|
|
|
|
|
| 158 |
return QueryResponse(
|
| 159 |
user_id=req.user_id,
|
| 160 |
query=req.query,
|
|
|
|
| 177 |
"urgency": urgency
|
| 178 |
}
|
| 179 |
|
| 180 |
+
@app.on_event("startup")
|
| 181 |
+
def warmup():
|
| 182 |
+
classify_text("hello")
|
| 183 |
+
generate_answer("test", "1")
|
| 184 |
+
|
| 185 |
|
| 186 |
if __name__ == "__main__":
|
| 187 |
import uvicorn
|
service/data_loader_service.py
CHANGED
|
@@ -6,15 +6,12 @@ class CSVDataLoader:
|
|
| 6 |
self.path = Path(filename)
|
| 7 |
|
| 8 |
def load_qa_pairs(self) -> list[str]:
|
| 9 |
-
|
| 10 |
-
|
| 11 |
with self.path.open(encoding="utf-8") as f:
|
| 12 |
reader = csv.DictReader(f)
|
| 13 |
for row in reader:
|
| 14 |
q = row.get("question", "").strip()
|
| 15 |
a = row.get("answer", "").strip()
|
| 16 |
-
|
| 17 |
if q and a:
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
return documents
|
|
|
|
| 6 |
self.path = Path(filename)
|
| 7 |
|
| 8 |
def load_qa_pairs(self) -> list[str]:
|
| 9 |
+
docs = []
|
|
|
|
| 10 |
with self.path.open(encoding="utf-8") as f:
|
| 11 |
reader = csv.DictReader(f)
|
| 12 |
for row in reader:
|
| 13 |
q = row.get("question", "").strip()
|
| 14 |
a = row.get("answer", "").strip()
|
|
|
|
| 15 |
if q and a:
|
| 16 |
+
docs.append(f"Q: {q}\nA: {a}")
|
| 17 |
+
return docs
|
|
|
service/rag_service.py
CHANGED
|
@@ -1,55 +1,44 @@
|
|
|
|
|
|
|
|
| 1 |
|
| 2 |
from service.data_loader_service import CSVDataLoader
|
| 3 |
from service.embedded_service import EmbeddingService
|
| 4 |
from service.vector_store_service import VectorStoreService
|
| 5 |
from service.llm_service import LLMService
|
| 6 |
-
from service.memory_service import get_memory, save_memory
|
| 7 |
|
| 8 |
|
| 9 |
-
|
|
|
|
| 10 |
embedder = EmbeddingService()
|
| 11 |
llm = LLMService()
|
| 12 |
|
| 13 |
-
|
|
|
|
| 14 |
documents = loader.load_qa_pairs()
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
memory = get_memory(session_id)
|
| 25 |
-
|
| 26 |
-
prompt = f"""
|
| 27 |
-
<|system|>
|
| 28 |
-
You are a helpful assistant.
|
| 29 |
-
Answer ONLY using the provided context.
|
| 30 |
-
Give a COMPLETE, well-formed answer.
|
| 31 |
-
Do not stop mid-sentence.
|
| 32 |
-
If the answer is not in the context, say "I don't know".
|
| 33 |
|
| 34 |
-
|
| 35 |
-
{memory}
|
| 36 |
|
| 37 |
-
|
| 38 |
-
Context:
|
| 39 |
-
{chr(10).join(context)}
|
| 40 |
-
|
| 41 |
-
Question:
|
| 42 |
-
{question}
|
| 43 |
-
|
| 44 |
-
<|assistant|>
|
| 45 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
# ✅ Hard safety fallback
|
| 51 |
-
if not answer:
|
| 52 |
-
answer = context[0].split("Answer:", 1)[-1].strip()
|
| 53 |
-
|
| 54 |
-
save_memory(session_id, question, answer)
|
| 55 |
-
return answer
|
|
|
|
| 1 |
+
import pickle
|
| 2 |
+
from pathlib import Path
|
| 3 |
|
| 4 |
from service.data_loader_service import CSVDataLoader
|
| 5 |
from service.embedded_service import EmbeddingService
|
| 6 |
from service.vector_store_service import VectorStoreService
|
| 7 |
from service.llm_service import LLMService
|
|
|
|
| 8 |
|
| 9 |
|
| 10 |
+
CACHE = Path("embeddings.pkl")
|
| 11 |
+
|
| 12 |
embedder = EmbeddingService()
|
| 13 |
llm = LLMService()
|
| 14 |
|
| 15 |
+
# Load documents
|
| 16 |
+
loader = CSVDataLoader("data.csv")
|
| 17 |
documents = loader.load_qa_pairs()
|
| 18 |
|
| 19 |
+
# Load or compute embeddings
|
| 20 |
+
if CACHE.exists():
|
| 21 |
+
with CACHE.open("rb") as f:
|
| 22 |
+
embeddings = pickle.load(f)
|
| 23 |
+
else:
|
| 24 |
+
embeddings = embedder.embed(documents)
|
| 25 |
+
with CACHE.open("wb") as f:
|
| 26 |
+
pickle.dump(embeddings, f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
+
vector_store = VectorStoreService(embeddings, documents)
|
|
|
|
| 29 |
|
| 30 |
+
def generate_answer(question: str):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
"""
|
| 32 |
+
Generates answer for a query using RAG (retrieval + LLM).
|
| 33 |
+
"""
|
| 34 |
+
query_vec = embedder.embed([question])[0]
|
| 35 |
+
context = vector_store.search(query_vec, k=3)
|
| 36 |
|
| 37 |
+
prompt = (
|
| 38 |
+
"<|system|>Answer ONLY from context. If unsure say 'I don't know'.\n"
|
| 39 |
+
"<|user|>\n"
|
| 40 |
+
+ "\n".join(context)
|
| 41 |
+
+ f"\n\nQuestion: {question}\n<|assistant|>"
|
| 42 |
+
)
|
| 43 |
|
| 44 |
+
return llm.generate(prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
service/vector_store_service.py
CHANGED
|
@@ -2,13 +2,10 @@ import numpy as np
|
|
| 2 |
|
| 3 |
class VectorStoreService:
|
| 4 |
def __init__(self, embeddings, documents):
|
| 5 |
-
self.embeddings = np.array(embeddings
|
| 6 |
self.documents = documents
|
| 7 |
|
| 8 |
-
def search(self, query_embedding,
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
top_indices = scores.argsort()[-top_k:][::-1]
|
| 13 |
-
|
| 14 |
-
return [self.documents[i] for i in top_indices]
|
|
|
|
| 2 |
|
| 3 |
class VectorStoreService:
|
| 4 |
def __init__(self, embeddings, documents):
|
| 5 |
+
self.embeddings = np.array(embeddings)
|
| 6 |
self.documents = documents
|
| 7 |
|
| 8 |
+
def search(self, query_embedding, k=3):
|
| 9 |
+
scores = query_embedding @ self.embeddings.T
|
| 10 |
+
top_k = scores.argsort()[-k:][::-1]
|
| 11 |
+
return [self.documents[i] for i in top_k]
|
|
|
|
|
|
|
|
|