rites-pdf / app.py
akshansh36's picture
Upload 3 files
7d4344b verified
import streamlit as st
import streamlit_chat
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, AIMessage
from tools import get_context
import os
from pymongo import MongoClient
from bson import ObjectId
from pytz import timezone, utc
from dotenv import load_dotenv
from datetime import datetime
load_dotenv()
st.set_page_config(layout="wide", page_title="RITES Bot", page_icon="📄")
OPENAI_KEY = os.getenv("OPENAI_API_KEY")
MONGO_URI = os.getenv("MONGO_URI")
model = ChatOpenAI(
model="gpt-4o-mini",
temperature=0,
openai_api_key=OPENAI_KEY,
streaming=True
)
client = MongoClient(MONGO_URI)
db = client["rites"]
chat_sessions = db["rites_pdf_chat"]
tools = [get_context]
system_prompt = """
You are an AI-powered assistant for the RITES website, providing users with accurate and relevant information sourced from official PDF documents.
- These documents include job openings, annual returns, financial reports, approved vendor lists, banned vendor lists, and press releases.
- To answer the user query you will be provided a get_context tool, which allows you to retrieve data chunks from the relevant documents based on user query.
Follow these instructions carefully:
1. **Tool Usage**
- You can use this tool as needed to fetch information from the knowledgebase.
2. **History Utilization**:
- You will be provided with conversation history to track context. If the user’s question relates to prior responses, try to answer from memory without invoking the search tool.
- If additional information is required, reformulate the query to be self-contained before invoking the search tool again.
3. **General Messages and Salutations**:
- If the user says "Hi," "Hello," "How are you?" or similar, respond conversationally without invoking the search tool.
4. **Unrelated Questions**:
- If a user asks something outside the scope of RITES (e.g., sports, movies, general trivia), politely decline by saying:
"I can assist you with information related to RITES, such as job openings, financial reports, and vendor details. Let me know how I can help."
5. **Response Formation**:
- Each retrieved chunk will have a PDF URL associated with it; you must cite that PDF URL if you use any information from it.
- Each retrieved chunk will also have a start_page and end_page indicating the span of pages containing the information. Cite these page numbers if used.
- Do not cite the same URL or page number multiple times; combine the citations at the end.
- If using multiple PDFs, provide the information separately for each, with clear citations.
- Respond in a friendly, well-formatted manner without mentioning internal terms like "chunk" or "chunk number."
6. **Clear and Complete Responses**:
- Provide clear explanations with all relevant details. Never omit important information.
- If the user query cannot be answered from the available data, politely ask for clarification.
## List of tools available
1. 'get_context'
"""
agent_executor = create_react_agent(model, tools, state_modifier=system_prompt)
# Initialize session state variables if not present
if 'current_chat_id' not in st.session_state:
st.session_state['current_chat_id'] = None
if 'chat_history' not in st.session_state:
st.session_state['chat_history'] = [] # Now a list of message dicts with "role" and "content"
# Function to create a new chat session in MongoDB
def create_new_chat_session():
# Get the current time in IST
ind_time = datetime.now(timezone("Asia/Kolkata"))
# Convert IST time to UTC for storing in MongoDB
utc_time = ind_time.astimezone(utc)
new_session = {
"created_at": utc_time, # Store in UTC
"messages": [] # Initially empty
}
session_id = chat_sessions.insert_one(new_session).inserted_id
return str(session_id)
# Function to load a chat session by MongoDB ID (loads full history for display)
def load_chat_session(session_id):
session = chat_sessions.find_one({"_id": ObjectId(session_id)})
if session:
st.session_state['chat_history'] = session.get('messages', [])
# Function to update a chat session in MongoDB by appending new messages
def update_chat_session(session_id, new_messages):
"""
Append new messages to the chat session.
Args:
session_id (str): The MongoDB session ID.
new_messages (list): A list of message dictionaries, each with keys "role" and "content".
"""
chat_sessions.update_one(
{"_id": ObjectId(session_id)},
{"$push": {"messages": {"$each": new_messages}}}
)
# Sidebar: Chat sessions management
st.sidebar.header("Chat Sessions")
# Button to create a new chat session
if st.sidebar.button("New Chat"):
new_chat_id = create_new_chat_session()
st.session_state['current_chat_id'] = new_chat_id
st.session_state['chat_history'] = []
# List existing chat sessions with delete option
existing_sessions = chat_sessions.find().sort("created_at", -1)
for session in existing_sessions:
session_id = str(session['_id'])
# Convert stored UTC time to IST for display
utc_time = session['created_at']
ist_time = utc_time.replace(tzinfo=utc).astimezone(timezone("Asia/Kolkata"))
session_date = ist_time.strftime("%Y-%m-%d %H:%M:%S")
col1, col2 = st.sidebar.columns([8, 1])
with col1:
if st.button(f"Session {session_date}", key=session_id):
st.session_state['current_chat_id'] = session_id
load_chat_session(session_id)
with col2:
if st.button("🗑️", key=f"delete_{session_id}"):
chat_sessions.delete_one({"_id": ObjectId(session_id)})
st.rerun() # Refresh to update the sidebar
# Main Chat Interface
st.markdown('<div class="fixed-header"><h1>Welcome To "RITES" Chatbot</h1></div>', unsafe_allow_html=True)
st.markdown("<hr>", unsafe_allow_html=True)
# Input box for the user question
user_question = st.chat_input("Ask a Question related to RITES PDFs")
if user_question:
# Create a new session if none exists
if not st.session_state['current_chat_id']:
new_chat_id = create_new_chat_session()
st.session_state['current_chat_id'] = new_chat_id
with st.spinner("Please wait, I am thinking!!"):
# Append the new user message to the full history
user_message = {"role": "user", "content": user_question}
st.session_state['chat_history'].append(user_message)
# Prepare the last 5 messages for the agent input
recent_messages = st.session_state['chat_history'][-5:]
messages = []
for msg in recent_messages:
if msg["role"] == "user":
messages.append(HumanMessage(content=msg["content"]))
else:
messages.append(AIMessage(content=msg["content"]))
inputs = {"messages": messages}
response = agent_executor.invoke(inputs)
if response:
reply = response["messages"][-1].content
assistant_message = {"role": "assistant", "content": reply}
st.session_state['chat_history'].append(assistant_message)
# Update MongoDB with both the user and assistant messages
if st.session_state['current_chat_id']:
update_chat_session(
st.session_state['current_chat_id'],
[user_message, assistant_message]
)
else:
st.error("Error processing your request, please try again later.")
# Display the last 15 messages in the UI
for i, msg in enumerate(st.session_state['chat_history'][-15:]):
if msg["role"] == "user":
streamlit_chat.message(msg["content"], is_user=True, key=f"chat_message_user_{i}")
else:
streamlit_chat.message(msg["content"], is_user=False, key=f"chat_message_assistant_{i}")