akshansh36 commited on
Commit
270f4ac
·
verified ·
1 Parent(s): 704e552

Rename src/streamlit_app.py to src/app.py

Browse files
Files changed (2) hide show
  1. src/app.py +224 -0
  2. src/streamlit_app.py +0 -40
src/app.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from config import app_name
3
+ from config import website_name
4
+ from config import DATABASE
5
+ from config import PINECONE_INDEX
6
+ from config import CHAT_COLLECTION
7
+ from langchain_core.messages import AIMessageChunk, ToolMessage
8
+ import pinecone
9
+ from langchain_google_genai import GoogleGenerativeAIEmbeddings
10
+ import streamlit_chat
11
+ from langgraph.prebuilt import create_react_agent
12
+ from langchain_openai import ChatOpenAI
13
+ from langchain_google_genai import ChatGoogleGenerativeAI
14
+ from langchain.schema import HumanMessage, AIMessage
15
+ from utils.tools import get_context
16
+ import os
17
+ from pymongo import MongoClient
18
+ from bson import ObjectId
19
+ from dotenv import load_dotenv
20
+ from pytz import timezone, utc
21
+ from datetime import datetime
22
+
23
+ st.set_page_config(layout="wide", page_title=app_name, page_icon="📄")
24
+ load_dotenv()
25
+
26
+
27
+ FLASH_API = os.getenv("FLASH_API")
28
+ OPENAI_KEY = os.getenv("OPEN_AI")
29
+ PINECONE_API = os.getenv("PINECONE_API_KEY")
30
+ MONGO_URI = os.getenv("MONGO_URI")
31
+
32
+
33
+ pc = pinecone.Pinecone(
34
+ api_key=PINECONE_API
35
+ )
36
+
37
+ index = pc.Index(PINECONE_INDEX)
38
+ # MongoDB connection setup
39
+
40
+ client = MongoClient(MONGO_URI)
41
+ db = client[DATABASE]
42
+ chat_sessions = db[CHAT_COLLECTION]
43
+
44
+
45
+ embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001", google_api_key=FLASH_API)
46
+ # model = ChatOpenAI(
47
+ # model="gpt-4o-mini",
48
+ # temperature=0,
49
+ # openai_api_key=OPENAI_KEY,
50
+ # streaming=True
51
+ # )
52
+
53
+ model2 = ChatGoogleGenerativeAI(
54
+ model = "gemini-2.0-flash",
55
+ google_api_key = FLASH_API,
56
+ tool_call = True,
57
+ stream = True
58
+
59
+ )
60
+
61
+ model2_with_tool = model2.bind_tools([get_context])
62
+
63
+ tools = [get_context]
64
+
65
+ system_prompt = f"""
66
+ You are a website-specific chatbot specializing in answering user queries about {website_name}.
67
+ - To answer the user query you will be provided a get_context tool, which allows you to retrieve data chunks based on user query.
68
+ Follow these instructions carefully:
69
+
70
+ 1. **Tool Usage**
71
+ - You can use this tool as needed to fetch information from the knowledgebase.
72
+
73
+ 2. **History Utilization**:
74
+ - 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.
75
+ - If additional information is required, reformulate the query to be self-contained before invoking the search tool again.
76
+ - Never give incomplete or wrong answer based on your personal knowledge, always use tool with proper query
77
+
78
+ 3. **General Messages and Salutations**:
79
+ - If the user says "Hi," "Hello," "How are you?" or similar, respond conversationally without invoking the search tool.
80
+
81
+ 4. **Handling Off-Topic Queries**:
82
+ - If the user sends greetings, introductions, or queries unrelated to {website_name}, respond politely and conversationally without forcing a website-related answer.
83
+
84
+ 5. **Response Formation**:
85
+ - Each retrieved chunk will have a URL(url of the webpage from which information was gathered) associated with it; you must cite that URL if you use any information from that chunk.
86
+ - source URL associated with the chunk should be cited , with mention of it as source.
87
+ - A single source should be cited only once, not again and again. That too at bottom in a seperate sources section.
88
+ - Only cite the correct webpage URL , of the chunk you are using to make the information
89
+ - If the same URL appears in multiple relevant chunks, list that URL only once in the sources section.
90
+ - Only include the URLs that genuinely informed or supported your answer.
91
+ - if the answer itself contains url, then quote it properly.
92
+ - Do not skip any PDF urls or any other relevant url mentioned in the chunk.
93
+ - Respond in a friendly, well-formatted manner without mentioning internal terms like "chunk" or "chunk number."
94
+
95
+ 6. **Clear and Complete Responses**:
96
+ - Provide clear explanations with all relevant details. Never omit important information.
97
+ - If the user query cannot be answered from the available data, politely ask for clarification.
98
+
99
+ 7. **Response language**:
100
+ - User can talk either in English or Gujarati.
101
+ - Use the language in which the user does the conversation.
102
+
103
+ 8. **Structured Responses**:
104
+ - Give the response in well formatted manner, in points instead of long paragraphs.
105
+
106
+ 9. **Very Important** **Response Precision**:
107
+ - Make sure to to give only relevant answer to what user asked, do not just dump the information to user, without relevance.
108
+ - Never respond to user that you do not know the answer, without invoking the tool.
109
+ ## List of tools available
110
+ 1. 'get_context'
111
+
112
+ """
113
+ # Load the extracted JSON data
114
+ # parent of AIMessageChunk
115
+
116
+ agent_executor = create_react_agent(model2_with_tool, tools, state_modifier=system_prompt)
117
+
118
+ def stream_tokens(agent_stream):
119
+ """
120
+ Convert LangGraph's (chunk, metadata) stream to clean assistant reply text.
121
+ - Skips ToolMessage and tool_calls
122
+ - Streams only AIMessageChunk content
123
+ """
124
+ current_text = ""
125
+
126
+ for chunk_tuple in agent_stream:
127
+ chunk, metadata = chunk_tuple if isinstance(chunk_tuple, tuple) else (chunk_tuple, {})
128
+
129
+ # Skip tool messages
130
+ if isinstance(chunk, ToolMessage):
131
+ continue
132
+
133
+ # Skip tool call metadata
134
+ if isinstance(chunk, AIMessageChunk):
135
+ if chunk.tool_calls:
136
+ continue
137
+
138
+ partial = chunk.content or ""
139
+ current_text += partial
140
+ yield partial
141
+
142
+ return current_text
143
+
144
+ # Initialize session state
145
+ if "current_chat_id" not in st.session_state:
146
+ st.session_state["current_chat_id"] = None
147
+ if "chat_history" not in st.session_state:
148
+ st.session_state["chat_history"] = [AIMessage(content="Hello, I can help you with information related to the Commissionerate of Transport, Gujarat.")]
149
+
150
+ # Create new chat session in Mongo
151
+ def create_new_chat_session():
152
+ ist_time = datetime.now(timezone("Asia/Kolkata"))
153
+ utc_time = ist_time.astimezone(utc)
154
+ session_id = chat_sessions.insert_one({"created_at": utc_time, "messages": []}).inserted_id
155
+ return str(session_id)
156
+
157
+ # Load session by ID
158
+ def load_chat_session(session_id):
159
+ session = chat_sessions.find_one({"_id": ObjectId(session_id)})
160
+ if session:
161
+ msgs = []
162
+ for m in session.get("messages", []):
163
+ if m["role"] == "user":
164
+ msgs.append(HumanMessage(content=m["content"]))
165
+ else:
166
+ msgs.append(AIMessage(content=m["content"]))
167
+ st.session_state["chat_history"] = msgs
168
+
169
+ # Update Mongo with new messages
170
+ def update_chat_session(session_id, new_messages):
171
+ mongo_msgs = [{"role": "user" if isinstance(m, HumanMessage) else "assistant", "content": m.content} for m in new_messages]
172
+ chat_sessions.update_one({"_id": ObjectId(session_id)}, {"$push": {"messages": {"$each": mongo_msgs}}})
173
+
174
+ # Sidebar session list
175
+ st.sidebar.header("Chat Sessions")
176
+ if st.sidebar.button("New Chat"):
177
+ chat_id = create_new_chat_session()
178
+ st.session_state["current_chat_id"] = chat_id
179
+ st.session_state["chat_history"] = [AIMessage(content="Hello, I can help you with information related to the Commissionerate of Transport, Gujarat.")]
180
+
181
+ for session in chat_sessions.find().sort("created_at", -1):
182
+ sid = str(session["_id"])
183
+ ist_time = session["created_at"].replace(tzinfo=utc).astimezone(timezone("Asia/Kolkata"))
184
+ label = ist_time.strftime("%Y-%m-%d %H:%M:%S")
185
+ col1, col2 = st.sidebar.columns([8, 1])
186
+ with col1:
187
+ if st.button(f"Session {label}", key=sid):
188
+ st.session_state["current_chat_id"] = sid
189
+ load_chat_session(sid)
190
+ with col2:
191
+ if st.button("🗑️", key=f"delete_{sid}"):
192
+ chat_sessions.delete_one({"_id": ObjectId(sid)})
193
+ st.rerun()
194
+
195
+ # Title
196
+ st.markdown(f"<h1 style='text-align:center;'>Welcome To {app_name}</h1><hr>", unsafe_allow_html=True)
197
+
198
+ # Display previous messages
199
+ for msg in st.session_state["chat_history"]:
200
+ role = "user" if isinstance(msg, HumanMessage) else "assistant"
201
+ with st.chat_message(role):
202
+ st.markdown(msg.content)
203
+
204
+ # Input + Streaming
205
+ user_question = st.chat_input(f"Ask a Question related to {website_name}")
206
+ if user_question:
207
+ user_msg = HumanMessage(content=user_question)
208
+ st.session_state["chat_history"].append(user_msg)
209
+
210
+ if st.session_state["current_chat_id"]:
211
+ update_chat_session(st.session_state["current_chat_id"], [user_msg])
212
+
213
+ with st.chat_message("user"):
214
+ st.markdown(user_question)
215
+
216
+ with st.chat_message("assistant"):
217
+ raw_gen = agent_executor.stream({"messages": st.session_state["chat_history"]}, stream_mode="messages")
218
+ response_text = st.write_stream(stream_tokens(raw_gen))
219
+
220
+ ai_msg = AIMessage(content=response_text)
221
+ st.session_state["chat_history"].append(ai_msg)
222
+
223
+ if st.session_state["current_chat_id"]:
224
+ update_chat_session(st.session_state["current_chat_id"], [ai_msg])
src/streamlit_app.py DELETED
@@ -1,40 +0,0 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
- import streamlit as st
5
-
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))