Ajey95 commited on
Commit
a34718b
ยท
1 Parent(s): e06770f

Fix: chat_history addition

Browse files
Files changed (3) hide show
  1. agents/academic_agent.py +2 -0
  2. app.py +583 -483
  3. templates/index.html +193 -6
agents/academic_agent.py CHANGED
@@ -413,7 +413,9 @@ Your reasoning process must be:
413
  1. First, analyze the CONVERSATION HISTORY to understand the immediate context of the CURRENT QUESTION. This is especially important to understand what "this," "that," or "it" refers to.
414
  2. Once you understand the user's real question, check if the UPLOADED FILE context is relevant to the topic.
415
  3. Formulate your answer based on this reasoning, keeping an encouraging and professional tone.
 
416
  CONVERSATION HISTORY:
 
417
  {context_section}
418
  CURRENT QUESTION:
419
  User: {query}
 
413
  1. First, analyze the CONVERSATION HISTORY to understand the immediate context of the CURRENT QUESTION. This is especially important to understand what "this," "that," or "it" refers to.
414
  2. Once you understand the user's real question, check if the UPLOADED FILE context is relevant to the topic.
415
  3. Formulate your answer based on this reasoning, keeping an encouraging and professional tone.
416
+
417
  CONVERSATION HISTORY:
418
+ {history_for_prompt}
419
  {context_section}
420
  CURRENT QUESTION:
421
  User: {query}
app.py CHANGED
@@ -1,303 +1,62 @@
1
- # # Shiva
2
- # from flask import Flask, render_template, request, jsonify, session
3
- # import os
4
- # from dotenv import load_dotenv
5
- # import json
6
- # import random
7
- # from werkzeug.utils import secure_filename
8
- # import google.generativeai as genai
9
- # from pathlib import Path
10
-
11
- # # Load environment variables
12
- # load_dotenv()
13
-
14
- # app = Flask(__name__)
15
- # app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'dev-secret-key')
16
- # app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
17
-
18
- # # Configure upload settings
19
- # UPLOAD_FOLDER = 'uploads'
20
- # ALLOWED_EXTENSIONS = {'txt', 'pdf', 'docx', 'doc', 'json', 'csv'}
21
- # app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
22
-
23
- # # Create upload directory
24
- # os.makedirs(UPLOAD_FOLDER, exist_ok=True)
25
-
26
- # # Configure Gemini API
27
- # GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
28
- # if GEMINI_API_KEY:
29
- # genai.configure(api_key=GEMINI_API_KEY)
30
- # model = genai.GenerativeModel('gemini-1.5-pro')
31
- # print("โœ… Gemini API configured successfully!")
32
- # else:
33
- # model = None
34
- # print("โš ๏ธ No Gemini API key found. Using fallback responses.")
35
-
36
- # # Import agents and utilities
37
- # from agents.router_agent import RouterAgent
38
- # from utils.helpers import load_quotes, get_greeting
39
- # from utils.file_processor import FileProcessor
40
-
41
- # def allowed_file(filename):
42
- # return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
43
-
44
- # class MyPharmaAI:
45
- # def __init__(self):
46
- # self.router = RouterAgent(model) # Pass model to router
47
- # self.quotes = load_quotes()
48
- # self.file_processor = FileProcessor()
49
-
50
- # def process_query(self, query, user_name="Student", uploaded_files=None):
51
- # """Process user query through the router agent with optional file context"""
52
- # try:
53
- # # Check if we have uploaded files to reference
54
- # file_context = ""
55
- # if uploaded_files and 'uploaded_files' in session:
56
- # file_context = self.get_file_context(session['uploaded_files'])
57
-
58
- # # Route the query to appropriate agent
59
- # response = self.router.route_query(query, file_context)
60
- # return {
61
- # 'success': True,
62
- # 'response': response,
63
- # 'agent_used': response.get('agent_type', 'unknown')
64
- # }
65
- # except Exception as e:
66
- # return {
67
- # 'success': False,
68
- # 'response': f"เคฎเคพเคซ เค•เคฐเฅ‡เค‚ (Sorry), I encountered an error: {str(e)}",
69
- # 'agent_used': 'error'
70
- # }
71
-
72
- # def get_file_context(self, uploaded_files):
73
- # """Get context from uploaded files"""
74
- # context = ""
75
- # for file_info in uploaded_files[-3:]: # Last 3 files only
76
- # file_path = file_info['path']
77
- # if os.path.exists(file_path):
78
- # try:
79
- # content = self.file_processor.extract_text(file_path)
80
- # if content:
81
- # context += f"\n\n๐Ÿ“„ Content from {file_info['original_name']}:\n{content[:2000]}..." # Limit context
82
- # except Exception as e:
83
- # context += f"\n\nโŒ Error reading {file_info['original_name']}: {str(e)}"
84
- # return context
85
-
86
- # def get_daily_quote(self):
87
- # """Get inspirational quote from Gita/Vedas"""
88
- # return random.choice(self.quotes) if self.quotes else "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ"
89
-
90
- # def process_file_upload(self, file):
91
- # """Process uploaded file and extract information"""
92
- # try:
93
- # if file and allowed_file(file.filename):
94
- # filename = secure_filename(file.filename)
95
- # timestamp = str(int(time.time()))
96
- # filename = f"{timestamp}_{filename}"
97
- # file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
98
- # file.save(file_path)
99
-
100
- # # Extract text content
101
- # content = self.file_processor.extract_text(file_path)
102
-
103
- # # Store in session
104
- # if 'uploaded_files' not in session:
105
- # session['uploaded_files'] = []
106
-
107
- # file_info = {
108
- # 'original_name': file.filename,
109
- # 'saved_name': filename,
110
- # 'path': file_path,
111
- # 'size': os.path.getsize(file_path),
112
- # 'preview': content[:500] if content else "No text content extracted"
113
- # }
114
-
115
- # session['uploaded_files'].append(file_info)
116
- # session.modified = True
117
-
118
- # return {
119
- # 'success': True,
120
- # 'message': f'File "{file.filename}" uploaded successfully! You can now ask questions about its content.',
121
- # 'file_info': file_info
122
- # }
123
- # else:
124
- # return {
125
- # 'success': False,
126
- # 'message': 'Invalid file type. Supported: TXT, PDF, DOCX, DOC, JSON, CSV'
127
- # }
128
- # except Exception as e:
129
- # return {
130
- # 'success': False,
131
- # 'message': f'Error uploading file: {str(e)}'
132
- # }
133
-
134
- # # Initialize the AI system
135
- # import time
136
- # pharma_ai = MyPharmaAI()
137
-
138
- # @app.route('/')
139
- # def index():
140
- # """Main chat interface"""
141
- # greeting = get_greeting()
142
- # daily_quote = pharma_ai.get_daily_quote()
143
-
144
- # # Get uploaded files info
145
- # uploaded_files = session.get('uploaded_files', [])
146
-
147
- # return render_template('index.html',
148
- # greeting=greeting,
149
- # daily_quote=daily_quote,
150
- # uploaded_files=uploaded_files,
151
- # api_available=bool(GEMINI_API_KEY))
152
-
153
- # @app.route('/chat', methods=['POST'])
154
- # def chat():
155
- # """Main chat endpoint"""
156
- # try:
157
- # data = request.get_json()
158
-
159
- # if not data or 'query' not in data:
160
- # return jsonify({
161
- # 'success': False,
162
- # 'error': 'No query provided'
163
- # }), 400
164
-
165
- # user_query = data.get('query', '').strip()
166
- # user_name = data.get('user_name', 'Student')
167
-
168
- # if not user_query:
169
- # return jsonify({
170
- # 'success': False,
171
- # 'error': 'Empty query'
172
- # }), 400
173
-
174
- # # Process the query (with file context if available)
175
- # result = pharma_ai.process_query(user_query, user_name, session.get('uploaded_files'))
176
-
177
- # return jsonify(result)
178
-
179
- # except Exception as e:
180
- # return jsonify({
181
- # 'success': False,
182
- # 'error': f'Server error: {str(e)}'
183
- # }), 500
184
-
185
- # @app.route('/upload', methods=['POST'])
186
- # def upload_file():
187
- # """Handle file upload"""
188
- # try:
189
- # if 'file' not in request.files:
190
- # return jsonify({
191
- # 'success': False,
192
- # 'error': 'No file provided'
193
- # }), 400
194
-
195
- # file = request.files['file']
196
-
197
- # if file.filename == '':
198
- # return jsonify({
199
- # 'success': False,
200
- # 'error': 'No file selected'
201
- # }), 400
202
-
203
- # result = pharma_ai.process_file_upload(file)
204
- # return jsonify(result)
205
-
206
- # except Exception as e:
207
- # return jsonify({
208
- # 'success': False,
209
- # 'error': f'Upload error: {str(e)}'
210
- # }), 500
211
-
212
- # @app.route('/files')
213
- # def get_uploaded_files():
214
- # """Get list of uploaded files"""
215
- # uploaded_files = session.get('uploaded_files', [])
216
- # return jsonify({
217
- # 'files': uploaded_files,
218
- # 'count': len(uploaded_files)
219
- # })
220
-
221
- # @app.route('/clear_files', methods=['POST'])
222
- # def clear_files():
223
- # """Clear uploaded files"""
224
- # try:
225
- # # Remove files from disk
226
- # if 'uploaded_files' in session:
227
- # for file_info in session['uploaded_files']:
228
- # file_path = file_info['path']
229
- # if os.path.exists(file_path):
230
- # os.remove(file_path)
231
-
232
- # # Clear session
233
- # session.pop('uploaded_files', None)
234
-
235
- # return jsonify({
236
- # 'success': True,
237
- # 'message': 'All files cleared successfully'
238
- # })
239
- # except Exception as e:
240
- # return jsonify({
241
- # 'success': False,
242
- # 'error': f'Error clearing files: {str(e)}'
243
- # }), 500
244
-
245
- # @app.route('/quote')
246
- # def get_quote():
247
- # """Get a random inspirational quote"""
248
- # quote = pharma_ai.get_daily_quote()
249
- # return jsonify({'quote': quote})
250
-
251
- # @app.route('/health')
252
- # def health_check():
253
- # """Health check endpoint"""
254
- # return jsonify({
255
- # 'status': 'healthy',
256
- # 'app': 'MyPharma AI',
257
- # 'version': '2.0.0',
258
- # 'gemini_api': 'connected' if GEMINI_API_KEY else 'not configured',
259
- # 'features': ['chat', 'file_upload', 'multi_agent', 'indian_theme']
260
- # })
261
-
262
- # if __name__ == '__main__':
263
- # # Create necessary directories
264
- # for directory in ['data', 'static/css', 'static/js', 'templates', 'agents', 'utils', 'uploads']:
265
- # os.makedirs(directory, exist_ok=True)
266
-
267
- # print("๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI Starting...")
268
- # print(f"๐Ÿ“ Upload folder: {UPLOAD_FOLDER}")
269
- # print(f"๐Ÿค– Gemini API: {'โœ… Ready' if GEMINI_API_KEY else 'โŒ Not configured'}")
270
- # print("๐Ÿš€ Server starting on http://localhost:5000")
271
-
272
- # # Run the app
273
- # app.run(debug=True, port=5000)
274
- # # #### app.py (Main Application)
275
- # # from flask import Flask, render_template, request, jsonify
276
  # # import os
277
  # # from dotenv import load_dotenv
278
  # # import json
279
  # # import random
 
 
 
280
 
281
  # # # Load environment variables
282
  # # load_dotenv()
283
 
284
  # # app = Flask(__name__)
285
  # # app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'dev-secret-key')
286
-
287
- # # # Import agents
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  # # from agents.router_agent import RouterAgent
289
  # # from utils.helpers import load_quotes, get_greeting
 
 
 
 
290
 
291
  # # class MyPharmaAI:
292
  # # def __init__(self):
293
- # # self.router = RouterAgent()
294
  # # self.quotes = load_quotes()
 
295
 
296
- # # def process_query(self, query, user_name="Student"):
297
- # # """Process user query through the router agent"""
298
  # # try:
 
 
 
 
 
299
  # # # Route the query to appropriate agent
300
- # # response = self.router.route_query(query)
301
  # # return {
302
  # # 'success': True,
303
  # # 'response': response,
@@ -310,11 +69,70 @@
310
  # # 'agent_used': 'error'
311
  # # }
312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  # # def get_daily_quote(self):
314
  # # """Get inspirational quote from Gita/Vedas"""
315
  # # return random.choice(self.quotes) if self.quotes else "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
  # # # Initialize the AI system
 
318
  # # pharma_ai = MyPharmaAI()
319
 
320
  # # @app.route('/')
@@ -322,9 +140,15 @@
322
  # # """Main chat interface"""
323
  # # greeting = get_greeting()
324
  # # daily_quote = pharma_ai.get_daily_quote()
 
 
 
 
325
  # # return render_template('index.html',
326
  # # greeting=greeting,
327
- # # daily_quote=daily_quote)
 
 
328
 
329
  # # @app.route('/chat', methods=['POST'])
330
  # # def chat():
@@ -347,8 +171,8 @@
347
  # # 'error': 'Empty query'
348
  # # }), 400
349
 
350
- # # # Process the query
351
- # # result = pharma_ai.process_query(user_query, user_name)
352
 
353
  # # return jsonify(result)
354
 
@@ -358,6 +182,66 @@
358
  # # 'error': f'Server error: {str(e)}'
359
  # # }), 500
360
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  # # @app.route('/quote')
362
  # # def get_quote():
363
  # # """Get a random inspirational quote"""
@@ -370,248 +254,464 @@
370
  # # return jsonify({
371
  # # 'status': 'healthy',
372
  # # 'app': 'MyPharma AI',
373
- # # 'version': '1.0.0'
 
 
374
  # # })
375
 
376
  # # if __name__ == '__main__':
377
- # # # Create data directories if they don't exist
378
- # # os.makedirs('data', exist_ok=True)
379
- # # os.makedirs('static/css', exist_ok=True)
380
- # # os.makedirs('static/js', exist_ok=True)
381
- # # os.makedirs('templates', exist_ok=True)
382
- # # os.makedirs('agents', exist_ok=True)
383
- # # os.makedirs('utils', exist_ok=True)
 
384
 
385
  # # # Run the app
386
  # # app.run(debug=True, port=5000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
 
388
  # app.py
389
- # Main Flask application for MyPharma AI
390
 
391
- from flask import Flask, render_template, request, jsonify, session
392
  import os
393
- import json
394
  import random
395
- import time
396
  from dotenv import load_dotenv
397
- from werkzeug.utils import secure_filename
398
  import google.generativeai as genai
399
 
400
- # Load environment variables from a .env file
 
 
 
 
 
 
401
  load_dotenv()
 
 
402
 
403
  # --- App Configuration ---
404
  app = Flask(__name__)
405
  app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'a-very-secret-key-for-dev')
406
- app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
407
 
408
- # --- Upload Configuration ---
409
- UPLOAD_FOLDER = '/tmp/uploads'
410
- ALLOWED_EXTENSIONS = {'txt', 'pdf', 'docx', 'json', 'csv'}
411
- app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
412
- os.makedirs(UPLOAD_FOLDER, exist_ok=True)
413
-
414
- # --- Gemini API Configuration ---
415
- GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
416
  model = None
417
- if GEMINI_API_KEY:
418
- try:
 
 
419
  genai.configure(api_key=GEMINI_API_KEY)
420
- # Using gemini-1.5-flash for speed and cost-effectiveness
421
  model = genai.GenerativeModel('gemini-1.5-flash')
422
- print("โœ… Gemini 1.5 Flash Model configured successfully!")
423
- except Exception as e:
424
- print(f"โŒ Error configuring Gemini API: {e}")
425
- else:
426
- print("โš ๏ธ No Gemini API key found. AI features will be disabled.")
427
-
428
- # --- Import Agents and Utilities ---
429
- # (Ensure these files exist in their respective directories)
430
- from agents.router_agent import RouterAgent
431
- from utils.helpers import load_quotes, get_greeting
432
- from utils.file_processor import FileProcessor
433
-
434
- def allowed_file(filename):
435
- """Check if the uploaded file has an allowed extension."""
436
- return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
437
 
438
  # --- Main AI Application Class ---
439
  class MyPharmaAI:
440
- """Orchestrator for the entire AI system."""
441
- def __init__(self):
442
- self.router = RouterAgent(model) # The router now gets the configured model
443
  self.quotes = load_quotes()
444
- self.file_processor = FileProcessor()
445
-
446
- def process_query(self, query, user_name="Student", viva_state=None, uploaded_files=None, chat_history=None):
447
- """Routes a user's query to the appropriate agent, handling context."""
448
- try:
449
- # This block correctly gets the file content from the session data
450
- file_context = ""
451
- if uploaded_files:
452
- file_context = self.get_file_context(uploaded_files)
453
-
454
- # This passes the file content and chat history to the router
455
- response_data = self.router.route_query(query, file_context, viva_state, chat_history)
456
-
457
- return {
458
- 'success': True,
459
- **response_data
460
- }
461
- except Exception as e:
462
- print(f"Error in MyPharmaAI.process_query: {e}")
463
- return {
464
- 'success': False,
465
- 'message': f"Sorry, a critical error occurred: {str(e)}",
466
- 'agent_used': 'error'
467
- }
468
-
469
-
470
- def get_file_context(self, uploaded_files_session):
471
- """Extracts text from the most recent files to use as context."""
472
- context = ""
473
- for file_info in uploaded_files_session[-3:]: # Limit to last 3 files
474
- file_path = file_info.get('path')
475
- if file_path and os.path.exists(file_path):
476
- try:
477
- content = self.file_processor.extract_text(file_path)
478
- if content:
479
- # Limit context from each file to 2000 characters
480
- context += f"\n\n--- Content from {file_info['original_name']} ---\n{content[:2000]}..."
481
- except Exception as e:
482
- context += f"\n\n--- Error reading {file_info['original_name']}: {str(e)} ---"
483
- return context
484
-
485
- def get_daily_quote(self):
486
- """Returns a random quote."""
487
- return random.choice(self.quotes) if self.quotes else "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ"
488
-
489
- # Initialize the AI system
490
- pharma_ai = MyPharmaAI()
491
 
492
- # --- Flask Routes ---
493
 
 
494
  @app.route('/')
495
  def index():
496
- """Renders the main chat interface."""
497
- greeting = get_greeting()
498
- daily_quote = pharma_ai.get_daily_quote()
499
- uploaded_files = session.get('uploaded_files', [])
500
- return render_template('index.html',
501
- greeting=greeting,
502
- daily_quote=daily_quote,
503
- uploaded_files=uploaded_files)
504
 
505
  @app.route('/chat', methods=['POST'])
506
  def chat():
507
- """Handles the main chat logic, including session management for the Viva Agent."""
508
- try:
509
- data = request.get_json()
510
- query = data.get('query', '').strip()
511
- if not query:
512
- return jsonify({'success': False, 'error': 'Empty query'}), 400
513
-
514
- # --- HISTORY MANAGEMENT START ---
515
-
516
- # Get the conversation history from the session (or start a new one)
517
- chat_history = session.get('chat_history', [])
518
 
519
- # Get current viva state from session for the Viva Agent
520
- viva_state = session.get('viva_state', None)
521
- uploaded_files = session.get('uploaded_files', None)
522
-
523
- # Process the query through the main orchestrator
524
- result = pharma_ai.process_query(query, viva_state=viva_state, uploaded_files=uploaded_files,chat_history=chat_history)
525
- # If the query was successful, update the history
526
  if result.get('success'):
527
- # Add the user's query and the AI's message to the history
528
  chat_history.append({'role': 'user', 'parts': [query]})
529
  chat_history.append({'role': 'model', 'parts': [result.get('message', '')]})
530
-
531
- # Keep the history from getting too long (e.g., last 10 exchanges)
532
- session['chat_history'] = chat_history[-20:]
533
-
534
- # --- HISTORY MANAGEMENT END ---
535
-
536
- # If the Viva agent returns an updated state, save it to the session
537
- if 'viva_state' in result:
538
- session['viva_state'] = result.get('viva_state')
539
-
540
  return jsonify(result)
541
-
542
  except Exception as e:
543
  print(f"Error in /chat endpoint: {e}")
544
- return jsonify({'success': False, 'error': f'Server error: {str(e)}'}), 500
545
-
546
- @app.route('/upload', methods=['POST'])
547
- def upload_file():
548
- """Handles file uploads."""
549
- if 'file' not in request.files:
550
- return jsonify({'success': False, 'error': 'No file part'}), 400
551
- file = request.files['file']
552
- if file.filename == '':
553
- return jsonify({'success': False, 'error': 'No selected file'}), 400
554
- if file and allowed_file(file.filename):
555
- filename = secure_filename(file.filename)
556
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
557
- file.save(file_path)
558
-
559
- if 'uploaded_files' not in session:
560
- session['uploaded_files'] = []
561
-
562
- file_info = {'original_name': filename, 'path': file_path}
563
- session['uploaded_files'].append(file_info)
564
- session.modified = True
565
-
566
- return jsonify({
567
- 'success': True,
568
- 'message': f'File "{filename}" uploaded. You can now ask questions about it.',
569
- 'files': session['uploaded_files']
570
- })
571
- return jsonify({'success': False, 'error': 'File type not allowed'}), 400
572
-
573
- @app.route('/files', methods=['GET'])
574
- def get_uploaded_files():
575
- """Returns the list of uploaded files from the session."""
576
- return jsonify({'files': session.get('uploaded_files', [])})
577
-
578
- @app.route('/clear_files', methods=['POST'])
579
- def clear_files():
580
- """Deletes uploaded files from disk and clears them from the session."""
581
- if 'uploaded_files' in session:
582
- for file_info in session['uploaded_files']:
583
- if os.path.exists(file_info['path']):
584
- os.remove(file_info['path'])
585
- session.pop('uploaded_files', None)
586
- session.pop('viva_state', None) # Also clear viva state
587
- return jsonify({'success': True, 'message': 'All files and sessions cleared.'})
588
-
589
- @app.route('/quote')
590
- def get_quote():
591
- """Returns a new random quote."""
592
- return jsonify({'quote': pharma_ai.get_daily_quote()})
593
 
594
  # --- Main Execution ---
595
- # if __name__ == '__main__':
596
- # # Ensure all necessary directories exist
597
- # for directory in ['data', 'static/css', 'static/js', 'templates', 'agents', 'utils', 'uploads']:
598
- # os.makedirs(directory, exist_ok=True)
599
-
600
- # print("๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI Starting...")
601
- # print(f"๐Ÿค– Gemini API Status: {'โœ… Ready' if model else 'โŒ Not configured'}")
602
- # print("๐Ÿš€ Server starting on http://127.0.0.1:5000")
603
- # app.run(debug=True, port=5000)
604
  if __name__ == '__main__':
605
- # Create necessary directories (this is good practice)
606
- for directory in ['data', 'uploads', 'templates']:
607
- os.makedirs(directory, exist_ok=True)
608
-
609
- # Get port from environment variable, defaulting to 5000 for local testing
610
  port = int(os.environ.get('PORT', 7860))
611
-
612
- print("๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI Starting...")
613
- print(f"๐Ÿค– Gemini API Status: {'โœ… Ready' if model else 'โŒ Not configured'}")
614
- print(f"๐Ÿš€ Server starting on http://0.0.0.0:{port}")
615
-
616
- # Run the app to be accessible on the server
617
  app.run(host='0.0.0.0', port=port)
 
1
+ # # # Shiva
2
+ # # from flask import Flask, render_template, request, jsonify, session
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  # # import os
4
  # # from dotenv import load_dotenv
5
  # # import json
6
  # # import random
7
+ # # from werkzeug.utils import secure_filename
8
+ # # import google.generativeai as genai
9
+ # # from pathlib import Path
10
 
11
  # # # Load environment variables
12
  # # load_dotenv()
13
 
14
  # # app = Flask(__name__)
15
  # # app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'dev-secret-key')
16
+ # # app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
17
+
18
+ # # # Configure upload settings
19
+ # # UPLOAD_FOLDER = 'uploads'
20
+ # # ALLOWED_EXTENSIONS = {'txt', 'pdf', 'docx', 'doc', 'json', 'csv'}
21
+ # # app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
22
+
23
+ # # # Create upload directory
24
+ # # os.makedirs(UPLOAD_FOLDER, exist_ok=True)
25
+
26
+ # # # Configure Gemini API
27
+ # # GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
28
+ # # if GEMINI_API_KEY:
29
+ # # genai.configure(api_key=GEMINI_API_KEY)
30
+ # # model = genai.GenerativeModel('gemini-1.5-pro')
31
+ # # print("โœ… Gemini API configured successfully!")
32
+ # # else:
33
+ # # model = None
34
+ # # print("โš ๏ธ No Gemini API key found. Using fallback responses.")
35
+
36
+ # # # Import agents and utilities
37
  # # from agents.router_agent import RouterAgent
38
  # # from utils.helpers import load_quotes, get_greeting
39
+ # # from utils.file_processor import FileProcessor
40
+
41
+ # # def allowed_file(filename):
42
+ # # return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
43
 
44
  # # class MyPharmaAI:
45
  # # def __init__(self):
46
+ # # self.router = RouterAgent(model) # Pass model to router
47
  # # self.quotes = load_quotes()
48
+ # # self.file_processor = FileProcessor()
49
 
50
+ # # def process_query(self, query, user_name="Student", uploaded_files=None):
51
+ # # """Process user query through the router agent with optional file context"""
52
  # # try:
53
+ # # # Check if we have uploaded files to reference
54
+ # # file_context = ""
55
+ # # if uploaded_files and 'uploaded_files' in session:
56
+ # # file_context = self.get_file_context(session['uploaded_files'])
57
+
58
  # # # Route the query to appropriate agent
59
+ # # response = self.router.route_query(query, file_context)
60
  # # return {
61
  # # 'success': True,
62
  # # 'response': response,
 
69
  # # 'agent_used': 'error'
70
  # # }
71
 
72
+ # # def get_file_context(self, uploaded_files):
73
+ # # """Get context from uploaded files"""
74
+ # # context = ""
75
+ # # for file_info in uploaded_files[-3:]: # Last 3 files only
76
+ # # file_path = file_info['path']
77
+ # # if os.path.exists(file_path):
78
+ # # try:
79
+ # # content = self.file_processor.extract_text(file_path)
80
+ # # if content:
81
+ # # context += f"\n\n๐Ÿ“„ Content from {file_info['original_name']}:\n{content[:2000]}..." # Limit context
82
+ # # except Exception as e:
83
+ # # context += f"\n\nโŒ Error reading {file_info['original_name']}: {str(e)}"
84
+ # # return context
85
+
86
  # # def get_daily_quote(self):
87
  # # """Get inspirational quote from Gita/Vedas"""
88
  # # return random.choice(self.quotes) if self.quotes else "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ"
89
+
90
+ # # def process_file_upload(self, file):
91
+ # # """Process uploaded file and extract information"""
92
+ # # try:
93
+ # # if file and allowed_file(file.filename):
94
+ # # filename = secure_filename(file.filename)
95
+ # # timestamp = str(int(time.time()))
96
+ # # filename = f"{timestamp}_{filename}"
97
+ # # file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
98
+ # # file.save(file_path)
99
+
100
+ # # # Extract text content
101
+ # # content = self.file_processor.extract_text(file_path)
102
+
103
+ # # # Store in session
104
+ # # if 'uploaded_files' not in session:
105
+ # # session['uploaded_files'] = []
106
+
107
+ # # file_info = {
108
+ # # 'original_name': file.filename,
109
+ # # 'saved_name': filename,
110
+ # # 'path': file_path,
111
+ # # 'size': os.path.getsize(file_path),
112
+ # # 'preview': content[:500] if content else "No text content extracted"
113
+ # # }
114
+
115
+ # # session['uploaded_files'].append(file_info)
116
+ # # session.modified = True
117
+
118
+ # # return {
119
+ # # 'success': True,
120
+ # # 'message': f'File "{file.filename}" uploaded successfully! You can now ask questions about its content.',
121
+ # # 'file_info': file_info
122
+ # # }
123
+ # # else:
124
+ # # return {
125
+ # # 'success': False,
126
+ # # 'message': 'Invalid file type. Supported: TXT, PDF, DOCX, DOC, JSON, CSV'
127
+ # # }
128
+ # # except Exception as e:
129
+ # # return {
130
+ # # 'success': False,
131
+ # # 'message': f'Error uploading file: {str(e)}'
132
+ # # }
133
 
134
  # # # Initialize the AI system
135
+ # # import time
136
  # # pharma_ai = MyPharmaAI()
137
 
138
  # # @app.route('/')
 
140
  # # """Main chat interface"""
141
  # # greeting = get_greeting()
142
  # # daily_quote = pharma_ai.get_daily_quote()
143
+
144
+ # # # Get uploaded files info
145
+ # # uploaded_files = session.get('uploaded_files', [])
146
+
147
  # # return render_template('index.html',
148
  # # greeting=greeting,
149
+ # # daily_quote=daily_quote,
150
+ # # uploaded_files=uploaded_files,
151
+ # # api_available=bool(GEMINI_API_KEY))
152
 
153
  # # @app.route('/chat', methods=['POST'])
154
  # # def chat():
 
171
  # # 'error': 'Empty query'
172
  # # }), 400
173
 
174
+ # # # Process the query (with file context if available)
175
+ # # result = pharma_ai.process_query(user_query, user_name, session.get('uploaded_files'))
176
 
177
  # # return jsonify(result)
178
 
 
182
  # # 'error': f'Server error: {str(e)}'
183
  # # }), 500
184
 
185
+ # # @app.route('/upload', methods=['POST'])
186
+ # # def upload_file():
187
+ # # """Handle file upload"""
188
+ # # try:
189
+ # # if 'file' not in request.files:
190
+ # # return jsonify({
191
+ # # 'success': False,
192
+ # # 'error': 'No file provided'
193
+ # # }), 400
194
+
195
+ # # file = request.files['file']
196
+
197
+ # # if file.filename == '':
198
+ # # return jsonify({
199
+ # # 'success': False,
200
+ # # 'error': 'No file selected'
201
+ # # }), 400
202
+
203
+ # # result = pharma_ai.process_file_upload(file)
204
+ # # return jsonify(result)
205
+
206
+ # # except Exception as e:
207
+ # # return jsonify({
208
+ # # 'success': False,
209
+ # # 'error': f'Upload error: {str(e)}'
210
+ # # }), 500
211
+
212
+ # # @app.route('/files')
213
+ # # def get_uploaded_files():
214
+ # # """Get list of uploaded files"""
215
+ # # uploaded_files = session.get('uploaded_files', [])
216
+ # # return jsonify({
217
+ # # 'files': uploaded_files,
218
+ # # 'count': len(uploaded_files)
219
+ # # })
220
+
221
+ # # @app.route('/clear_files', methods=['POST'])
222
+ # # def clear_files():
223
+ # # """Clear uploaded files"""
224
+ # # try:
225
+ # # # Remove files from disk
226
+ # # if 'uploaded_files' in session:
227
+ # # for file_info in session['uploaded_files']:
228
+ # # file_path = file_info['path']
229
+ # # if os.path.exists(file_path):
230
+ # # os.remove(file_path)
231
+
232
+ # # # Clear session
233
+ # # session.pop('uploaded_files', None)
234
+
235
+ # # return jsonify({
236
+ # # 'success': True,
237
+ # # 'message': 'All files cleared successfully'
238
+ # # })
239
+ # # except Exception as e:
240
+ # # return jsonify({
241
+ # # 'success': False,
242
+ # # 'error': f'Error clearing files: {str(e)}'
243
+ # # }), 500
244
+
245
  # # @app.route('/quote')
246
  # # def get_quote():
247
  # # """Get a random inspirational quote"""
 
254
  # # return jsonify({
255
  # # 'status': 'healthy',
256
  # # 'app': 'MyPharma AI',
257
+ # # 'version': '2.0.0',
258
+ # # 'gemini_api': 'connected' if GEMINI_API_KEY else 'not configured',
259
+ # # 'features': ['chat', 'file_upload', 'multi_agent', 'indian_theme']
260
  # # })
261
 
262
  # # if __name__ == '__main__':
263
+ # # # Create necessary directories
264
+ # # for directory in ['data', 'static/css', 'static/js', 'templates', 'agents', 'utils', 'uploads']:
265
+ # # os.makedirs(directory, exist_ok=True)
266
+
267
+ # # print("๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI Starting...")
268
+ # # print(f"๐Ÿ“ Upload folder: {UPLOAD_FOLDER}")
269
+ # # print(f"๐Ÿค– Gemini API: {'โœ… Ready' if GEMINI_API_KEY else 'โŒ Not configured'}")
270
+ # # print("๐Ÿš€ Server starting on http://localhost:5000")
271
 
272
  # # # Run the app
273
  # # app.run(debug=True, port=5000)
274
+ # # # #### app.py (Main Application)
275
+ # # # from flask import Flask, render_template, request, jsonify
276
+ # # # import os
277
+ # # # from dotenv import load_dotenv
278
+ # # # import json
279
+ # # # import random
280
+
281
+ # # # # Load environment variables
282
+ # # # load_dotenv()
283
+
284
+ # # # app = Flask(__name__)
285
+ # # # app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'dev-secret-key')
286
+
287
+ # # # # Import agents
288
+ # # # from agents.router_agent import RouterAgent
289
+ # # # from utils.helpers import load_quotes, get_greeting
290
+
291
+ # # # class MyPharmaAI:
292
+ # # # def __init__(self):
293
+ # # # self.router = RouterAgent()
294
+ # # # self.quotes = load_quotes()
295
+
296
+ # # # def process_query(self, query, user_name="Student"):
297
+ # # # """Process user query through the router agent"""
298
+ # # # try:
299
+ # # # # Route the query to appropriate agent
300
+ # # # response = self.router.route_query(query)
301
+ # # # return {
302
+ # # # 'success': True,
303
+ # # # 'response': response,
304
+ # # # 'agent_used': response.get('agent_type', 'unknown')
305
+ # # # }
306
+ # # # except Exception as e:
307
+ # # # return {
308
+ # # # 'success': False,
309
+ # # # 'response': f"เคฎเคพเคซ เค•เคฐเฅ‡เค‚ (Sorry), I encountered an error: {str(e)}",
310
+ # # # 'agent_used': 'error'
311
+ # # # }
312
+
313
+ # # # def get_daily_quote(self):
314
+ # # # """Get inspirational quote from Gita/Vedas"""
315
+ # # # return random.choice(self.quotes) if self.quotes else "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ"
316
+
317
+ # # # # Initialize the AI system
318
+ # # # pharma_ai = MyPharmaAI()
319
+
320
+ # # # @app.route('/')
321
+ # # # def index():
322
+ # # # """Main chat interface"""
323
+ # # # greeting = get_greeting()
324
+ # # # daily_quote = pharma_ai.get_daily_quote()
325
+ # # # return render_template('index.html',
326
+ # # # greeting=greeting,
327
+ # # # daily_quote=daily_quote)
328
+
329
+ # # # @app.route('/chat', methods=['POST'])
330
+ # # # def chat():
331
+ # # # """Main chat endpoint"""
332
+ # # # try:
333
+ # # # data = request.get_json()
334
+
335
+ # # # if not data or 'query' not in data:
336
+ # # # return jsonify({
337
+ # # # 'success': False,
338
+ # # # 'error': 'No query provided'
339
+ # # # }), 400
340
+
341
+ # # # user_query = data.get('query', '').strip()
342
+ # # # user_name = data.get('user_name', 'Student')
343
+
344
+ # # # if not user_query:
345
+ # # # return jsonify({
346
+ # # # 'success': False,
347
+ # # # 'error': 'Empty query'
348
+ # # # }), 400
349
+
350
+ # # # # Process the query
351
+ # # # result = pharma_ai.process_query(user_query, user_name)
352
+
353
+ # # # return jsonify(result)
354
+
355
+ # # # except Exception as e:
356
+ # # # return jsonify({
357
+ # # # 'success': False,
358
+ # # # 'error': f'Server error: {str(e)}'
359
+ # # # }), 500
360
+
361
+ # # # @app.route('/quote')
362
+ # # # def get_quote():
363
+ # # # """Get a random inspirational quote"""
364
+ # # # quote = pharma_ai.get_daily_quote()
365
+ # # # return jsonify({'quote': quote})
366
+
367
+ # # # @app.route('/health')
368
+ # # # def health_check():
369
+ # # # """Health check endpoint"""
370
+ # # # return jsonify({
371
+ # # # 'status': 'healthy',
372
+ # # # 'app': 'MyPharma AI',
373
+ # # # 'version': '1.0.0'
374
+ # # # })
375
+
376
+ # # # if __name__ == '__main__':
377
+ # # # # Create data directories if they don't exist
378
+ # # # os.makedirs('data', exist_ok=True)
379
+ # # # os.makedirs('static/css', exist_ok=True)
380
+ # # # os.makedirs('static/js', exist_ok=True)
381
+ # # # os.makedirs('templates', exist_ok=True)
382
+ # # # os.makedirs('agents', exist_ok=True)
383
+ # # # os.makedirs('utils', exist_ok=True)
384
+
385
+ # # # # Run the app
386
+ # # # app.run(debug=True, port=5000)
387
+
388
+ # # app.py
389
+ # # Main Flask application for MyPharma AI
390
+
391
+ # from flask import Flask, render_template, request, jsonify, session
392
+ # import os
393
+ # import json
394
+ # import random
395
+ # import time
396
+ # from dotenv import load_dotenv
397
+ # from werkzeug.utils import secure_filename
398
+ # import google.generativeai as genai
399
+
400
+ # # Load environment variables from a .env file
401
+ # load_dotenv()
402
+
403
+ # # --- App Configuration ---
404
+ # app = Flask(__name__)
405
+ # app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'a-very-secret-key-for-dev')
406
+ # app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
407
+
408
+ # # --- Upload Configuration ---
409
+ # UPLOAD_FOLDER = '/tmp/uploads'
410
+ # ALLOWED_EXTENSIONS = {'txt', 'pdf', 'docx', 'json', 'csv'}
411
+ # app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
412
+ # os.makedirs(UPLOAD_FOLDER, exist_ok=True)
413
+
414
+ # # --- Gemini API Configuration ---
415
+ # GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
416
+ # model = None
417
+ # if GEMINI_API_KEY:
418
+ # try:
419
+ # genai.configure(api_key=GEMINI_API_KEY)
420
+ # # Using gemini-1.5-flash for speed and cost-effectiveness
421
+ # model = genai.GenerativeModel('gemini-1.5-flash')
422
+ # print("โœ… Gemini 1.5 Flash Model configured successfully!")
423
+ # except Exception as e:
424
+ # print(f"โŒ Error configuring Gemini API: {e}")
425
+ # else:
426
+ # print("โš ๏ธ No Gemini API key found. AI features will be disabled.")
427
+
428
+ # # --- Import Agents and Utilities ---
429
+ # # (Ensure these files exist in their respective directories)
430
+ # from agents.router_agent import RouterAgent
431
+ # from utils.helpers import load_quotes, get_greeting
432
+ # from utils.file_processor import FileProcessor
433
+
434
+ # def allowed_file(filename):
435
+ # """Check if the uploaded file has an allowed extension."""
436
+ # return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
437
+
438
+ # # --- Main AI Application Class ---
439
+ # class MyPharmaAI:
440
+ # """Orchestrator for the entire AI system."""
441
+ # def __init__(self):
442
+ # self.router = RouterAgent(model) # The router now gets the configured model
443
+ # self.quotes = load_quotes()
444
+ # self.file_processor = FileProcessor()
445
+
446
+ # def process_query(self, query, user_name="Student", viva_state=None, uploaded_files=None, chat_history=None):
447
+ # """Routes a user's query to the appropriate agent, handling context."""
448
+ # try:
449
+ # # This block correctly gets the file content from the session data
450
+ # file_context = ""
451
+ # if uploaded_files:
452
+ # file_context = self.get_file_context(uploaded_files)
453
+
454
+ # # This passes the file content and chat history to the router
455
+ # response_data = self.router.route_query(query, file_context, viva_state, chat_history)
456
+
457
+ # return {
458
+ # 'success': True,
459
+ # **response_data
460
+ # }
461
+ # except Exception as e:
462
+ # print(f"Error in MyPharmaAI.process_query: {e}")
463
+ # return {
464
+ # 'success': False,
465
+ # 'message': f"Sorry, a critical error occurred: {str(e)}",
466
+ # 'agent_used': 'error'
467
+ # }
468
+
469
+
470
+ # def get_file_context(self, uploaded_files_session):
471
+ # """Extracts text from the most recent files to use as context."""
472
+ # context = ""
473
+ # for file_info in uploaded_files_session[-3:]: # Limit to last 3 files
474
+ # file_path = file_info.get('path')
475
+ # if file_path and os.path.exists(file_path):
476
+ # try:
477
+ # content = self.file_processor.extract_text(file_path)
478
+ # if content:
479
+ # # Limit context from each file to 2000 characters
480
+ # context += f"\n\n--- Content from {file_info['original_name']} ---\n{content[:2000]}..."
481
+ # except Exception as e:
482
+ # context += f"\n\n--- Error reading {file_info['original_name']}: {str(e)} ---"
483
+ # return context
484
+
485
+ # def get_daily_quote(self):
486
+ # """Returns a random quote."""
487
+ # return random.choice(self.quotes) if self.quotes else "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ"
488
+
489
+ # # Initialize the AI system
490
+ # pharma_ai = MyPharmaAI()
491
+
492
+ # # --- Flask Routes ---
493
+
494
+ # @app.route('/')
495
+ # def index():
496
+ # """Renders the main chat interface."""
497
+ # greeting = get_greeting()
498
+ # daily_quote = pharma_ai.get_daily_quote()
499
+ # uploaded_files = session.get('uploaded_files', [])
500
+ # return render_template('index.html',
501
+ # greeting=greeting,
502
+ # daily_quote=daily_quote,
503
+ # uploaded_files=uploaded_files)
504
+
505
+ # @app.route('/chat', methods=['POST'])
506
+ # def chat():
507
+ # """Handles the main chat logic, including session management for the Viva Agent."""
508
+ # try:
509
+ # data = request.get_json()
510
+ # query = data.get('query', '').strip()
511
+ # if not query:
512
+ # return jsonify({'success': False, 'error': 'Empty query'}), 400
513
+
514
+ # # --- HISTORY MANAGEMENT START ---
515
+
516
+ # # Get the conversation history from the session (or start a new one)
517
+ # chat_history = session.get('chat_history', [])
518
+
519
+ # # Get current viva state from session for the Viva Agent
520
+ # viva_state = session.get('viva_state', None)
521
+ # uploaded_files = session.get('uploaded_files', None)
522
+
523
+ # # Process the query through the main orchestrator
524
+ # result = pharma_ai.process_query(query, viva_state=viva_state, uploaded_files=uploaded_files,chat_history=chat_history)
525
+ # # If the query was successful, update the history
526
+ # if result.get('success'):
527
+ # # Add the user's query and the AI's message to the history
528
+ # chat_history.append({'role': 'user', 'parts': [query]})
529
+ # chat_history.append({'role': 'model', 'parts': [result.get('message', '')]})
530
+
531
+ # # Keep the history from getting too long (e.g., last 10 exchanges)
532
+ # session['chat_history'] = chat_history[-20:]
533
+
534
+ # # --- HISTORY MANAGEMENT END ---
535
+
536
+ # # If the Viva agent returns an updated state, save it to the session
537
+ # if 'viva_state' in result:
538
+ # session['viva_state'] = result.get('viva_state')
539
+
540
+ # return jsonify(result)
541
+
542
+ # except Exception as e:
543
+ # print(f"Error in /chat endpoint: {e}")
544
+ # return jsonify({'success': False, 'error': f'Server error: {str(e)}'}), 500
545
+
546
+ # @app.route('/upload', methods=['POST'])
547
+ # def upload_file():
548
+ # """Handles file uploads."""
549
+ # if 'file' not in request.files:
550
+ # return jsonify({'success': False, 'error': 'No file part'}), 400
551
+ # file = request.files['file']
552
+ # if file.filename == '':
553
+ # return jsonify({'success': False, 'error': 'No selected file'}), 400
554
+ # if file and allowed_file(file.filename):
555
+ # filename = secure_filename(file.filename)
556
+ # file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
557
+ # file.save(file_path)
558
+
559
+ # if 'uploaded_files' not in session:
560
+ # session['uploaded_files'] = []
561
+
562
+ # file_info = {'original_name': filename, 'path': file_path}
563
+ # session['uploaded_files'].append(file_info)
564
+ # session.modified = True
565
+
566
+ # return jsonify({
567
+ # 'success': True,
568
+ # 'message': f'File "{filename}" uploaded. You can now ask questions about it.',
569
+ # 'files': session['uploaded_files']
570
+ # })
571
+ # return jsonify({'success': False, 'error': 'File type not allowed'}), 400
572
+
573
+ # @app.route('/files', methods=['GET'])
574
+ # def get_uploaded_files():
575
+ # """Returns the list of uploaded files from the session."""
576
+ # return jsonify({'files': session.get('uploaded_files', [])})
577
+
578
+ # @app.route('/clear_files', methods=['POST'])
579
+ # def clear_files():
580
+ # """Deletes uploaded files from disk and clears them from the session."""
581
+ # if 'uploaded_files' in session:
582
+ # for file_info in session['uploaded_files']:
583
+ # if os.path.exists(file_info['path']):
584
+ # os.remove(file_info['path'])
585
+ # session.pop('uploaded_files', None)
586
+ # session.pop('viva_state', None) # Also clear viva state
587
+ # return jsonify({'success': True, 'message': 'All files and sessions cleared.'})
588
+
589
+ # @app.route('/quote')
590
+ # def get_quote():
591
+ # """Returns a new random quote."""
592
+ # return jsonify({'quote': pharma_ai.get_daily_quote()})
593
+
594
+ # # --- Main Execution ---
595
+ # # if __name__ == '__main__':
596
+ # # # Ensure all necessary directories exist
597
+ # # for directory in ['data', 'static/css', 'static/js', 'templates', 'agents', 'utils', 'uploads']:
598
+ # # os.makedirs(directory, exist_ok=True)
599
+
600
+ # # print("๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI Starting...")
601
+ # # print(f"๐Ÿค– Gemini API Status: {'โœ… Ready' if model else 'โŒ Not configured'}")
602
+ # # print("๐Ÿš€ Server starting on http://127.0.0.1:5000")
603
+ # # app.run(debug=True, port=5000)
604
+ # if __name__ == '__main__':
605
+ # # Create necessary directories (this is good practice)
606
+ # for directory in ['data', 'uploads', 'templates']:
607
+ # os.makedirs(directory, exist_ok=True)
608
+
609
+ # # Get port from environment variable, defaulting to 5000 for local testing
610
+ # port = int(os.environ.get('PORT', 7860))
611
+
612
+ # print("๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI Starting...")
613
+ # print(f"๐Ÿค– Gemini API Status: {'โœ… Ready' if model else 'โŒ Not configured'}")
614
+ # print(f"๐Ÿš€ Server starting on http://0.0.0.0:{port}")
615
+
616
+ # # Run the app to be accessible on the server
617
+ # app.run(host='0.0.0.0', port=port)
618
+
619
+
620
+
621
 
622
  # app.py
 
623
 
 
624
  import os
 
625
  import random
 
626
  from dotenv import load_dotenv
627
+ from flask import Flask, render_template, request, jsonify, session
628
  import google.generativeai as genai
629
 
630
+ # Import new langchain components and our helper
631
+ from langchain_google_genai import GoogleGenerativeAIEmbeddings
632
+ from langchain_community.vectorstores import FAISS
633
+ from utils.helpers import create_vector_store, get_greeting, load_quotes
634
+ from agents.router_agent import RouterAgent
635
+
636
+ # --- Initial Setup ---
637
  load_dotenv()
638
+ # Create the knowledge library on first startup if it doesn't exist
639
+ create_vector_store()
640
 
641
  # --- App Configuration ---
642
  app = Flask(__name__)
643
  app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'a-very-secret-key-for-dev')
 
644
 
645
+ # --- Gemini API & Knowledge Base Configuration ---
 
 
 
 
 
 
 
646
  model = None
647
+ vector_store = None
648
+ try:
649
+ GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
650
+ if GEMINI_API_KEY:
651
  genai.configure(api_key=GEMINI_API_KEY)
 
652
  model = genai.GenerativeModel('gemini-1.5-flash')
653
+
654
+ # Load the persistent knowledge base from disk
655
+ if os.path.exists('faiss_index'):
656
+ embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
657
+ vector_store = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
658
+ print("โœ… Gemini Model and Knowledge Base loaded successfully!")
659
+ else:
660
+ print("โœ… Gemini Model loaded. No knowledge base found.")
661
+ else:
662
+ print("โš ๏ธ No Gemini API key found.")
663
+ except Exception as e:
664
+ print(f"โŒ Error during initialization: {e}")
 
 
 
665
 
666
  # --- Main AI Application Class ---
667
  class MyPharmaAI:
668
+ def __init__(self, gemini_model, vector_store_db):
669
+ self.router = RouterAgent(gemini_model)
 
670
  self.quotes = load_quotes()
671
+ self.vector_store = vector_store_db
672
+
673
+ def process_query(self, query, viva_state, chat_history):
674
+ file_context = ""
675
+ if self.vector_store:
676
+ # Search the knowledge base for relevant documents
677
+ relevant_docs = self.vector_store.similarity_search(query)
678
+ # Join the content of the relevant docs to create the context
679
+ file_context = "\n".join(doc.page_content for doc in relevant_docs)
680
+
681
+ # Pass the retrieved context to the router, maintaining the existing structure
682
+ return self.router.route_query(query, file_context, viva_state, chat_history)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
 
684
+ pharma_ai = MyPharmaAI(model, vector_store)
685
 
686
+ # --- Flask Routes ---
687
  @app.route('/')
688
  def index():
689
+ return render_template('index.html', greeting=get_greeting(), daily_quote=random.choice(pharma_ai.quotes))
 
 
 
 
 
 
 
690
 
691
  @app.route('/chat', methods=['POST'])
692
  def chat():
693
+ data = request.get_json()
694
+ query = data.get('query', '').strip()
695
+ if not query:
696
+ return jsonify({'success': False, 'error': 'Empty query'}), 400
 
 
 
 
 
 
 
697
 
698
+ chat_history = session.get('chat_history', [])
699
+ viva_state = session.get('viva_state', None)
700
+
701
+ try:
702
+ result = pharma_ai.process_query(query, viva_state, chat_history)
 
 
703
  if result.get('success'):
 
704
  chat_history.append({'role': 'user', 'parts': [query]})
705
  chat_history.append({'role': 'model', 'parts': [result.get('message', '')]})
706
+ session['chat_history'] = chat_history[-10:]
 
 
 
 
 
 
 
 
 
707
  return jsonify(result)
 
708
  except Exception as e:
709
  print(f"Error in /chat endpoint: {e}")
710
+ return jsonify({'success': False, 'message': f'Server error: {e}', 'agent_used': 'error'}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711
 
712
  # --- Main Execution ---
 
 
 
 
 
 
 
 
 
713
  if __name__ == '__main__':
714
+ # Ensure data folder exists for quotes.json
715
+ os.makedirs('data', exist_ok=True)
 
 
 
716
  port = int(os.environ.get('PORT', 7860))
 
 
 
 
 
 
717
  app.run(host='0.0.0.0', port=port)
templates/index.html CHANGED
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
@@ -330,18 +330,18 @@
330
  </head>
331
  <body>
332
  <div class="container">
333
- <!-- Header -->
334
  <div class="header">
335
  <h1>๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI</h1>
336
  <div class="subtitle">{{ greeting or "เคจเคฎเคธเฅเคคเฅ‡! Your Intelligent Pharmacy Study Companion" }}</div>
337
  </div>
338
 
339
- <!-- Daily Quote -->
340
  <div class="quote-container" id="quoteContainer">
341
  ๐Ÿ“ฟ {{ daily_quote or "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ - Knowledge is the supreme wealth" }}
342
  </div>
343
 
344
- <!-- Chat Container -->
345
  <div class="chat-container">
346
  <div class="chat-header">
347
  ๐Ÿ’ฌ Chat with Your AI Study Buddy
@@ -375,7 +375,7 @@
375
  <div id="fileList">
376
  </div>
377
  </div>
378
- <!-- Quick Action Buttons -->
379
  <div class="quick-actions">
380
  <button class="quick-btn" onclick="populateInput('Explain ')">๐Ÿ“Š Explain Topic</button>
381
  <button class="quick-btn" onclick="populateInput('What are the side effects of ')">โš—๏ธ Drug Info</button>
@@ -383,7 +383,7 @@
383
  <button class="quick-btn" onclick="populateInput('Mnemonic for ')">๐Ÿง  Mnemonics</button>
384
  </div>
385
 
386
- <!-- Input Container -->
387
  <div class="input-container">
388
  <input type="text"
389
  id="messageInput"
@@ -597,4 +597,191 @@
597
  });
598
  </script>
599
  </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  </html>
 
1
+ <!--<!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
 
330
  </head>
331
  <body>
332
  <div class="container">
333
+
334
  <div class="header">
335
  <h1>๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI</h1>
336
  <div class="subtitle">{{ greeting or "เคจเคฎเคธเฅเคคเฅ‡! Your Intelligent Pharmacy Study Companion" }}</div>
337
  </div>
338
 
339
+
340
  <div class="quote-container" id="quoteContainer">
341
  ๐Ÿ“ฟ {{ daily_quote or "เคตเคฟเคฆเฅเคฏเคพ เคงเคจเค‚ เคธเคฐเฅเคต เคงเคจ เคชเฅเคฐเคงเคพเคจเคฎเฅ - Knowledge is the supreme wealth" }}
342
  </div>
343
 
344
+
345
  <div class="chat-container">
346
  <div class="chat-header">
347
  ๐Ÿ’ฌ Chat with Your AI Study Buddy
 
375
  <div id="fileList">
376
  </div>
377
  </div>
378
+
379
  <div class="quick-actions">
380
  <button class="quick-btn" onclick="populateInput('Explain ')">๐Ÿ“Š Explain Topic</button>
381
  <button class="quick-btn" onclick="populateInput('What are the side effects of ')">โš—๏ธ Drug Info</button>
 
383
  <button class="quick-btn" onclick="populateInput('Mnemonic for ')">๐Ÿง  Mnemonics</button>
384
  </div>
385
 
386
+
387
  <div class="input-container">
388
  <input type="text"
389
  id="messageInput"
 
597
  });
598
  </script>
599
  </body>
600
+ </html>-->
601
+
602
+
603
+ <!DOCTYPE html>
604
+ <html lang="en">
605
+ <head>
606
+ <meta charset="UTF-8">
607
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
608
+ <title>MyPharma AI - Your Study Companion</title>
609
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
610
+ <style>
611
+ :root {
612
+ --saffron: #FF9933; --maroon: #800000; --gold: #FFD700;
613
+ --peacock-blue: #005F9E; --cream: #FFF8E7; --light-saffron: #FFE4B5;
614
+ }
615
+ * { margin: 0; padding: 0; box-sizing: border-box; }
616
+ body {
617
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
618
+ background: linear-gradient(135deg, var(--cream) 0%, var(--light-saffron) 100%);
619
+ min-height: 100vh;
620
+ display: flex; align-items: center; justify-content: center; padding: 20px;
621
+ }
622
+ .container {
623
+ max-width: 800px; margin: 0 auto; width: 100%;
624
+ height: 90vh; max-height: 850px; display: flex; flex-direction: column;
625
+ background: white; border-radius: 15px; box-shadow: 0 8px 25px rgba(0,0,0,0.1);
626
+ border: 3px solid var(--gold); overflow: hidden;
627
+ }
628
+ .header {
629
+ background: linear-gradient(135deg, var(--maroon) 0%, var(--peacock-blue) 100%);
630
+ color: white; padding: 20px; text-align: center;
631
+ }
632
+ .header h1 { font-size: 2em; margin-bottom: 5px; }
633
+ .header .subtitle { font-size: 1.1em; opacity: 0.9; }
634
+ .chat-container { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
635
+ .chat-messages { flex: 1; padding: 20px; overflow-y: auto; }
636
+ .message { margin-bottom: 20px; display: flex; max-width: 85%; animation: fadeIn 0.3s ease-in; }
637
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
638
+ .message.user { margin-left: auto; flex-direction: row-reverse; }
639
+ .message-bubble {
640
+ padding: 12px 18px; border-radius: 20px; word-wrap: break-word; line-height: 1.6;
641
+ }
642
+ .message.user .message-bubble {
643
+ background: linear-gradient(135deg, var(--peacock-blue) 0%, var(--maroon) 100%);
644
+ color: white; border-bottom-right-radius: 5px;
645
+ }
646
+ .message.bot .message-bubble {
647
+ background: linear-gradient(135deg, var(--light-saffron) 0%, var(--cream) 100%);
648
+ color: var(--maroon); border: 2px solid var(--saffron); border-bottom-left-radius: 5px;
649
+ }
650
+ .agent-badge {
651
+ display: inline-block; background: var(--gold); color: var(--maroon);
652
+ padding: 3px 8px; border-radius: 12px; font-size: 0.8em; font-weight: bold; margin-bottom: 8px;
653
+ }
654
+ .input-area { padding: 20px; background: var(--cream); border-top: 3px solid var(--gold); }
655
+ .quick-actions { display: flex; gap: 10px; margin-bottom: 15px; flex-wrap: wrap; }
656
+ .quick-btn {
657
+ background: white; color: var(--peacock-blue); border: 2px solid var(--peacock-blue);
658
+ padding: 8px 15px; border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.3s ease;
659
+ }
660
+ .quick-btn:hover { background: var(--peacock-blue); color: white; }
661
+ .input-container { display: flex; gap: 10px; align-items: center; }
662
+ #messageInput {
663
+ flex: 1; padding: 15px 20px; border: 2px solid var(--saffron);
664
+ border-radius: 25px; font-size: 16px; outline: none;
665
+ }
666
+ #sendBtn {
667
+ background: linear-gradient(135deg, var(--saffron) 0%, var(--gold) 100%);
668
+ color: var(--maroon); border: none; padding: 15px 25px; border-radius: 25px;
669
+ cursor: pointer; font-weight: bold; font-size: 16px; transition: all 0.3s ease;
670
+ }
671
+ #sendBtn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(255,153,51,0.4); }
672
+ .typing-indicator span { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background-color: #aaa; margin: 0 2px; animation: bounce 1s infinite; }
673
+ .typing-indicator span:nth-child(2) { animation-delay: 0.1s; }
674
+ .typing-indicator span:nth-child(3) { animation-delay: 0.2s; }
675
+ @keyframes bounce { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-6px); } }
676
+ </style>
677
+ </head>
678
+ <body>
679
+ <div class="container">
680
+ <div class="header">
681
+ <h1>๐Ÿ‡ฎ๐Ÿ‡ณ MyPharma AI</h1>
682
+ <div class="subtitle">{{ greeting }}</div>
683
+ </div>
684
+
685
+ <div class="chat-container">
686
+ <div class="chat-messages" id="chatMessages">
687
+ <div class="message bot">
688
+ <div class="message-bubble">
689
+ <div class="agent-badge">๐Ÿค– AI Study Buddy</div>
690
+ ๐Ÿ™ <strong>Namaste!</strong> I have studied the documents in the knowledge library. Ask me anything about your subjects, and I will find the answer for you.
691
+ </div>
692
+ </div>
693
+ </div>
694
+
695
+ <div class="input-area">
696
+ <div class="quick-actions">
697
+ <button class="quick-btn" onclick="populateInput('Explain ')">๐Ÿ“Š Explain Topic</button>
698
+ <button class="quick-btn" onclick="populateInput('What are the side effects of ')">โš—๏ธ Drug Info</button>
699
+ <button class="quick-btn" onclick="populateInput('Make a quiz on ')">โ“ Create Quiz</button>
700
+ </div>
701
+
702
+ <div class="input-container">
703
+ <input type="text" id="messageInput" placeholder="Ask about your documents..." onkeypress="handleKeyPress(event)">
704
+ <button id="sendBtn" onclick="sendMessage()">Send ๐Ÿ“จ</button>
705
+ </div>
706
+ </div>
707
+ </div>
708
+ </div>
709
+
710
+ <script>
711
+ let isProcessing = false;
712
+
713
+ async function sendMessage() {
714
+ const input = document.getElementById('messageInput');
715
+ const message = input.value.trim();
716
+ if (!message || isProcessing) return;
717
+
718
+ addMessage(message, 'user');
719
+ input.value = '';
720
+ showLoading(true);
721
+
722
+ try {
723
+ const response = await fetch('/chat', {
724
+ method: 'POST',
725
+ headers: { 'Content-Type': 'application/json' },
726
+ body: JSON.stringify({ query: message })
727
+ });
728
+ const data = await response.json();
729
+ showLoading(false);
730
+ if (data.success) {
731
+ addMessage(data.message, 'bot', data.agent_used);
732
+ } else {
733
+ addMessage(`โŒ Error: ${data.error || 'Something went wrong'}`, 'bot', 'error');
734
+ }
735
+ } catch (error) {
736
+ showLoading(false);
737
+ addMessage(`โŒ Connection error: ${error.message}`, 'bot', 'error');
738
+ }
739
+ }
740
+
741
+ function addMessage(text, sender, agentType = '') {
742
+ const messagesContainer = document.getElementById('chatMessages');
743
+ const messageDiv = document.createElement('div');
744
+ messageDiv.className = `message ${sender}`;
745
+ const agentIcons = { 'academic': '๐Ÿ“š Academic Agent', 'drug_info': '๐Ÿ’Š Drug Info Agent', 'quiz_generation': 'โ“ Quiz Master' };
746
+ const agentBadge = sender === 'bot' ? `<div class="agent-badge">${agentIcons[agentType] || '๐Ÿค– AI Assistant'}</div>` : '';
747
+ const formattedText = marked.parse(text || 'Sorry, I received an empty response.');
748
+ messageDiv.innerHTML = `<div class="message-bubble">${agentBadge}${formattedText}</div>`;
749
+ messagesContainer.appendChild(messageDiv);
750
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
751
+ }
752
+
753
+ function showLoading(show) {
754
+ document.getElementById('sendBtn').disabled = show;
755
+ const existingLoading = document.getElementById('loading-indicator');
756
+ if (existingLoading) existingLoading.remove();
757
+
758
+ if (show) {
759
+ const messagesContainer = document.getElementById('chatMessages');
760
+ const loadingDiv = document.createElement('div');
761
+ loadingDiv.className = 'message bot';
762
+ loadingDiv.id = 'loading-indicator';
763
+ loadingDiv.innerHTML = `<div class="message-bubble"><div class="typing-indicator"><span></span><span></span><span></span></div></div>`;
764
+ messagesContainer.appendChild(loadingDiv);
765
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
766
+ }
767
+ }
768
+
769
+ function handleKeyPress(event) {
770
+ if (event.key === 'Enter' && !event.shiftKey) {
771
+ event.preventDefault();
772
+ sendMessage();
773
+ }
774
+ }
775
+
776
+ function populateInput(templateText) {
777
+ const input = document.getElementById('messageInput');
778
+ input.value = templateText;
779
+ input.focus();
780
+ }
781
+
782
+ document.addEventListener('DOMContentLoaded', () => {
783
+ document.getElementById('messageInput').focus();
784
+ });
785
+ </script>
786
+ </body>
787
  </html>