-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
92 lines (71 loc) · 2.96 KB
/
Copy pathmain.py
File metadata and controls
92 lines (71 loc) · 2.96 KB
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
from fastapi import FastAPI
from pydantic import BaseModel # Pydantic validates incoming request data
import ollama
import chromadb
from chromadb.utils.embedding_functions.ollama_embedding_function import (
OllamaEmbeddingFunction,
)
app = FastAPI()
# Connect to the same ChromaDB collection you built in Step 2
client = chromadb.PersistentClient(path="./chroma_db")
ef = OllamaEmbeddingFunction(
model_name="nomic-embed-text",
url="http://localhost:11434",
)
collection = client.get_or_create_collection(
name="personal_profile",
embedding_function=ef,
)
# Define the expected shape of incoming data for the POST endpoint
class DocumentSubmission(BaseModel):
user_name: str # Who this profile belongs to
content: str # The profile text to store
@app.post("/documents") # POST endpoint - accepts data in the request body
def add_document(submission: DocumentSubmission):
# Split the submitted profile into chunks by paragraph
chunks = [chunk.strip() for chunk in submission.content.split("\n\n") if chunk.strip()]
# Store each chunk in ChromaDB with the user's name attached as metadata
collection.add(
ids=[f"{submission.user_name}-chunk{i}" for i in range(len(chunks))],
documents=chunks,
metadatas=[
{"source": "profile", "user_name": submission.user_name, "chunk_index": i}
for i in range(len(chunks)) # user_name metadata lets us filter by user later
],
)
return {
"message": f"Added {len(chunks)} chunks for user '{submission.user_name}'.",
"user_name": submission.user_name,
"chunks_added": len(chunks),
}
@app.get("/ask")
def ask(question: str, user: str = None): # user is optional, None means search all profiles
# Build the query parameters
query_params = {
"query_texts": [question],
"n_results": 2,
}
# If a user name was provided, only search that user's chunks
if user:
query_params["where"] = {"user_name": user} # ChromaDB metadata filter
# Step 1: RETRIEVE - search ChromaDB for the most relevant chunks
results = collection.query(**query_params) # ** unpacks the dictionary as keyword arguments
context = "\n\n".join(results["documents"][0])
# Step 2: AUGMENT - build a prompt that includes the retrieved context
augmented_prompt = f"""Use the following context to answer the question.
If the context doesn't contain relevant information, say so.
Context:
{context}
Question: {question}"""
# Step 3: GENERATE - send the augmented prompt to the local LLM
response = ollama.chat(
model="qwen2.5:0.5b",
messages=[{"role": "user", "content": augmented_prompt}],
)
# Return the answer along with metadata about the query
return {
"question": question,
"answer": response["message"]["content"],
"context_used": results["documents"][0],
"filtered_by_user": user, # Shows which user was filtered (or None for all)
}