Spaces:
Sleeping
Sleeping
Upgraded to Groq RAG Engine with Secure Env Vars
Browse files- __pycache__/api.cpython-312.pyc +0 -0
- ai_brain.py +34 -0
- api.py +80 -0
- ask_brain.py +45 -0
- render.yaml +6 -0
- requirements.txt +6 -0
__pycache__/api.cpython-312.pyc
ADDED
|
Binary file (3.72 kB). View file
|
|
|
ai_brain.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from sentence_transformers import SentenceTransformer
|
| 3 |
+
from supabase import create_client, Client
|
| 4 |
+
|
| 5 |
+
# 1. Put your real URL and Key inside the quotation marks below!
|
| 6 |
+
SUPABASE_URL = "https://hnrexbxxhdjksyllcmgg.supabase.co"
|
| 7 |
+
SUPABASE_KEY = "sb_publishable_t69puYMhsUaZ7GlYTXu6gQ_dg4pCHg5"
|
| 8 |
+
|
| 9 |
+
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 10 |
+
|
| 11 |
+
def test_ai_database():
|
| 12 |
+
print("Downloading AI tool (this takes a few seconds)...")
|
| 13 |
+
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
|
| 14 |
+
|
| 15 |
+
print("Converting text into numbers...")
|
| 16 |
+
# This turns English text into numbers so the database can search it later
|
| 17 |
+
embedding_numbers = model.encode("Farmers get 6000 rupees a year").tolist()
|
| 18 |
+
|
| 19 |
+
print("Saving to Supabase...")
|
| 20 |
+
data = {
|
| 21 |
+
"scheme_title": "Farmer Test Scheme",
|
| 22 |
+
"chunk_text": "Farmers get 6000 rupees a year",
|
| 23 |
+
"embedding": embedding_numbers,
|
| 24 |
+
"source_url": "test.com"
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
try:
|
| 28 |
+
supabase.table("document_chunks").insert(data).execute()
|
| 29 |
+
print("✅ SUCCESS! The data is saved in your database!")
|
| 30 |
+
except Exception as e:
|
| 31 |
+
print(f"❌ Error: {e}")
|
| 32 |
+
|
| 33 |
+
if __name__ == "__main__":
|
| 34 |
+
test_ai_database()
|
api.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from fastapi import FastAPI
|
| 3 |
+
from fastapi.responses import StreamingResponse
|
| 4 |
+
from pydantic import BaseModel
|
| 5 |
+
from sentence_transformers import SentenceTransformer
|
| 6 |
+
from supabase import create_client, Client
|
| 7 |
+
from groq import Groq
|
| 8 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 9 |
+
|
| 10 |
+
# --- 1. YOUR SECRET KEYS (SECURED) ---
|
| 11 |
+
SUPABASE_URL = os.environ.get("SUPABASE_URL")
|
| 12 |
+
SUPABASE_KEY = os.environ.get("SUPABASE_KEY")
|
| 13 |
+
GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
|
| 14 |
+
|
| 15 |
+
# --- 2. INITIALIZE CLIENTS ---
|
| 16 |
+
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 17 |
+
groq_client = Groq(api_key=GROQ_API_KEY)
|
| 18 |
+
|
| 19 |
+
app = FastAPI()
|
| 20 |
+
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
|
| 21 |
+
|
| 22 |
+
# Allow React to talk to this API
|
| 23 |
+
app.add_middleware(
|
| 24 |
+
CORSMiddleware,
|
| 25 |
+
allow_origins=["*"],
|
| 26 |
+
allow_credentials=True,
|
| 27 |
+
allow_methods=["*"],
|
| 28 |
+
allow_headers=["*"],
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
class SearchQuery(BaseModel):
|
| 32 |
+
question: str
|
| 33 |
+
|
| 34 |
+
# --- 3. THE TRUE RAG ENGINE ---
|
| 35 |
+
# Notice we changed the URL path to match Claude's blueprint!
|
| 36 |
+
@app.post("/api/rag/query")
|
| 37 |
+
async def rag_query(query: SearchQuery):
|
| 38 |
+
print(f"Citizen asked: {query.question}")
|
| 39 |
+
|
| 40 |
+
# STEP A: RETRIEVAL (Find the math matches)
|
| 41 |
+
query_numbers = model.encode(query.question).tolist()
|
| 42 |
+
result = supabase.rpc("match_documents", {
|
| 43 |
+
"query_embedding": query_numbers,
|
| 44 |
+
"match_count": 5
|
| 45 |
+
}).execute()
|
| 46 |
+
|
| 47 |
+
chunks = result.data
|
| 48 |
+
|
| 49 |
+
# STEP B: CONTEXT ASSEMBLY (Package the data for the AI to read)
|
| 50 |
+
if not chunks:
|
| 51 |
+
context = "No relevant schemes found in the database."
|
| 52 |
+
else:
|
| 53 |
+
context = "\n\n---\n\n".join([
|
| 54 |
+
f"[Document: {c.get('scheme_title', 'Unknown')}]\n{c.get('chunk_text', '')}"
|
| 55 |
+
for c in chunks
|
| 56 |
+
])
|
| 57 |
+
|
| 58 |
+
# STEP C: GENERATION (Ask Llama-3 to write a beautiful answer)
|
| 59 |
+
def stream_answer():
|
| 60 |
+
response = groq_client.chat.completions.create(
|
| 61 |
+
model="llama-3.3-70b-versatile",
|
| 62 |
+
messages=[
|
| 63 |
+
{"role": "system", "content":
|
| 64 |
+
"You are GovBridge AI, a helpful assistant for Indian citizens. "
|
| 65 |
+
"Answer the user's question using ONLY the provided context. "
|
| 66 |
+
"Always cite the official scheme names. If the context does not "
|
| 67 |
+
"contain the answer, clearly say 'This information is not available in our database.'"},
|
| 68 |
+
{"role": "user", "content": f"Context:\n{context}\n\nQuestion: {query.question}"}
|
| 69 |
+
],
|
| 70 |
+
temperature=0.1, # Low temperature means it stays highly factual!
|
| 71 |
+
max_tokens=1024,
|
| 72 |
+
stream=True
|
| 73 |
+
)
|
| 74 |
+
for chunk in response:
|
| 75 |
+
delta = chunk.choices[0].delta.content or ""
|
| 76 |
+
if delta:
|
| 77 |
+
yield delta
|
| 78 |
+
|
| 79 |
+
# Stream the text back to the website exactly like ChatGPT does!
|
| 80 |
+
return StreamingResponse(stream_answer(), media_type="text/plain")
|
ask_brain.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from sentence_transformers import SentenceTransformer
|
| 3 |
+
from supabase import create_client, Client
|
| 4 |
+
|
| 5 |
+
# 1. Put your real URL and Key inside the quotation marks below!
|
| 6 |
+
SUPABASE_URL = "https://hnrexbxxhdjksyllcmgg.supabase.co"
|
| 7 |
+
SUPABASE_KEY = "sb_publishable_t69puYMhsUaZ7GlYTXu6gQ_dg4pCHg5"
|
| 8 |
+
|
| 9 |
+
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 10 |
+
|
| 11 |
+
def ask_question():
|
| 12 |
+
print("Waking up the AI...")
|
| 13 |
+
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
|
| 14 |
+
|
| 15 |
+
# We are asking about a "kisan" (which we didn't save in the database)
|
| 16 |
+
user_question = "How can a kisan get financial help?"
|
| 17 |
+
print(f"\nQuestion: '{user_question}'")
|
| 18 |
+
|
| 19 |
+
print("Converting question into numbers...")
|
| 20 |
+
query_numbers = model.encode(user_question).tolist()
|
| 21 |
+
|
| 22 |
+
print("Searching Supabase...")
|
| 23 |
+
try:
|
| 24 |
+
# Ask Supabase to run the 'match_documents' SQL function
|
| 25 |
+
response = supabase.rpc("match_documents", {
|
| 26 |
+
"query_embedding": query_numbers,
|
| 27 |
+
"match_count": 1
|
| 28 |
+
}).execute()
|
| 29 |
+
|
| 30 |
+
matches = response.data
|
| 31 |
+
|
| 32 |
+
if matches:
|
| 33 |
+
best_match = matches[0]
|
| 34 |
+
print("\n✨ --- AI FOUND A MATCH! --- ✨")
|
| 35 |
+
print(f"Scheme: {best_match['scheme_title']}")
|
| 36 |
+
print(f"Details: {best_match['chunk_text']}")
|
| 37 |
+
print(f"Accuracy Score: {best_match['similarity']:.2f}")
|
| 38 |
+
else:
|
| 39 |
+
print("\n❌ No documents found.")
|
| 40 |
+
|
| 41 |
+
except Exception as e:
|
| 42 |
+
print(f"❌ Error: {e}")
|
| 43 |
+
|
| 44 |
+
if __name__ == "__main__":
|
| 45 |
+
ask_question()
|
render.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
- type: web
|
| 3 |
+
name: govbridge-api
|
| 4 |
+
runtime: python
|
| 5 |
+
buildCommand: pip install -r requirements.txt
|
| 6 |
+
startCommand: uvicorn api:app --host 0.0.0.0 --port $PORT
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
pydantic
|
| 4 |
+
sentence-transformers
|
| 5 |
+
supabase
|
| 6 |
+
groq
|