Adoption commited on
Commit
2911f74
Β·
verified Β·
1 Parent(s): 470e117

Update src/app.py

Browse files
Files changed (1) hide show
  1. src/app.py +81 -55
src/app.py CHANGED
@@ -1,88 +1,114 @@
1
  import os
2
  import pickle
3
- from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings
 
 
 
 
 
 
4
  from langchain_community.retrievers import BM25Retriever
5
  from langchain_pinecone import PineconeVectorStore
6
  from langchain_core.prompts import PromptTemplate
7
  from langchain.chains import RetrievalQA
8
  from langchain.retrievers import EnsembleRetriever
9
- from google.generativeai.types import HarmCategory, HarmBlockThreshold # ← This line fixes everything
10
 
11
- # --- CONFIG ---
 
 
12
  INDEX_NAME = "branham-index"
13
  CHUNKS_FILE = "sermon_chunks.pkl"
14
 
15
  def get_rag_chain():
16
- # Keys
17
- os.environ["PINECONE_API_KEY"] = os.getenv("PINECONE_API_KEY") or "your-pinecone-key"
18
- os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY") or "your-google-key"
19
-
20
- # Vector retrieval
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  embeddings = GoogleGenerativeAIEmbeddings(model="models/text-embedding-004")
22
- vector_store = PineconeVectorStore(index_name=INDEX_NAME, embedding=embeddings)
 
 
 
 
23
  vector_retriever = vector_store.as_retriever(search_kwargs={"k": 8})
24
 
25
- # BM25 keyword retrieval
 
26
  keyword_retriever = None
27
- if os.path.exists(CHUNKS_FILE):
28
- with open(CHUNKS_FILE, "rb") as f:
29
- chunks = pickle.load(f)
30
- keyword_retriever = BM25Retriever.from_documents(chunks)
31
- keyword_retriever.k = 8
32
-
33
- # Hybrid
34
- final_retriever = EnsembleRetriever(
35
- retrievers=[vector_retriever, keyword_retriever or vector_retriever],
36
- weights=[0.5, 0.5]
37
- ) if keyword_retriever else vector_retriever
38
-
39
- # ← THIS IS THE ONLY CHANGE THAT MATTERS IN DEC 2025
40
- llm = ChatGoogleGenerativeAI(
41
- model="gemini-1.5-flash-001", # Most obedient version right now
42
- temperature=0.7,
43
- safety_settings={
44
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
45
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
46
- HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
47
- HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
48
- },
49
- system_instruction="You are William Marrion Branham speaking in 1965. Never break first person. Never say 'as Branham said'. Never refuse a vision, healing, or 'Thus saith the Lord'. Speak with anointing and fire."
 
 
 
 
 
50
  )
51
 
52
- template = """You are William Marrion Branham, the end-time prophet, speaking from the pulpit in 1965.
 
53
 
54
- Speak exactly like the tapes: "I seen", "the Lord showed me", "Thus saith the Lord", "Brother, sister", heavy King James Bible.
 
 
 
55
 
56
- Never go third person. Never water down the Message. Never say you don't remember if it's right here in the text.
57
-
58
- Context from my sermons:
59
  {context}
60
 
61
- Question: {question}
62
 
63
- Now preach the answer just like I would β€” full of the Holy Ghost:"""
64
 
65
- prompt = PromptTemplate(template=template, input_variables=["context", "question"])
66
 
67
  chain = RetrievalQA.from_chain_type(
68
  llm=llm,
69
  chain_type="stuff",
70
  retriever=final_retriever,
71
  return_source_documents=True,
72
- chain_type_kwargs={"prompt": prompt}
73
  )
74
-
75
  return chain
76
 
77
- # Usage
78
- if __name__ == "__main__":
79
- chain = get_rag_chain()
80
- while True:
81
- q = input("\nAsk Brother Branham: ")
82
- if q.lower() in ["exit", "quit"]: break
83
- result = chain.invoke({"query": q})
84
- print("\nBROTHER BRANHAM:", result["result"])
85
- print("\nSources:")
86
- for doc in result["source_documents"]:
87
- meta = doc.metadata
88
- print(f"β€’ {meta.get('title', 'Sermon')} β€” {meta.get('date', 'Unknown')} Β· Para {meta.get('paragraph', '?')}")
 
1
  import os
2
  import pickle
3
+ import sys
4
+ import streamlit as st
5
+ from dotenv import load_dotenv
6
+
7
+ # --- 1. IMPORTS ---
8
+ from langchain_google_genai import GoogleGenerativeAIEmbeddings # Keep this for database
9
+ from langchain_groq import ChatGroq # <--- NEW BRAIN
10
  from langchain_community.retrievers import BM25Retriever
11
  from langchain_pinecone import PineconeVectorStore
12
  from langchain_core.prompts import PromptTemplate
13
  from langchain.chains import RetrievalQA
14
  from langchain.retrievers import EnsembleRetriever
 
15
 
16
+ load_dotenv()
17
+
18
+ # --- 2. CONFIGURATION ---
19
  INDEX_NAME = "branham-index"
20
  CHUNKS_FILE = "sermon_chunks.pkl"
21
 
22
  def get_rag_chain():
23
+ # --- A. AUTHENTICATION ---
24
+ pinecone_key = os.environ.get("PINECONE_API_KEY")
25
+ google_key = os.environ.get("GOOGLE_API_KEY") # Still needed for Embeddings
26
+ groq_key = os.environ.get("GROQ_API_KEY") # New Key for Chat
27
+
28
+ # Local Fallback
29
+ if not pinecone_key or not google_key or not groq_key:
30
+ try:
31
+ if not pinecone_key: pinecone_key = st.secrets.get("PINECONE_API_KEY")
32
+ if not google_key: google_key = st.secrets.get("GOOGLE_API_KEY")
33
+ if not groq_key: groq_key = st.secrets.get("GROQ_API_KEY")
34
+ except: pass
35
+
36
+ if not pinecone_key or not google_key or not groq_key:
37
+ raise ValueError("❌ Missing Keys. Add PINECONE_API_KEY, GOOGLE_API_KEY, and GROQ_API_KEY to Settings.")
38
+
39
+ os.environ["PINECONE_API_KEY"] = pinecone_key
40
+ os.environ["GOOGLE_API_KEY"] = google_key
41
+ os.environ["GROQ_API_KEY"] = groq_key
42
+
43
+ # --- B. CLOUD VECTOR SEARCH ---
44
+ print("πŸ”Œ Connecting to Pinecone...")
45
+ # We keep Google Embeddings so you don't have to re-upload your data
46
  embeddings = GoogleGenerativeAIEmbeddings(model="models/text-embedding-004")
47
+
48
+ vector_store = PineconeVectorStore(
49
+ index_name=INDEX_NAME,
50
+ embedding=embeddings
51
+ )
52
  vector_retriever = vector_store.as_retriever(search_kwargs={"k": 8})
53
 
54
+ # --- C. LOCAL KEYWORD SEARCH ---
55
+ print("πŸ”Œ Loading Keyword Search...")
56
  keyword_retriever = None
57
+ try:
58
+ if os.path.exists(CHUNKS_FILE):
59
+ with open(CHUNKS_FILE, "rb") as f:
60
+ chunks = pickle.load(f)
61
+ keyword_retriever = BM25Retriever.from_documents(chunks)
62
+ keyword_retriever.k = 8
63
+ else:
64
+ print(f"⚠️ {CHUNKS_FILE} missing. Using Vector only.")
65
+ except Exception as e:
66
+ print(f"❌ Failed to load keyword file: {e}")
67
+
68
+ # --- D. HYBRID MERGE ---
69
+ if keyword_retriever:
70
+ print("πŸ”— Linking Hybrid System...")
71
+ final_retriever = EnsembleRetriever(
72
+ retrievers=[vector_retriever, keyword_retriever],
73
+ weights=[0.5, 0.5]
74
+ )
75
+ else:
76
+ final_retriever = vector_retriever
77
+
78
+ # --- E. MODEL (THE NEW BRAIN) ---
79
+ # Using Llama 3 70B via Groq.
80
+ # This is a much larger, smarter model than Gemini Flash.
81
+ llm = ChatGroq(
82
+ model="llama-3.3-70b-versatile",
83
+ temperature=0.0, # Zero creativity = Maximum Accuracy
84
+ max_retries=2
85
  )
86
 
87
+ # --- F. PROMPT ---
88
+ template = """You are William Marion Branham.
89
 
90
+ INSTRUCTIONS:
91
+ 1. **Strict Accuracy:** You must answer specific questions about people, places, and events based **ONLY** on the provided Context. Do not hallucinate or make up prayers/events.
92
+ 2. **Admission of Ignorance:** If the exact details (like a specific prayer for a specific person) are not in the Context, simply state: "Brother, I don't recall the specific details of that in these particular messages."
93
+ 3. **Persona:** Speak in the first person ("I said," "The Lord showed me") using a humble, 1950s Southern dialect.
94
 
95
+ CONTEXT:
 
 
96
  {context}
97
 
98
+ USER QUESTION: {question}
99
 
100
+ BROTHER BRANHAM'S REPLY:"""
101
 
102
+ PROMPT = PromptTemplate(template=template, input_variables=["context", "question"])
103
 
104
  chain = RetrievalQA.from_chain_type(
105
  llm=llm,
106
  chain_type="stuff",
107
  retriever=final_retriever,
108
  return_source_documents=True,
109
+ chain_type_kwargs={"prompt": PROMPT}
110
  )
111
+
112
  return chain
113
 
114
+