MahatirTusher commited on
Commit
bd70104
·
verified ·
1 Parent(s): baf0aa7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +267 -269
app.py CHANGED
@@ -1,269 +1,267 @@
1
- ```python
2
- import streamlit as st
3
- st.set_page_config(page_title="LazyAss Reader AI", layout="wide") # MUST be first
4
-
5
- from langchain_core.messages import AIMessage, HumanMessage
6
- from langchain_community.document_loaders import WebBaseLoader
7
- from langchain.text_splitter import RecursiveCharacterTextSplitter
8
- from langchain_community.embeddings import HuggingFaceEmbeddings
9
- from langchain_community.vectorstores import FAISS
10
- from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
11
- from langchain.chains.combine_documents import create_stuff_documents_chain
12
- from langchain.chains import create_history_aware_retriever, create_retrieval_chain
13
- import requests
14
- import re
15
-
16
- # --- Configuration ---
17
- DEEPSEEK_API_KEY = "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"
18
- EMBEDDING_MODEL_NAME = "BAAI/bge-small-en-v1.5"
19
- DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
20
-
21
- # --- Custom CSS for Professional UI ---
22
- st.markdown("""
23
- <style>
24
- .main { background-color: #f9fafb; }
25
- .stSidebar { background-color: #ffffff; border-right: 1px solid #e5e7eb; }
26
- .stButton>button {
27
- background-color: #2563eb;
28
- color: white;
29
- border-radius: 8px;
30
- padding: 10px 20px;
31
- font-weight: 500;
32
- }
33
- .stButton>button:hover { background-color: #1d4ed8; }
34
- .stTextInput>div>input {
35
- border-radius: 8px;
36
- border: 1px solid #d1d5db;
37
- padding: 10px;
38
- }
39
- .chat-message {
40
- padding: 15px;
41
- border-radius: 8px;
42
- margin-bottom: 10px;
43
- }
44
- .human-message {
45
- background-color: #dbeafe;
46
- margin-left: 20%;
47
- text-align: right;
48
- }
49
- .ai-message {
50
- background-color: #f3f4f6;
51
- margin-right: 20%;
52
- }
53
- h1 { color: #1f2937; font-size: 2.5rem; }
54
- h2 { color: #374151; }
55
- .sidebar-text {
56
- color: #4b5563;
57
- font-size: 1rem;
58
- margin-top: 20px;
59
- font-family: 'Noto Sans Bengali', sans-serif;
60
- }
61
- .stRadio > label { margin-right: 20px; }
62
- </style>
63
- <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Bengali:wght@400;700&display=swap" rel="stylesheet">
64
- """, unsafe_allow_html=True)
65
-
66
- # --- Initialization ---
67
- @st.cache_resource
68
- def get_embedding_model():
69
- try:
70
- return HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)
71
- except Exception as e:
72
- st.error(f"🔴 Failed to load embedding model '{EMBEDDING_MODEL_NAME}': {e}")
73
- st.stop()
74
- embed_model = get_embedding_model()
75
-
76
- st.title("LazyAss Reader AI 💬")
77
-
78
- # Initialize session state
79
- if "chat_history" not in st.session_state:
80
- st.session_state.chat_history = [AIMessage(content="Hello! Please enter a website URL in the sidebar to begin. / হ্যালো! শুরু করতে সাইডবারে একটি ওয়েবসাইট URL লিখুন।")]
81
- if "vector_store" not in st.session_state:
82
- st.session_state.vector_store = None
83
- if "processed_url" not in st.session_state:
84
- st.session_state.processed_url = None
85
- if "documents" not in st.session_state:
86
- st.session_state.documents = None
87
-
88
- # --- Core Functions ---
89
- def detect_language(text):
90
- """Detect if the input text is Bengali or English."""
91
- bengali_regex = re.compile(r'[\u0980-\u09FF]')
92
- return "bn" if bengali_regex.search(text) else "en"
93
-
94
- def call_deepseek(prompt, language):
95
- """Call DeepSeek API for chat or summarization."""
96
- headers = {
97
- "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
98
- "Content-Type": "application/json"
99
- }
100
- payload = {
101
- "model": "deepseek-r1",
102
- "messages": [{"role": "user", "content": prompt}],
103
- "max_tokens": 500,
104
- "temperature": 0.7
105
- }
106
- try:
107
- response = requests.post(DEEPSEEK_API_URL, json=payload, headers=headers)
108
- response.raise_for_status()
109
- return response.json()["choices"][0]["message"]["content"].strip()
110
- except Exception as e:
111
- return "একটি ত্রুটি ঘটেছে।" if language == "bn" else f"Error: {str(e)}"
112
-
113
- def get_vector_store_from_url(url):
114
- """Process website and create FAISS vector store."""
115
- if not url:
116
- return None, "URL is empty."
117
- try:
118
- loader = WebBaseLoader(url)
119
- documents = loader.load()
120
- if not documents:
121
- return None, "Could not load any content from the URL."
122
-
123
- text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
124
- doc_chunks = text_splitter.split_documents(documents)
125
- if not doc_chunks:
126
- return None, "Loaded content but could not split it into chunks."
127
-
128
- vector_store = FAISS.from_documents(doc_chunks, embed_model)
129
- return vector_store, doc_chunks, None
130
- except Exception as e:
131
- return None, None, f"Failed to process URL '{url}': {str(e)}"
132
-
133
- def get_context_retriever_chain(vector_store):
134
- """Create a retriever chain using DeepSeek."""
135
- try:
136
- retriever = vector_store.as_retriever()
137
- prompt = ChatPromptTemplate.from_messages([
138
- MessagesPlaceholder(variable_name='chat_history'),
139
- ("user", "{input}"),
140
- ("user", "Given the above conversation, generate a search query to look up relevant information from the website content.")
141
- ])
142
- def invoke_deepseek(input_dict):
143
- language = detect_language(input_dict["input"])
144
- prompt_text = prompt.format(**input_dict)
145
- return {"context": call_deepseek(prompt_text, language)}
146
- return create_history_aware_retriever(invoke_deepseek, retriever, prompt)
147
- except Exception as e:
148
- st.error(f"🔴 Error creating retriever chain: {e}")
149
- return None
150
-
151
- def get_conversational_rag_chain(retriever_chain):
152
- """Create a conversational RAG chain using DeepSeek."""
153
- try:
154
- prompt = ChatPromptTemplate.from_messages([
155
- ("system", "You are an assistant for answering questions about a specific website. Use the provided context to answer in the user's language (Bengali or English). If the information is not in the context, state that you cannot answer based on the provided website content. Be concise and helpful.\n\nContext:\n{context}"),
156
- MessagesPlaceholder(variable_name='chat_history'),
157
- ('user', "{input}"),
158
- ])
159
- def invoke_deepseek(input_dict):
160
- language = detect_language(input_dict["input"])
161
- prompt_text = prompt.format(**input_dict)
162
- return {"answer": call_deepseek(prompt_text, language)}
163
- stuff_documents_chain = create_stuff_documents_chain(invoke_deepseek, prompt)
164
- return create_retrieval_chain(retriever_chain, stuff_documents_chain)
165
- except Exception as e:
166
- st.error(f"🔴 Error creating RAG chain: {e}")
167
- return None
168
-
169
- def get_response(user_input):
170
- """Get response from the RAG chain."""
171
- if st.session_state.vector_store is None:
172
- return "⚠️ Please submit a valid website URL first using the sidebar."
173
-
174
- retriever_chain = get_context_retriever_chain(st.session_state.vector_store)
175
- if not retriever_chain:
176
- return "🔴 Error: Could not create the retriever chain."
177
-
178
- conversation_rag_chain = get_conversational_rag_chain(retriever_chain)
179
- if not conversation_rag_chain:
180
- return "🔴 Error: Could not create the conversation chain."
181
-
182
- try:
183
- response = conversation_rag_chain.invoke({
184
- "chat_history": st.session_state.chat_history,
185
- "input": user_input
186
- })
187
- answer = response.get('answer', '').strip()
188
- refusals = [
189
- "I cannot answer based on the provided website content",
190
- "information is not in the context",
191
- "don't have information about that",
192
- ]
193
- is_refusal = not answer or any(refusal in answer.lower() for refusal in refusals)
194
- language = detect_language(user_input)
195
- return answer if answer and not is_refusal else (
196
- "আমি ওয়েবসাইটের তথ্যের উপর ভিত্তি করে আপনার প্রশ্নের উত্তর দিতে পারিনি।" if language == "bn"
197
- else "I couldn't find relevant information on the website to answer your question."
198
- )
199
- except Exception as e:
200
- language = detect_language(user_input)
201
- return "একটি ত্রুটি ঘটেছে।" if language == "bn" else f"🔴 Error processing your query: {str(e)}"
202
-
203
- def summarize_content(language):
204
- """Summarize website content in the chosen language."""
205
- if not st.session_state.documents:
206
- return "⚠️ No website content available to summarize."
207
- try:
208
- context = " ".join([doc.page_content for doc in st.session_state.documents])[:2000]
209
- prompt = f"Summarize the following website content in {'Bengali' if language == 'bn' else 'English'} in 100 words or less:\n\n{context}"
210
- return call_deepseek(prompt, language)
211
- except Exception as e:
212
- return "একটি ত্রুটি ঘটেছে।" if language == "bn" else f"Error: {str(e)}"
213
-
214
- # --- Streamlit UI ---
215
- with st.sidebar:
216
- st.header("Settings / সেটিংস")
217
- web_url = st.text_input("Enter Website URL / ওয়েবসাইট URL লিখুন", key="url_input")
218
- button_clicked = st.button("Load Website / ওয়েবসাইট লোড করুন", type="primary")
219
-
220
- if button_clicked:
221
- if not web_url:
222
- st.warning("Please enter a website URL. / অনুগ্রহ করে একটি ওয়েবসাইট URL লিখুন।")
223
- elif web_url != st.session_state.get("processed_url"):
224
- with st.spinner(f"Processing {web_url}..."):
225
- vector_store, documents, error_message = get_vector_store_from_url(web_url)
226
- if error_message:
227
- st.error(f"🔴 Failed: {error_message}")
228
- st.session_state.vector_store = None
229
- st.session_state.processed_url = None
230
- st.session_state.documents = None
231
- st.session_state.chat_history = [AIMessage(content="Failed to load the website. / ওয়েবসাইট লোড করতে ব্যর্থ।")]
232
- elif vector_store:
233
- st.session_state.vector_store = vector_store
234
- st.session_state.documents = documents
235
- st.session_state.processed_url = web_url
236
- st.session_state.chat_history = [AIMessage(content=f"Website '{web_url}' loaded! How can I help you? / ওয়েবসাইট '{web_url}' লোড হয়েছে! আমি কীভাবে সাহায্য করতে পারি?")]
237
- st.success("✅ Website loaded successfully! / ওয়েবসাইট সফলভাবে লোড হয়েছে!")
238
- st.rerun()
239
- else:
240
- st.info("This URL has already been loaded. / এই URL ইতিমধ্যে লোড করা হয়েছে।")
241
-
242
- st.markdown('<p class="sidebar-text">আপনি চাইলে বাংলায় প্রশ্নও করতে পারেন যেকোনো ইংরেজি দূর্বোধ্য সাইটের লেখাজোকা বুঝতে</p>', unsafe_allow_html=True)
243
-
244
- st.subheader("Chat History / চ্যাট ইতিহাস")
245
- for message in st.session_state.chat_history:
246
- with st.chat_message("AI" if isinstance(message, AIMessage) else "Human"):
247
- st.markdown(f'<div class="chat-message {"ai-message" if isinstance(message, AIMessage) else "human-message"}">{message.content}</div>', unsafe_allow_html=True)
248
-
249
- user_query = st.chat_input("Ask a question about the website... / ওয়েবসাইট সম্পর্কে একটি প্রশ্ন জিজ্ঞাসা করুন...")
250
- if user_query:
251
- st.session_state.chat_history.append(HumanMessage(content=user_query))
252
- with st.chat_message("Human"):
253
- st.markdown(f'<div class="chat-message human-message">{user_query}</div>', unsafe_allow_html=True)
254
-
255
- with st.spinner("Thinking... / চিন্তা করছে..."):
256
- response_content = get_response(user_query)
257
-
258
- st.session_state.chat_history.append(AIMessage(content=response_content))
259
- with st.chat_message("AI"):
260
- st.markdown(f'<div class="chat-message ai-message">{response_content}</div>', unsafe_allow_html=True)
261
-
262
- # --- Summarize Section ---
263
- st.subheader("Summarize Content / সামারি করুন")
264
- summary_lang = st.radio("Select summary language / সামারি ভাষা নির্বাচন করুন:", ["English", "বাংলা"], horizontal=True)
265
- if st.button("Summarize / সামারি করুন", type="primary"):
266
- with st.spinner("Summarizing... / সামারি করছে..."):
267
- summary = summarize_content("bn" if summary_lang == "বাংলা" else "en")
268
- st.markdown(f"**Summary / সামারি:** {summary}")
269
- ```
 
1
+ import streamlit as st
2
+ st.set_page_config(page_title="LazyAss Reader AI", layout="wide") # MUST be first
3
+
4
+ from langchain_core.messages import AIMessage, HumanMessage
5
+ from langchain_community.document_loaders import WebBaseLoader
6
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
7
+ from langchain_community.embeddings import HuggingFaceEmbeddings
8
+ from langchain_community.vectorstores import FAISS
9
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
10
+ from langchain.chains.combine_documents import create_stuff_documents_chain
11
+ from langchain.chains import create_history_aware_retriever, create_retrieval_chain
12
+ import requests
13
+ import re
14
+
15
+ # --- Configuration ---
16
+ DEEPSEEK_API_KEY = "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"
17
+ EMBEDDING_MODEL_NAME = "BAAI/bge-small-en-v1.5"
18
+ DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
19
+
20
+ # --- Custom CSS for Professional UI ---
21
+ st.markdown("""
22
+ <style>
23
+ .main { background-color: #f9fafb; }
24
+ .stSidebar { background-color: #ffffff; border-right: 1px solid #e5e7eb; }
25
+ .stButton>button {
26
+ background-color: #2563eb;
27
+ color: white;
28
+ border-radius: 8px;
29
+ padding: 10px 20px;
30
+ font-weight: 500;
31
+ }
32
+ .stButton>button:hover { background-color: #1d4ed8; }
33
+ .stTextInput>div>input {
34
+ border-radius: 8px;
35
+ border: 1px solid #d1d5db;
36
+ padding: 10px;
37
+ }
38
+ .chat-message {
39
+ padding: 15px;
40
+ border-radius: 8px;
41
+ margin-bottom: 10px;
42
+ }
43
+ .human-message {
44
+ background-color: #dbeafe;
45
+ margin-left: 20%;
46
+ text-align: right;
47
+ }
48
+ .ai-message {
49
+ background-color: #f3f4f6;
50
+ margin-right: 20%;
51
+ }
52
+ h1 { color: #1f2937; font-size: 2.5rem; }
53
+ h2 { color: #374151; }
54
+ .sidebar-text {
55
+ color: #4b5563;
56
+ font-size: 1rem;
57
+ margin-top: 20px;
58
+ font-family: 'Noto Sans Bengali', sans-serif;
59
+ }
60
+ .stRadio > label { margin-right: 20px; }
61
+ </style>
62
+ <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Bengali:wght@400;700&display=swap" rel="stylesheet">
63
+ """, unsafe_allow_html=True)
64
+
65
+ # --- Initialization ---
66
+ @st.cache_resource
67
+ def get_embedding_model():
68
+ try:
69
+ return HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)
70
+ except Exception as e:
71
+ st.error(f"🔴 Failed to load embedding model '{EMBEDDING_MODEL_NAME}': {e}")
72
+ st.stop()
73
+ embed_model = get_embedding_model()
74
+
75
+ st.title("LazyAss Reader AI 💬")
76
+
77
+ # Initialize session state
78
+ if "chat_history" not in st.session_state:
79
+ st.session_state.chat_history = [AIMessage(content="Hello! Please enter a website URL in the sidebar to begin. / হ্যালো! শুরু করতে সাইডবারে একটি ওয়েবসাইট URL লিখুন।")]
80
+ if "vector_store" not in st.session_state:
81
+ st.session_state.vector_store = None
82
+ if "processed_url" not in st.session_state:
83
+ st.session_state.processed_url = None
84
+ if "documents" not in st.session_state:
85
+ st.session_state.documents = None
86
+
87
+ # --- Core Functions ---
88
+ def detect_language(text):
89
+ """Detect if the input text is Bengali or English."""
90
+ bengali_regex = re.compile(r'[\u0980-\u09FF]')
91
+ return "bn" if bengali_regex.search(text) else "en"
92
+
93
+ def call_deepseek(prompt, language):
94
+ """Call DeepSeek API for chat or summarization."""
95
+ headers = {
96
+ "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
97
+ "Content-Type": "application/json"
98
+ }
99
+ payload = {
100
+ "model": "deepseek-r1",
101
+ "messages": [{"role": "user", "content": prompt}],
102
+ "max_tokens": 500,
103
+ "temperature": 0.7
104
+ }
105
+ try:
106
+ response = requests.post(DEEPSEEK_API_URL, json=payload, headers=headers)
107
+ response.raise_for_status()
108
+ return response.json()["choices"][0]["message"]["content"].strip()
109
+ except Exception as e:
110
+ return "একটি ত্রুটি ঘটেছে।" if language == "bn" else f"Error: {str(e)}"
111
+
112
+ def get_vector_store_from_url(url):
113
+ """Process website and create FAISS vector store."""
114
+ if not url:
115
+ return None, "URL is empty."
116
+ try:
117
+ loader = WebBaseLoader(url)
118
+ documents = loader.load()
119
+ if not documents:
120
+ return None, "Could not load any content from the URL."
121
+
122
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
123
+ doc_chunks = text_splitter.split_documents(documents)
124
+ if not doc_chunks:
125
+ return None, "Loaded content but could not split it into chunks."
126
+
127
+ vector_store = FAISS.from_documents(doc_chunks, embed_model)
128
+ return vector_store, doc_chunks, None
129
+ except Exception as e:
130
+ return None, None, f"Failed to process URL '{url}': {str(e)}"
131
+
132
+ def get_context_retriever_chain(vector_store):
133
+ """Create a retriever chain using DeepSeek."""
134
+ try:
135
+ retriever = vector_store.as_retriever()
136
+ prompt = ChatPromptTemplate.from_messages([
137
+ MessagesPlaceholder(variable_name='chat_history'),
138
+ ("user", "{input}"),
139
+ ("user", "Given the above conversation, generate a search query to look up relevant information from the website content.")
140
+ ])
141
+ def invoke_deepseek(input_dict):
142
+ language = detect_language(input_dict["input"])
143
+ prompt_text = prompt.format(**input_dict)
144
+ return {"context": call_deepseek(prompt_text, language)}
145
+ return create_history_aware_retriever(invoke_deepseek, retriever, prompt)
146
+ except Exception as e:
147
+ st.error(f"🔴 Error creating retriever chain: {e}")
148
+ return None
149
+
150
+ def get_conversational_rag_chain(retriever_chain):
151
+ """Create a conversational RAG chain using DeepSeek."""
152
+ try:
153
+ prompt = ChatPromptTemplate.from_messages([
154
+ ("system", "You are an assistant for answering questions about a specific website. Use the provided context to answer in the user's language (Bengali or English). If the information is not in the context, state that you cannot answer based on the provided website content. Be concise and helpful.\n\nContext:\n{context}"),
155
+ MessagesPlaceholder(variable_name='chat_history'),
156
+ ('user', "{input}"),
157
+ ])
158
+ def invoke_deepseek(input_dict):
159
+ language = detect_language(input_dict["input"])
160
+ prompt_text = prompt.format(**input_dict)
161
+ return {"answer": call_deepseek(prompt_text, language)}
162
+ stuff_documents_chain = create_stuff_documents_chain(invoke_deepseek, prompt)
163
+ return create_retrieval_chain(retriever_chain, stuff_documents_chain)
164
+ except Exception as e:
165
+ st.error(f"🔴 Error creating RAG chain: {e}")
166
+ return None
167
+
168
+ def get_response(user_input):
169
+ """Get response from the RAG chain."""
170
+ if st.session_state.vector_store is None:
171
+ return "⚠️ Please submit a valid website URL first using the sidebar."
172
+
173
+ retriever_chain = get_context_retriever_chain(st.session_state.vector_store)
174
+ if not retriever_chain:
175
+ return "🔴 Error: Could not create the retriever chain."
176
+
177
+ conversation_rag_chain = get_conversational_rag_chain(retriever_chain)
178
+ if not conversation_rag_chain:
179
+ return "🔴 Error: Could not create the conversation chain."
180
+
181
+ try:
182
+ response = conversation_rag_chain.invoke({
183
+ "chat_history": st.session_state.chat_history,
184
+ "input": user_input
185
+ })
186
+ answer = response.get('answer', '').strip()
187
+ refusals = [
188
+ "I cannot answer based on the provided website content",
189
+ "information is not in the context",
190
+ "don't have information about that",
191
+ ]
192
+ is_refusal = not answer or any(refusal in answer.lower() for refusal in refusals)
193
+ language = detect_language(user_input)
194
+ return answer if answer and not is_refusal else (
195
+ "আমি ওয়েবসাইটের তথ্যের উপর ভিত্তি করে আপনার প্রশ্নের উত্তর দিতে পারিনি।" if language == "bn"
196
+ else "I couldn't find relevant information on the website to answer your question."
197
+ )
198
+ except Exception as e:
199
+ language = detect_language(user_input)
200
+ return "একটি ত্রুটি ঘটেছে।" if language == "bn" else f"🔴 Error processing your query: {str(e)}"
201
+
202
+ def summarize_content(language):
203
+ """Summarize website content in the chosen language."""
204
+ if not st.session_state.documents:
205
+ return "⚠️ No website content available to summarize."
206
+ try:
207
+ context = " ".join([doc.page_content for doc in st.session_state.documents])[:2000]
208
+ prompt = f"Summarize the following website content in {'Bengali' if language == 'bn' else 'English'} in 100 words or less:\n\n{context}"
209
+ return call_deepseek(prompt, language)
210
+ except Exception as e:
211
+ return "একটি ত্রুটি ঘটেছে।" if language == "bn" else f"Error: {str(e)}"
212
+
213
+ # --- Streamlit UI ---
214
+ with st.sidebar:
215
+ st.header("Settings / সেটিংস")
216
+ web_url = st.text_input("Enter Website URL / ওয়েবসাইট URL লিখুন", key="url_input")
217
+ button_clicked = st.button("Load Website / ওয়েবসাইট লোড করুন", type="primary")
218
+
219
+ if button_clicked:
220
+ if not web_url:
221
+ st.warning("Please enter a website URL. / অনুগ্রহ করে একটি ওয়েবসাইট URL লিখুন।")
222
+ elif web_url != st.session_state.get("processed_url"):
223
+ with st.spinner(f"Processing {web_url}..."):
224
+ vector_store, documents, error_message = get_vector_store_from_url(web_url)
225
+ if error_message:
226
+ st.error(f"🔴 Failed: {error_message}")
227
+ st.session_state.vector_store = None
228
+ st.session_state.processed_url = None
229
+ st.session_state.documents = None
230
+ st.session_state.chat_history = [AIMessage(content="Failed to load the website. / ওয়েবসাইট লোড করতে ব্যর্থ।")]
231
+ elif vector_store:
232
+ st.session_state.vector_store = vector_store
233
+ st.session_state.documents = documents
234
+ st.session_state.processed_url = web_url
235
+ st.session_state.chat_history = [AIMessage(content=f"Website '{web_url}' loaded! How can I help you? / ওয়েবসাইট '{web_url}' লোড হয়েছে! আমি কীভাবে সাহায্য করতে পারি?")]
236
+ st.success("Website loaded successfully! / ওয়েবসাইট সফলভাবে লোড হয়েছে!")
237
+ st.rerun()
238
+ else:
239
+ st.info("This URL has already been loaded. / এই URL ইতিমধ্যে লোড করা হয়েছে।")
240
+
241
+ st.markdown('<p class="sidebar-text">আপনি চ���ইলে বাংলায় প্রশ্নও করতে পারেন যেকোনো ইংরেজি দূর্বোধ্য সাইটের লেখাজোকা বুঝতে</p>', unsafe_allow_html=True)
242
+
243
+ st.subheader("Chat History / চ্যাট ইতিহাস")
244
+ for message in st.session_state.chat_history:
245
+ with st.chat_message("AI" if isinstance(message, AIMessage) else "Human"):
246
+ st.markdown(f'<div class="chat-message {"ai-message" if isinstance(message, AIMessage) else "human-message"}">{message.content}</div>', unsafe_allow_html=True)
247
+
248
+ user_query = st.chat_input("Ask a question about the website... / ওয়েবসাইট সম্পর্কে একটি প্রশ্ন জিজ্ঞাসা করুন...")
249
+ if user_query:
250
+ st.session_state.chat_history.append(HumanMessage(content=user_query))
251
+ with st.chat_message("Human"):
252
+ st.markdown(f'<div class="chat-message human-message">{user_query}</div>', unsafe_allow_html=True)
253
+
254
+ with st.spinner("Thinking... / চিন্তা করছে..."):
255
+ response_content = get_response(user_query)
256
+
257
+ st.session_state.chat_history.append(AIMessage(content=response_content))
258
+ with st.chat_message("AI"):
259
+ st.markdown(f'<div class="chat-message ai-message">{response_content}</div>', unsafe_allow_html=True)
260
+
261
+ # --- Summarize Section ---
262
+ st.subheader("Summarize Content / সামারি করুন")
263
+ summary_lang = st.radio("Select summary language / সামারি ভাষা নির্বাচন করুন:", ["English", "বাংলা"], horizontal=True)
264
+ if st.button("Summarize / সামারি করুন", type="primary"):
265
+ with st.spinner("Summarizing... / সামারি করছে..."):
266
+ summary = summarize_content("bn" if summary_lang == "বাংলা" else "en")
267
+ st.markdown(f"**Summary / সামারি:** {summary}")