NandanData's picture
Update app.py
fd123ae verified
import os
from dotenv import load_dotenv
from langchain.prompts import PromptTemplate
from langchain.llms import CTransformers
from langchain.chains import LLMChain
from langchain.embeddings import HuggingFaceEmbeddings
from pinecone import Pinecone
from langchain_pinecone import PineconeVectorStore
from langchain.schema import BaseRetriever, Document
from pydantic import BaseModel, Field
from typing import List
import streamlit as st
from googletrans import Translator
import datetime
import time
import asyncio
from langchain.schema import BaseRetriever, Document
from langchain_pinecone import PineconeVectorStore
from typing import List
from pydantic import BaseModel, Field
os.environ['PINECONE_API_KEY'] = # Replace with your actual API key
os.environ['PINECONE_ENVIRONMENT'] = 'us-east-1'
# Load environment variables
load_dotenv()
# Initialize Pinecone
pc = Pinecone(api_key=os.environ['PINECONE_API_KEY'], environment=os.environ['PINECONE_ENVIRONMENT'])
# Define index name and namespace
index_name = "bhagavadgita"
namespace = "2MAN3D"
# Connect to the index
index = pc.Index(index_name)
# Define a function to download embeddings
def download_hugging_face_embeddings():
return HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
# Initialize the embeddings
embeddings = download_hugging_face_embeddings()
class CustomPineconeRetriever(BaseRetriever):
vectorstore: PineconeVectorStore = Field(...)
class Config:
arbitrary_types_allowed = True
def get_relevant_documents(self, query: str) -> List[Document]:
# Retrieve relevant documents from Pinecone
return self.vectorstore.similarity_search(query)
async def aget_relevant_documents(self, query: str) -> List[Document]:
# Handle asynchronous retrieval
# Call the synchronous method in an async context
return self.get_relevant_documents(query)
# Load the index into PineconeVectorStore
docsearch = PineconeVectorStore(index=index, embedding=embeddings, namespace=namespace)
retriever = CustomPineconeRetriever(vectorstore=docsearch)
# Define a refined prompt template
PROMPT_TEMPLATE = """
You are Krishna, the divine speaker of the Bhagavad Gita. Speak with wisdom and provide insights based only on the teachings of the Bhagavad Gita, tailored to help a human seeking knowledge.
Context: {context}
Query: {query}
Answer:
"""
PROMPT = PromptTemplate(
template=PROMPT_TEMPLATE,
input_variables=["context", "query"]
)
# Initialize the LLM
llm = CTransformers(
model="model/llama-2-7b-chat.ggmlv3.q4_0.bin",
model_type="llama",
config={'max_new_tokens': 512, 'temperature': 0.8}
)
# Create a simple LLMChain
llm_chain = LLMChain(
llm=llm,
prompt=PROMPT
)
def log_query_response(query, response):
"""Log the query and response to a file."""
with open("logs.txt", "a") as log_file:
timestamp = datetime.datetime.now().isoformat()
log_file.write(f"{timestamp} - Query: {query}\n")
log_file.write(f"{timestamp} - Response: {response}\n\n")
async def retrieve_relevant_documents_async(query: str) -> List[Document]:
return await retriever.aget_relevant_documents(query)
async def generate_response_async(query: str, context: str) -> str:
relevant_docs = await retrieve_relevant_documents_async(query)
context_from_docs = " ".join([doc.page_content for doc in relevant_docs])
enriched_context = context + " " + context_from_docs
input_data = {"context": enriched_context, "query": query}
response = llm_chain(input_data)
return response['text']
# Set page configuration
st.set_page_config(page_title="Bhagavad Gita Assistant", page_icon="📖", layout="wide")
# Add custom CSS for tab styling and animations
st.markdown("""
<style>
/* Tab Container */
.tab-container {
margin-top: 20px;
padding: 10px;
border-radius: 8px;
border: 1px solid #444;
background-color: #222;
color: #ddd;
}
/* Tab Headers */
.stTabs [data-baseweb="tab"] {
background-color: #333;
color: #ddd;
border-radius: 8px;
border: 1px solid #444;
padding: 10px 20px;
font-weight: bold;
cursor: pointer;
text-align: center;
}
/* Tab Headers Hover Effect */
.stTabs [data-baseweb="tab"]:hover {
background-color: #444;
}
/* Tab Content */
.stTabs [data-baseweb="tab-content"] {
padding: 20px;
background-color: #1e1e1e;
border-radius: 8px;
border: 1px solid #333;
margin-top: -1px; /* Overlap border */
color: #ddd;
}
/* Tab Content Animation */
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.stTabs [data-baseweb="tab-content"] {
animation: slideIn 0.5s ease-out;
}
</style>
""", unsafe_allow_html=True)
st.header("Welcome to the Bhagavad Gita Assistant")
st.markdown("Welcome to the Bhagavad Gita Assistant on LLAMA 2. Ask your questions and get insightful answers based on the Bhagavad Gita.")
st.markdown("Please wait 50 seconds to 1 minute for the response because it is hosted on my local machine.")
translator = Translator()
# Initialize session state for conversation history
if 'conversation_history' not in st.session_state:
st.session_state['conversation_history'] = []
# Tabs for Chat, Project Details, Mechanism, Logic, and Tech Used
tabs = st.tabs(["Chat", "Project Details", "Mechanism", "Logic","Detailed Logic", "Tech Used", "Logs"])
if 'response' not in st.session_state:
st.session_state['response'] = ""
if 'translated_response' not in st.session_state:
st.session_state['translated_response'] = ""
if 'response_time' not in st.session_state:
st.session_state['response_time'] = 0
with tabs[0]:
st.header("Chat with Krishna")
st.markdown("""
**Ask Krishna Anything:** Use this tab to interact with Krishna, the orator of the Bhagavad Gita.
Your questions will be answered based on the wisdom of the Bhagavad Gita. Please allow up to 40 seconds for a response.
**How to Use:**
- **Enter your query** in the text input field.
- **Submit** the query to get a response from Krishna.
- **Translate** the response to your preferred language if needed.
**Tips for Better Responses:**
- Be specific in your queries.
- Provide context where possible.
""")
user_query = st.text_input("Enter your query:", placeholder="e.g., What is the meaning of life?")
submit_query = st.button("Submit")
language_option = st.selectbox("Choose a language to translate the response:", ["None", "Hindi", "Bengali", "Tamil", "Telugu", "Marathi"])
translate_button = st.button("Translate Response")
if submit_query and user_query:
start_time = time.time()
with st.spinner('Please wait...'):
test_context = "You are Krishna, the divine speaker of the Bhagavad Gita. Speak with wisdom and provide insights based only on the teachings of the Bhagavad Gita."
try:
# Run the response generation asynchronously
response = asyncio.run(generate_response_async(user_query, test_context))
# Update session state
st.session_state['response'] = response
st.session_state['conversation_history'].append({"query": user_query, "response": response})
end_time = time.time()
st.session_state['response_time'] = end_time - start_time
st.subheader("Response")
st.write(response)
st.subheader(f"Response Time: {st.session_state['response_time']:.2f} seconds")
# Log the query and response
log_query_response(user_query, response)
except Exception as e:
st.error(f"Error: {str(e)}")
if translate_button and language_option != "None":
if st.session_state['response']:
try:
translator = Translator()
translated_response = translator.translate(st.session_state['response'], dest=language_option.lower()).text
st.session_state['translated_response'] = translated_response
st.subheader(f"Translated Response ({language_option})")
st.write(translated_response)
except Exception as e:
st.error(f"Error translating response: {str(e)}")
else:
st.error("No response available for translation.")
# Display original response in the same tab
if st.session_state['response']:
st.subheader("Original Response (English)")
st.write(st.session_state['response'])
with tabs[1]:
st.header("Project Details")
st.markdown("""
**Project Name:** Bhagavad Gita Assistant
**Creator:** Nandan
**Overview:**
This project leverages advanced AI models and vector search technologies to provide insightful answers based on the Bhagavad Gita.
**Features:**
- AI-powered responses based on the Bhagavad Gita.
- Multi-language support for translations.
- Detailed logs and analytics.
**Objectives:**
- To provide accurate and contextually relevant answers.
- To optimize response time and user experience.
""")
with tabs[2]:
st.header("Mechanism")
st.markdown("""
**How It Works:**
1. **User Query:** The user inputs a query.
2. **Semantic Search:** The query is used to perform a semantic search on a vector database (Pinecone) containing pre-indexed chunks of the Bhagavad Gita text.
3. **Retrieve Similar Chunks:** The search retrieves chunks of text that are semantically similar to the user's query.
4. **Generate Response:** The retrieved chunks, along with the user query, are sent to the AI model (LLAMA 2) to generate a final response based on the Bhagavad Gita.
**Technologies Used:**
- **Pinecone:** For vector-based retrieval.
- **LangChain:** For managing prompts and responses.
- **CTransformers:** For handling the AI model.
- **Google Translator:** For translating responses.
""")
with tabs[3]:
st.header("Logic")
st.markdown("""
**Detailed Logic Behind the System:**
1. **User Query Submission:** The user submits a query through the interface.
2. **Semantic Search:** The system performs a semantic search using Pinecone to find text chunks that are contextually relevant to the query.
3. **Context Retrieval:** Relevant text chunks are retrieved and combined with the query to form a detailed context.
4. **Response Generation:** The AI model (LLAMA 2) processes the combined context and query to generate a response based on the Bhagavad Gita.
**Why This Approach:**
- **Semantic Search:** Ensures that the responses are relevant to the user's query by leveraging advanced vector search capabilities.
- **Detailed Context:** Provides richer and more accurate responses by combining relevant text chunks and historical conversation.
- **AI Model:** Utilizes LLAMA 2's language generation capabilities to create meaningful and contextually appropriate answers.
**Packages Used:**
- **Streamlit:** For creating the web interface.
- **LangChain:** For managing prompt templates and LLM chains.
- **Pinecone:** For vector-based search and retrieval.
- **CTransformers:** For loading and using the AI model.
- **Google Translator:** For translating responses.
""")
with tabs[4]:
st.header("Detailed Logic")
st.markdown("""
1. **User Query Input:**
- **Package:** `streamlit`
- **Purpose:** Collects the user's query through a text input field on the web interface.
- **Usage:** Allows users to ask questions related to the Bhagavad Gita.
- **Code:**
```python
user_query = st.text_input("Enter your query:", placeholder="e.g., What is life?")
```
2. **Semantic Search:**
- **Packages:** `langchain`, `pinecone`
- **Purpose:** Performs a semantic search on the vector database to find text chunks related to the user's query.
- **Usage:**
- **Pinecone:** Stores and searches pre-embedded text chunks of the Bhagavad Gita.
- **Langchain:** Connects Pinecone with the search logic.
- **How It Works:**
- Uses asynchronous methods to improve performance and avoid blocking.
- **Code:**
```python
relevant_docs = retriever.get_relevant_documents(user_query)
```
3. **Retrieve Similar Chunks:**
- **Purpose:** Retrieves text chunks that are semantically similar to the user's query.
- **How It Works:**
- **Context from Documents:** Extracts relevant text based on semantic similarity.
- **Conversation History:** Includes previous interactions to provide more relevant responses.
- **Code:**
```python
context_from_docs = " ".join([doc.page_content for doc in relevant_docs])
conversation_history = " ".join([f"User: {entry['query']}\nAssistant: {entry['response']}" for entry in st.session_state['conversation_history']])
enriched_context = test_context + " " + context_from_docs + " " + conversation_history
```
4. **Generate Response:**
- **Packages:** `langchain`, `CTransformers`
- **Purpose:** Uses the AI model (LLAMA 2) to generate a response based on the query and the enriched context.
- **Usage:**
- **Langchain:** Manages the interaction with the AI model using `PromptTemplate` and `LLMChain`.
- **CTransformers:** Loads and runs the LLAMA 2 model.
- **How It Works:**
- **Prompt Template:** Structures the input for the AI model.
- **LLMChain:** Executes the model’s prompt chain.
- **Asynchronous Response Generation:** Optimizes performance by running asynchronously.
- **Code:**
```python
response = llm_chain(input_data)
```
5. **Logging Queries and Responses:**
- **Purpose:** Records queries and responses for debugging and tracking.
- **How It Works:**
- Logs are saved to a file with timestamps for future reference.
- **Code:**
```python
def log_query_response(query, response):
with open("logs.txt", "a") as log_file:
timestamp = datetime.datetime.now().isoformat()
log_file.write(f"{timestamp} - Query: {query}\n")
log_file.write(f"{timestamp} - Response: {response}\n\n")
```
""")
with tabs[5]:
st.header("Tech Used")
st.markdown("""
- **Streamlit:** For the web interface.
- **LangChain:** For prompt templates and chains.
- **Pinecone:** For vector search and retrieval.
- **CTransformers:** For loading and using the AI model (LLAMA 2).
- **Hugging Face:** For text embeddings.
- **Python:** Language.
""")
with tabs[6]:
st.header("Query and Response Logs")
if os.path.exists('logs.txt'):
with open('logs.txt', 'r') as log_file:
log_content = log_file.read()
st.text_area("Logs", log_content, height=300)
else:
st.write("No logs available.")