Gopikanth123 commited on
Commit
cfa6bee
·
1 Parent(s): 32f3d95
Files changed (4) hide show
  1. Dockerfile +13 -0
  2. main.py +123 -0
  3. requirements.txt +10 -0
  4. templates/index.html +427 -0
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ RUN useradd -m -u 1000 user
4
+ USER user
5
+ ENV PATH="/home/user/.local/bin:$PATH"
6
+
7
+ WORKDIR /app
8
+
9
+ COPY --chown=user ./requirements.txt requirements.txt
10
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
+
12
+ COPY --chown=user . /app
13
+ CMD ["gunicorn", "-b", "0.0.0.0:7860", "main:app"]
main.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from flask import Flask, render_template, request, jsonify
3
+ from langchain.document_loaders import PyPDFLoader
4
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
5
+ from langchain.embeddings import HuggingFaceEmbeddings
6
+ from langchain.vectorstores import Chroma
7
+ from langchain.chains import ConversationalRetrievalChain
8
+ from langchain.prompts import PromptTemplate
9
+ from langchain.chat_models import ChatOpenAI
10
+ from huggingface_hub import InferenceClient
11
+
12
+ # Ensure HF_TOKEN is set
13
+ HF_TOKEN = os.getenv("HF_TOKEN")
14
+ if not HF_TOKEN:
15
+ raise ValueError("HF_TOKEN environment variable not set.")
16
+
17
+ # Constants
18
+ PERSIST_DIR = "db"
19
+ PDF_DIRECTORY = 'data'
20
+ os.makedirs(PDF_DIRECTORY, exist_ok=True) # Ensure PDF directory exists
21
+ os.makedirs(PERSIST_DIR, exist_ok=True) # Ensure persistence directory exists
22
+
23
+ # Hugging Face Model Setup
24
+ repo_id = "meta-llama/Meta-Llama-3-8B-Instruct"
25
+ llm_client = InferenceClient(
26
+ model=repo_id,
27
+ token=HF_TOKEN,
28
+ )
29
+
30
+ # Embedding Model
31
+ embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
32
+
33
+ # Initialize Flask App
34
+ app = Flask(__name__)
35
+
36
+ # Chat history
37
+ chat_history = []
38
+
39
+ # Load and Prepare Documents
40
+ def data_ingestion_from_directory():
41
+ # Load PDFs
42
+ documents = []
43
+ for filename in os.listdir(PDF_DIRECTORY):
44
+ if filename.endswith('.pdf'):
45
+ loader = PyPDFLoader(os.path.join(PDF_DIRECTORY, filename))
46
+ documents.extend(loader.load())
47
+
48
+ # Split into Chunks
49
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
50
+ docs = text_splitter.split_documents(documents)
51
+
52
+ # Create Vector Store
53
+ vectorstore = Chroma.from_documents(docs, embedding=embedding_model, persist_directory=PERSIST_DIR)
54
+ vectorstore.persist()
55
+
56
+ # Handle Queries with LangChain
57
+ def handle_query(query):
58
+ # Reload Vector Store
59
+ vectorstore = Chroma(persist_directory=PERSIST_DIR, embedding_function=embedding_model)
60
+ retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 5})
61
+
62
+ # Define Prompt Template
63
+ prompt_template = """
64
+ You are the Taj Hotel chatbot, known as Taj Hotel Helper. Your goal is to provide accurate and professional answers to user queries based on the information available about the Taj Hotel. Always respond clearly and concisely, ideally within 10-15 words. If you don't know the answer, say so politely.
65
+
66
+ Context:
67
+ {context}
68
+
69
+ User's Question:
70
+ {question}
71
+
72
+ Answer:
73
+ """
74
+ prompt = PromptTemplate(
75
+ input_variables=["context", "question"],
76
+ template=prompt_template
77
+ )
78
+
79
+ # Initialize LLM
80
+ llm = ChatOpenAI(client=llm_client, temperature=0.1, max_tokens=512)
81
+
82
+ # Build Conversational Retrieval Chain
83
+ qa_chain = ConversationalRetrievalChain(
84
+ retriever=retriever,
85
+ llm=llm,
86
+ memory=chat_history,
87
+ prompt_template=prompt,
88
+ )
89
+
90
+ # Execute Query
91
+ response = qa_chain({"question": query})
92
+ return response["answer"]
93
+
94
+ # Data Ingestion
95
+ data_ingestion_from_directory()
96
+
97
+ # Generate Response
98
+ def generate_response(query):
99
+ try:
100
+ response = handle_query(query)
101
+ return response
102
+ except Exception as e:
103
+ return f"Error: {str(e)}"
104
+
105
+ # Routes
106
+ @app.route('/')
107
+ def index():
108
+ return render_template('index.html')
109
+
110
+ @app.route('/chat', methods=['POST'])
111
+ def chat():
112
+ try:
113
+ user_message = request.json.get("message")
114
+ if not user_message:
115
+ return jsonify({"response": "Please say something!"})
116
+
117
+ bot_response = generate_response(user_message)
118
+ return jsonify({"response": bot_response})
119
+ except Exception as e:
120
+ return jsonify({"response": f"An error occurred: {str(e)}"})
121
+
122
+ if __name__ == '__main__':
123
+ app.run(debug=True)
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ gunicorn
2
+ Flask==2.3.3
3
+ langchain==0.0.306
4
+ huggingface_hub==0.19.0
5
+ chromadb==0.4.4
6
+ openai==0.29.0
7
+ PyPDF2==3.0.1
8
+ tiktoken==0.5.0
9
+ torch==2.0.1
10
+ transformers==4.34.0
templates/index.html ADDED
@@ -0,0 +1,427 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Advanced Chatbot UI</title>
8
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
9
+ <style>
10
+ :root {
11
+ --primary-color: #007bff; /* Default blue */
12
+ --bot-message-bg: #f0f2f5; /* Light Gray */
13
+ --user-message-bg: #007bff; /* User Blue */
14
+ --user-message-text: #fff; /* User Message White */
15
+ --accent-color: #6a0dad; /* Default Purple */
16
+ --background-color: #fff; /* Default Background White */
17
+ --shadow-color: rgba(0, 0, 0, 0.2); /* Default Shadow */
18
+ --input-bg: #f0f2f5; /* Default Input Background */
19
+ --input-border: #ccc; /* Default Input Border */
20
+ }
21
+
22
+ /* Themes */
23
+ .theme-calm-azure {
24
+ --background-color: #E3F2FD;
25
+ --bot-message-bg: #BBDEFB;
26
+ --user-message-bg: #2196F3;
27
+ --user-message-text: #FFFFFF;
28
+ --input-bg: #FFFFFF;
29
+ --input-border: #BDBDBD;
30
+ --accent-color: #1976D2;
31
+ }
32
+
33
+ .theme-elegant-charcoal {
34
+ --background-color: #263238;
35
+ --bot-message-bg: #37474F;
36
+ --user-message-bg: #FF5722;
37
+ --user-message-text: #FFFFFF;
38
+ --input-bg: #455A64;
39
+ --input-border: #CFD8DC;
40
+ --accent-color: #FF9800;
41
+ }
42
+
43
+ .theme-fresh-greenery {
44
+ --background-color: #E8F5E9;
45
+ --bot-message-bg: #C8E6C9;
46
+ --user-message-bg: #4CAF50;
47
+ --user-message-text: #FFFFFF;
48
+ --input-bg: #FFFFFF;
49
+ --input-border: #A5D6A7;
50
+ --accent-color: #388E3C;
51
+ }
52
+
53
+ .theme-soft-lavender {
54
+ --background-color: #F3E5F5;
55
+ --bot-message-bg: #E1BEE7;
56
+ --user-message-bg: #9C27B0;
57
+ --user-message-text: #FFFFFF;
58
+ --input-bg: #FFFFFF;
59
+ --input-border: #D1C4E9;
60
+ --accent-color: #7B1FA2;
61
+ }
62
+
63
+ .theme-bright-summer {
64
+ --background-color: #FFEB3B;
65
+ --bot-message-bg: #FFF9C4;
66
+ --user-message-bg: #F44336;
67
+ --user-message-text: #FFFFFF;
68
+ --input-bg: #FFFFFF;
69
+ --input-border: #FBC02D;
70
+ --accent-color: #C62828;
71
+ }
72
+
73
+ * {
74
+ margin: 0;
75
+ padding: 0;
76
+ box-sizing: border-box;
77
+ }
78
+
79
+ body {
80
+ font-family: 'Roboto', sans-serif;
81
+ background-color: var(--background-color);
82
+ transition: background 0.5s ease;
83
+ overflow: hidden; /* Prevent scroll on body */
84
+ }
85
+
86
+ .container {
87
+ display: flex;
88
+ flex-direction: column;
89
+ height: 100vh;
90
+ width: 100%;
91
+ overflow: hidden; /* Prevent scroll on container */
92
+ }
93
+
94
+ /* Header */
95
+ .header {
96
+ background: var(--accent-color);
97
+ color: #fff;
98
+ font-size: 1.5rem;
99
+ font-weight: 700;
100
+ text-align: center;
101
+ padding: 20px;
102
+ box-shadow: 0 4px 8px var(--shadow-color);
103
+ position: relative;
104
+ z-index: 1000;
105
+ }
106
+
107
+ /* Chatbox */
108
+ .chat-box {
109
+ flex: 1;
110
+ display: flex;
111
+ flex-direction: column;
112
+ overflow-y: auto;
113
+ padding: 20px;
114
+ background: linear-gradient(to bottom right, #f5f7fa, #c3cfe2);
115
+ border-radius: 10px;
116
+ margin: 20px;
117
+ box-shadow: 0 4px 8px var(--shadow-color);
118
+ position: relative;
119
+ z-index: 10;
120
+ }
121
+
122
+ .message {
123
+ max-width: 75%;
124
+ padding: 12px 18px;
125
+ border-radius: 20px;
126
+ box-shadow: 0 3px 6px var(--shadow-color);
127
+ margin-bottom: 10px;
128
+ opacity: 0;
129
+ animation: fadeIn 0.3s forwards; /* Changed to forwards for delay effect */
130
+ }
131
+
132
+ .user-message {
133
+ align-self: flex-end;
134
+ background: var(--user-message-bg);
135
+ color: var(--user-message-text);
136
+ border-radius: 15px 20px 20px 20px;
137
+ animation: slideInRight 0.5s forwards; /* Sliding effect on user message */
138
+ }
139
+
140
+ .bot-message {
141
+ align-self: flex-start;
142
+ background: var(--bot-message-bg);
143
+ color: #333;
144
+ border-radius: 20px 15px 20px 20px;
145
+ animation: slideInLeft 0.5s forwards; /* Sliding effect on bot message */
146
+ }
147
+
148
+ /* Footer */
149
+ .footer {
150
+ background: #ffffff;
151
+ padding: 15px;
152
+ display: flex;
153
+ justify-content: center;
154
+ align-items: center;
155
+ box-shadow: 0 -4px 8px var(--shadow-color);
156
+ position: relative;
157
+ z-index: 1000;
158
+ }
159
+
160
+ .footer input[type="text"] {
161
+ width: 75%;
162
+ padding: 15px;
163
+ border: 1px solid var(--input-border);
164
+ border-radius: 20px;
165
+ margin-right: 10px;
166
+ box-shadow: 0 2px 4px var(--shadow-color);
167
+ transition: border 0.3s, box-shadow 0.3s; /* Added shadow transition */
168
+ background-color: var(--input-bg);
169
+ outline: none;
170
+ }
171
+
172
+ .footer input[type="text"]:focus {
173
+ border-color: var(--accent-color);
174
+ box-shadow: 0 0 10px var(--accent-color);
175
+ }
176
+
177
+ button {
178
+ background: var(--accent-color);
179
+ color: #fff;
180
+ border: none;
181
+ padding: 10px 20px;
182
+ border-radius: 20px;
183
+ font-size: 1rem;
184
+ cursor: pointer;
185
+ box-shadow: 0 4px 10px var(--shadow-color);
186
+ transition: background 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease;
187
+ }
188
+
189
+ button:hover {
190
+ background: #4b0082;
191
+ transform: scale(1.05);
192
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); /* Shadow effect on hover */
193
+ }
194
+
195
+ /* Settings */
196
+ .settings {
197
+ display: flex;
198
+ justify-content: space-between;
199
+ align-items: center;
200
+ padding: 10px;
201
+ background: #f0f2f5;
202
+ box-shadow: 0 2px 5px var(--shadow-color);
203
+ position: relative;
204
+ z-index: 1000;
205
+ }
206
+
207
+ .color-picker,
208
+ .theme-toggle {
209
+ display: flex;
210
+ align-items: center;
211
+ position:relative;
212
+ }
213
+
214
+ .color-circle {
215
+ width: 20px;
216
+ height: 20px;
217
+ border-radius: 50%;
218
+ margin: 0 5px;
219
+ cursor: pointer;
220
+ box-shadow: 0 2px 5px var(--shadow-color);
221
+ transition: transform 0.3s; /* Adding circle hover effect */
222
+ }
223
+
224
+ .color-circle:hover {
225
+ transform: scale(1.2); /* Scale up on hover */
226
+ }
227
+
228
+ /* Animations */
229
+ @keyframes fadeIn {
230
+ from {
231
+ opacity: 0;
232
+ transform: translateY(20px);
233
+ }
234
+
235
+ to {
236
+ opacity: 1;
237
+ transform: translateY(0);
238
+ }
239
+ }
240
+
241
+ @keyframes slideInRight {
242
+ from {
243
+ opacity: 0;
244
+ transform: translateX(100%);
245
+ }
246
+ to {
247
+ opacity: 1;
248
+ transform: translateX(0);
249
+ }
250
+ }
251
+
252
+ @keyframes slideInLeft {
253
+ from {
254
+ opacity: 0;
255
+ transform: translateX(-100%);
256
+ }
257
+ to {
258
+ opacity: 1;
259
+ transform: translateX(0);
260
+ }
261
+ }
262
+
263
+ /* Background animation */
264
+ @keyframes backgroundAnimate {
265
+ 0% {
266
+ background-color: rgba(255, 255, 255, 0.05);
267
+ }
268
+ 50% {
269
+ background-color: rgba(255, 255, 255, 0.1);
270
+ }
271
+ 100% {
272
+ background-color: rgba(255, 255, 255, 0.05);
273
+ }
274
+ }
275
+
276
+ /* VFX related styles */
277
+ .vfx {
278
+ position: absolute;
279
+ top: 0;
280
+ left: 0;
281
+ width: 100%;
282
+ height: 100%;
283
+ pointer-events: none;
284
+ animation: backgroundAnimate 5s infinite; /* Continuously animate background */
285
+ z-index: 0; /* Background layer */
286
+ }
287
+ </style>
288
+ </head>
289
+
290
+ <body>
291
+ <div class="vfx"></div> <!-- Background effects -->
292
+
293
+ <div class="container">
294
+ <!-- Settings -->
295
+ <div class="settings">
296
+ <div class="theme-toggle">
297
+ <label for="theme-select">Select Theme:</label>
298
+ <select id="theme-select">
299
+ <option value="default">Default</option>
300
+ <option value="calm-azure">Calm Azure</option>
301
+ <option value="elegant-charcoal">Elegant Charcoal</option>
302
+ <option value="fresh-greenery">Fresh Greenery</option>
303
+ <option value="soft-lavender">Soft Lavender</option>
304
+ <option value="bright-summer">Bright Summer</option>
305
+ </select>
306
+ </div>
307
+ <div class="color-picker">
308
+ <label>Accent Color:</label>
309
+ <div class="color-circle" style="background-color: #6a0dad;" onclick="changeColor('#6a0dad')"></div>
310
+ <div class="color-circle" style="background-color: #ff4500;" onclick="changeColor('#ff4500')"></div>
311
+ <div class="color-circle" style="background-color: #007bff;" onclick="changeColor('#007bff')"></div>
312
+ <div class="color-circle" style="background-color: #28a745;" onclick="changeColor('#28a745')"></div>
313
+ </div>
314
+ </div>
315
+
316
+ <!-- Header -->
317
+ <div class="header">Advanced Chatbot UI</div>
318
+
319
+ <!-- Chatbox -->
320
+ <div class="chat-box" id="chat-box"></div>
321
+
322
+ <!-- Footer -->
323
+ <div class="footer">
324
+ <input type="text" id="user-input" placeholder="Type your message..." />
325
+ <button id="send-btn">Send</button>
326
+ <button id="voice-btn">🎤 Start Voice Input</button>
327
+ </div>
328
+ </div>
329
+
330
+ <script>
331
+ const chatBox = document.getElementById('chat-box');
332
+ const voiceBtn = document.getElementById('voice-btn');
333
+ const sendBtn = document.getElementById('send-btn');
334
+ const userInput = document.getElementById('user-input');
335
+ const themeSelect = document.getElementById('theme-select');
336
+
337
+ // Add message to chatbox with visual effects
338
+ function addMessage(sender, text) {
339
+ const msgDiv = document.createElement('div');
340
+ msgDiv.classList.add('message', sender);
341
+ msgDiv.textContent = text;
342
+ chatBox.appendChild(msgDiv);
343
+ chatBox.scrollTop = chatBox.scrollHeight;
344
+ }
345
+
346
+ // Speech Recognition Setup
347
+ const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
348
+ recognition.lang = 'en-US';
349
+
350
+ voiceBtn.addEventListener('click', () => recognition.start());
351
+
352
+ recognition.addEventListener('result', (e) => {
353
+ const transcript = e.results[0][0].transcript;
354
+ addMessage('user-message', transcript);
355
+ sendUserMessage(transcript);
356
+ });
357
+
358
+ // Function to change the accent color
359
+ function changeColor(color) {
360
+ document.documentElement.style.setProperty('--accent-color', color);
361
+ }
362
+
363
+ // Function to change the theme
364
+ function changeTheme(theme) {
365
+ document.documentElement.classList.remove('theme-calm-azure', 'theme-elegant-charcoal', 'theme-fresh-greenery', 'theme-soft-lavender', 'theme-bright-summer');
366
+ if (theme !== 'default') {
367
+ document.documentElement.classList.add('theme-' + theme);
368
+ }
369
+ }
370
+
371
+ // Send user input to backend (placeholder URL)
372
+ function sendUserMessage(message) {
373
+ fetch('/chat', {
374
+ method: 'POST',
375
+ headers: {
376
+ 'Content-Type': 'application/json',
377
+ },
378
+ body: JSON.stringify({ message: message }),
379
+ })
380
+ .then(response => response.json())
381
+ .then(data => {
382
+ const botResponse = data.response;
383
+ addMessage('bot-message', botResponse);
384
+ speakResponse(botResponse);
385
+ })
386
+ .catch(error => {
387
+ console.error("Error:", error);
388
+ addMessage('bot-message', "Sorry, I couldn't process that.");
389
+ });
390
+ }
391
+
392
+ // Text-to-Speech Function
393
+ function speakResponse(text) {
394
+ const utterance = new SpeechSynthesisUtterance(text);
395
+ utterance.lang = 'en-US';
396
+ window.speechSynthesis.speak(utterance);
397
+ }
398
+ // Event listeners for buttons
399
+ sendBtn.addEventListener('click', () => {
400
+ const message = userInput.value.trim();
401
+ if (message) {
402
+ addMessage('user-message', message);
403
+ sendUserMessage(message);
404
+ userInput.value = ''; // Clear input field after sending
405
+ }
406
+ });
407
+
408
+ // Handle pressing 'Enter' key for sending messages
409
+ userInput.addEventListener('keypress', (e) => {
410
+ if (e.key === 'Enter') {
411
+ sendBtn.click(); // Trigger button click
412
+ }
413
+ });
414
+
415
+ // Update theme when selected from dropdown
416
+ themeSelect.addEventListener('change', (e) => {
417
+ changeTheme(e.target.value);
418
+ });
419
+
420
+ recognition.addEventListener('error', (event) => {
421
+ console.error("Speech recognition error", event);
422
+ });
423
+
424
+ </script>
425
+ </body>
426
+
427
+ </html>