joe4ai commited on
Commit
acc65ac
·
verified ·
1 Parent(s): 0cfc8ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -31
app.py CHANGED
@@ -1,5 +1,6 @@
1
  from helper import download_hugging_face_embeddings
2
- from langchain_pinecone import PineconeVectorStore
 
3
  from langchain_community.llms import Ollama
4
  from langchain.chains import create_retrieval_chain
5
  from langchain.chains.combine_documents import create_stuff_documents_chain
@@ -7,36 +8,139 @@ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
7
  from langchain.chains import create_history_aware_retriever
8
  from langchain.memory import ChatMessageHistory
9
  from langchain_core.runnables.history import RunnableWithMessageHistory
 
 
10
  from dotenv import load_dotenv
11
  from prompt import system_prompt, retriever_prompt
12
  import os
13
  import logging
14
  import gradio as gr
 
 
15
  import uuid
 
16
 
17
- logging.getLogger().setLevel(logging.ERROR)
 
18
 
 
19
  base = {}
20
  last_messages = 4
 
21
 
22
  load_dotenv()
23
-
24
- PINECONE_API_KEY = os.environ.get('PINECONE_API_KEY')
25
  BASE_URL = os.environ.get('BASE_URL')
26
-
27
- os.environ['PINECONE_API_KEY'] = PINECONE_API_KEY
28
  os.environ['BASE_URL'] = BASE_URL
29
 
30
- index_name = 'humblebee'
 
 
 
31
 
32
- docsearch = PineconeVectorStore.from_existing_index(
33
- index_name=index_name,
34
- embedding=download_hugging_face_embeddings()
35
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  retriever = docsearch.as_retriever(search_type='similarity', search_kwargs={'k':2})
38
 
39
- llm = Ollama(model='llama3.2', base_url=BASE_URL )
40
 
41
  prompt = ChatPromptTemplate.from_messages(
42
  [
@@ -70,14 +174,14 @@ rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chai
70
  def get_session_history(session_id):
71
  if session_id not in base:
72
  base[session_id] = ChatMessageHistory()
73
-
74
  stored_msg = base[session_id].messages
75
- if len(stored_msg) >= 4:
76
  base[session_id].clear()
77
-
78
  for msg in stored_msg[-last_messages:]:
79
  base[session_id].add_message(msg)
80
-
81
  return base[session_id]
82
 
83
  chat_with_msg_history = RunnableWithMessageHistory(
@@ -87,25 +191,116 @@ chat_with_msg_history = RunnableWithMessageHistory(
87
  history_messages_key='chat_history'
88
  )
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  with gr.Blocks() as demo:
91
- state = gr.State("")
92
- chatbot = gr.Chatbot()
93
- msg = gr.Textbox()
94
- clear = gr.ClearButton([msg, chatbot])
 
 
 
 
 
 
 
95
 
 
 
 
 
 
96
 
97
- def get_response(message, chat_history, session_id):
98
- if not chat_history:
99
- session_id = uuid.uuid4().hex
 
100
 
101
- print(f"Session ID: {session_id}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- response = chat_with_msg_history.invoke(
104
- {'input': message},
105
- {'configurable': {'session_id': session_id}},
106
- )
107
 
108
- chat_history.append((message, response['answer']))
109
- return '', chat_history, session_id
110
- msg.submit(get_response, [msg, chatbot, state], [msg, chatbot, state])
111
  demo.launch(share=True)
 
1
  from helper import download_hugging_face_embeddings
2
+ from url import md_files_url
3
+ from get_data import extract_repo_details, fetch_md_file_via_api, data_loader, chunk_text
4
  from langchain_community.llms import Ollama
5
  from langchain.chains import create_retrieval_chain
6
  from langchain.chains.combine_documents import create_stuff_documents_chain
 
8
  from langchain.chains import create_history_aware_retriever
9
  from langchain.memory import ChatMessageHistory
10
  from langchain_core.runnables.history import RunnableWithMessageHistory
11
+ from langchain.vectorstores import FAISS
12
+ from langchain.schema import Document
13
  from dotenv import load_dotenv
14
  from prompt import system_prompt, retriever_prompt
15
  import os
16
  import logging
17
  import gradio as gr
18
+ import sqlite3
19
+ import bcrypt
20
  import uuid
21
+ from datetime import datetime
22
 
23
+ logging.basicConfig(level=logging.INFO)
24
+ logger = logging.getLogger(__name__)
25
 
26
+ DB_PATH = "chatbot.db"
27
  base = {}
28
  last_messages = 4
29
+ documents = []
30
 
31
  load_dotenv()
32
+ AUTH_TOKEN_KEY = os.environ.get('AUTH_TOKEN_KEY')
 
33
  BASE_URL = os.environ.get('BASE_URL')
34
+ os.environ['AUTH_TOKEN_KEY'] = AUTH_TOKEN_KEY
 
35
  os.environ['BASE_URL'] = BASE_URL
36
 
37
+ # ---- Database part ----- #
38
+ # Database Connection
39
+ def connect_db():
40
+ return sqlite3.connect(DB_PATH)
41
 
42
+ def create_tables():
43
+ with connect_db() as conn:
44
+ cursor = conn.cursor()
45
+ cursor.execute('''
46
+ CREATE TABLE IF NOT EXISTS users (
47
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
48
+ username TEXT UNIQUE NOT NULL,
49
+ password_hash TEXT NOT NULL
50
+ )''')
51
+ cursor.execute('''
52
+ CREATE TABLE IF NOT EXISTS chat_history (
53
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
54
+ user_id INTEGER NOT NULL,
55
+ message TEXT NOT NULL,
56
+ response TEXT NOT NULL,
57
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
58
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
59
+ )''')
60
+ conn.commit()
61
+
62
+ create_tables()
63
+ logger.info("Database tables created successfully!")
64
+
65
+ # Secure Password Hashing
66
+ def hash_password(password):
67
+ return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
68
+
69
+ def check_password(password, hashed):
70
+ return bcrypt.checkpw(password.encode(), hashed.encode())
71
+
72
+ # Authenticate User
73
+ def authenticate(username, password):
74
+ with connect_db() as conn:
75
+ cursor = conn.cursor()
76
+ cursor.execute("SELECT id, password_hash FROM users WHERE username = ?", (username,))
77
+ user = cursor.fetchone()
78
+
79
+ if user and check_password(password, user[1]):
80
+ session_id = uuid.uuid4().hex # Unique session ID
81
+ return session_id, f"Welcome {username}!", user[0] # user_id
82
+ return None, "Invalid username or password.", None
83
+
84
+ # Signup Function
85
+ def signup(username, password):
86
+ try:
87
+ hashed_pw = hash_password(password)
88
+ with connect_db() as conn:
89
+ cursor = conn.cursor()
90
+ cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)", (username, hashed_pw))
91
+ conn.commit()
92
+ return f"User {username} registered successfully! You can now log in."
93
+ except sqlite3.IntegrityError:
94
+ return "Username already exists. Try another one."
95
+
96
+ # Store Chat in Database
97
+ def save_chat(user_id, message, response):
98
+ with connect_db() as conn:
99
+ cursor = conn.cursor()
100
+ cursor.execute("INSERT INTO chat_history (user_id, message, response, created_at) VALUES (?, ?, ?, ?)",
101
+ (user_id, message, response, datetime.now()))
102
+ conn.commit()
103
+
104
+ # Retrieve Chat History (User-specific)
105
+ def get_chat_history(user_id):
106
+ with connect_db() as conn:
107
+ cursor = conn.cursor()
108
+ cursor.execute("SELECT message, response FROM chat_history WHERE user_id = ? ORDER BY created_at", (user_id,))
109
+ chat_history = cursor.fetchall()
110
+ return [(msg, resp) for msg, resp in chat_history]
111
+ # --------------------------------- #
112
+
113
+ #Option 2-load directly from urls
114
+ for url in md_files_url:
115
+ try:
116
+ repo_owner, repo_name, file_path = extract_repo_details(url)
117
+ content = fetch_md_file_via_api(repo_owner, repo_name, file_path, AUTH_TOKEN_KEY)
118
+ if content:
119
+ document = Document(page_content=content, metadata={"source": file_path})
120
+ documents.append(document)
121
+ except ValueError as ve:
122
+ logging.error(f"Error processing URL {url}: {ve}")
123
+ print(f"Fetched {len(documents)} documents.")
124
+
125
+ text_chunk = chunk_text(documents)
126
+ try:
127
+ faiss_index = FAISS.from_documents(text_chunk, download_hugging_face_embeddings())
128
+ faiss_index.save_local('faiss_index')
129
+ except Exception as e:
130
+ logging.error(f"Error creating or saving FAISS index: {e}")
131
+
132
+ try:
133
+ docsearch = FAISS.load_local(
134
+ 'faiss_index',
135
+ download_hugging_face_embeddings(),
136
+ allow_dangerous_deserialization=True
137
+ )
138
+ except Exception as e:
139
+ logging.error(f"Error loading FAISS index: {e}")
140
 
141
  retriever = docsearch.as_retriever(search_type='similarity', search_kwargs={'k':2})
142
 
143
+ llm = Ollama(model='llama3.2', base_url=BASE_URL)
144
 
145
  prompt = ChatPromptTemplate.from_messages(
146
  [
 
174
  def get_session_history(session_id):
175
  if session_id not in base:
176
  base[session_id] = ChatMessageHistory()
177
+
178
  stored_msg = base[session_id].messages
179
+ if len(stored_msg) >= last_messages:
180
  base[session_id].clear()
181
+
182
  for msg in stored_msg[-last_messages:]:
183
  base[session_id].add_message(msg)
184
+
185
  return base[session_id]
186
 
187
  chat_with_msg_history = RunnableWithMessageHistory(
 
191
  history_messages_key='chat_history'
192
  )
193
 
194
+ def get_response(message, chat_history, session_id, user_id):
195
+ if not session_id or not user_id:
196
+ return "Session expired. Please log in again.", []
197
+
198
+ chat_history = get_chat_history(user_id) # Load user's previous chat history
199
+
200
+ response = chat_with_msg_history.invoke(
201
+ {'input': message},
202
+ {'configurable': {'session_id': session_id}},
203
+ )
204
+
205
+ # 🔹 Log the response for debugging
206
+ print("LangChain Response:", response)
207
+
208
+ # 🔹 Ensure response contains 'answer' (adjust this if needed)
209
+ if isinstance(response, dict) and 'answer' in response:
210
+ chatbot_reply = response['answer']
211
+ else:
212
+ chatbot_reply = "I'm sorry, I couldn't process that request."
213
+
214
+ save_chat(user_id, message, chatbot_reply)
215
+
216
+ chat_history.append((message, chatbot_reply)) # Append instead of overwriting
217
+ return "", chat_history
218
+
219
+ # Logout Function
220
+ def logout(session_id):
221
+ if session_id in base:
222
+ del base[session_id] # Clear session history
223
+ return None, "Logged out successfully.", None
224
+
225
+ ## ... [Keep all previous code up to the Gradio UI section] ...
226
+ # Gradio UI
227
  with gr.Blocks() as demo:
228
+ gr.Markdown("## HumblebeeAI Customer Support Chatbot")
229
+
230
+ with gr.Row():
231
+ username = gr.Textbox(label="Username", interactive=True)
232
+ password = gr.Textbox(label="Password", type="password", interactive=True)
233
+ login_button = gr.Button("Login", interactive=False) # Initially disabled
234
+ signup_button = gr.Button("Signup", interactive=False) # Initially disabled
235
+
236
+ login_status = gr.Textbox(label="Status", interactive=False)
237
+ session_state = gr.State(None)
238
+ user_id_state = gr.State(None)
239
 
240
+ with gr.Column(visible=False) as chat_interface:
241
+ chatbot = gr.Chatbot()
242
+ msg = gr.Textbox(label="Message", placeholder="Ask me anything...")
243
+ send_button = gr.Button("Send")
244
+ logout_button = gr.Button("Logout")
245
 
246
+ # 🔹 Enable buttons only when both username & password are filled
247
+ def enable_buttons(username, password):
248
+ is_valid = bool(username.strip()) and bool(password.strip())
249
+ return gr.update(interactive=is_valid), gr.update(interactive=is_valid)
250
 
251
+ username.change(enable_buttons, [username, password], [login_button, signup_button])
252
+ password.change(enable_buttons, [username, password], [login_button, signup_button])
253
+
254
+ # 🔹 Login Logic (Clears Username & Password)
255
+ def login_user(username, password):
256
+ session_id, message, user_id = authenticate(username, password)
257
+ if session_id:
258
+ return session_id, user_id, message, "", "", get_chat_history(user_id), gr.update(visible=True)
259
+ return None, None, message, username, password, [], gr.update(visible=False)
260
+
261
+ login_button.click(
262
+ login_user,
263
+ [username, password],
264
+ [session_state, user_id_state, login_status, username, password, chatbot, chat_interface]
265
+ )
266
+
267
+ # 🔹 Signup Logic (Clears Username & Password)
268
+ def signup_user(username, password):
269
+ message = signup(username, password)
270
+ return message, "", ""
271
+
272
+ signup_button.click(
273
+ signup_user,
274
+ [username, password],
275
+ [login_status, username, password]
276
+ )
277
+
278
+ # 🔹 Sending Messages
279
+ send_button.click(
280
+ get_response,
281
+ [msg, chatbot, session_state, user_id_state],
282
+ [msg, chatbot]
283
+ )
284
+
285
+ msg.submit(
286
+ get_response,
287
+ [msg, chatbot, session_state, user_id_state],
288
+ [msg, chatbot]
289
+ )
290
+
291
+ # 🔹 Logout Logic (Clears Chat and Resets UI)
292
+ def logout_user():
293
+ return None, "", "", [], gr.update(visible=False)
294
+
295
+ # 🔹 Logout Function (Clears Status, Session, and Chat History)
296
+ def logout_user():
297
+ return None, "", "", "", [], gr.update(visible=False)
298
+
299
+ logout_button.click(
300
+ logout_user,
301
+ None,
302
+ [session_state, username, password, login_status, chatbot, chat_interface]
303
+ )
304
 
 
 
 
 
305
 
 
 
 
306
  demo.launch(share=True)