shukdevdattaEX commited on
Commit
1a9c1a1
Β·
verified Β·
1 Parent(s): 7bae2d0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +6 -118
app.py CHANGED
@@ -12,14 +12,13 @@ from pathlib import Path
12
  try:
13
  from together import Together
14
  import PyPDF2
15
- from PIL import Image
16
  import speech_recognition as sr
17
  import io
18
  import subprocess
19
  import sys
20
  except ImportError as e:
21
  print(f"Missing dependency: {e}")
22
- print("Install with: pip install together PyPDF2 pillow speechrecognition pyaudio")
23
  sys.exit(1)
24
 
25
  class ConversationMemory:
@@ -34,7 +33,7 @@ class ConversationMemory:
34
  interaction = {
35
  "timestamp": datetime.now().isoformat(),
36
  "input_type": input_type,
37
- "content": content[:500] + "..." if len(content) > 500 else content, # Truncate for memory
38
  "response": response[:1000] + "..." if len(response) > 1000 else response,
39
  "metadata": metadata or {}
40
  }
@@ -47,25 +46,22 @@ class ConversationMemory:
47
  self.session_data = {}
48
 
49
  def get_relevant_context(self, query: str, limit: int = 3) -> List[Dict]:
50
- # Simple relevance scoring - in production, use embeddings
51
  relevant = []
52
  query_lower = query.lower()
53
 
54
- for conv in reversed(self.conversations[-10:]): # Check last 10 interactions
55
  score = 0
56
  content_lower = conv["content"].lower()
57
  response_lower = conv["response"].lower()
58
 
59
- # Simple keyword matching
60
  for word in query_lower.split():
61
- if len(word) > 3: # Skip short words
62
  if word in content_lower or word in response_lower:
63
  score += 1
64
 
65
  if score > 0:
66
  relevant.append((score, conv))
67
 
68
- # Sort by relevance and return top results
69
  relevant.sort(key=lambda x: x[0], reverse=True)
70
  return [conv for score, conv in relevant[:limit]]
71
 
@@ -101,33 +97,6 @@ class NexusAI:
101
  except Exception as e:
102
  return f"Error reading PDF: {str(e)}"
103
 
104
- def analyze_image(self, image_path: str) -> str:
105
- """Analyze image and return description"""
106
- try:
107
- with Image.open(image_path) as img:
108
- # Basic image analysis - in production, use vision models
109
- width, height = img.size
110
- mode = img.mode
111
- format_type = img.format
112
-
113
- description = f"Image Analysis:\n"
114
- description += f"- Dimensions: {width}x{height} pixels\n"
115
- description += f"- Color mode: {mode}\n"
116
- description += f"- Format: {format_type}\n"
117
-
118
- # Simple color analysis
119
- if mode == "RGB":
120
- # Get dominant colors (simplified)
121
- img_small = img.resize((50, 50))
122
- colors = img_small.getcolors(2500)
123
- if colors:
124
- dominant_color = max(colors, key=lambda x: x[0])[1]
125
- description += f"- Dominant color (RGB): {dominant_color}\n"
126
-
127
- return description
128
- except Exception as e:
129
- return f"Error analyzing image: {str(e)}"
130
-
131
  def transcribe_audio(self, audio_path: str) -> str:
132
  """Transcribe audio to text"""
133
  try:
@@ -143,12 +112,10 @@ class NexusAI:
143
  """Execute code safely (basic implementation)"""
144
  try:
145
  if language.lower() == "python":
146
- # Create a temporary file
147
  with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
148
  f.write(code)
149
  temp_file = f.name
150
 
151
- # Execute with timeout
152
  try:
153
  result = subprocess.run([sys.executable, temp_file],
154
  capture_output=True, text=True, timeout=10)
@@ -169,14 +136,12 @@ class NexusAI:
169
  """Build context messages for the AI model"""
170
  messages = []
171
 
172
- # Add system message
173
  system_msg = """You are Nexus AI, a creative multimodal assistant that helps users across different types of content.
174
- You excel at connecting insights across text, documents, images, voice, and code. Always provide helpful,
175
  contextual responses that build on previous interactions when relevant."""
176
 
177
  messages.append({"role": "system", "content": system_msg})
178
 
179
- # Add relevant conversation history
180
  relevant_context = self.memory.get_relevant_context(user_input)
181
  for context in relevant_context:
182
  messages.append({
@@ -184,7 +149,6 @@ class NexusAI:
184
  "content": f"[Previous {context['input_type']} interaction] {context['response'][:200]}..."
185
  })
186
 
187
- # Build current user message
188
  current_content = f"Input Type: {input_type}\n\n"
189
 
190
  if extracted_content:
@@ -213,7 +177,6 @@ class NexusAI:
213
 
214
  ai_response = response.choices[0].message.content
215
 
216
- # Store interaction in memory
217
  self.memory.add_interaction(
218
  input_type=input_type,
219
  content=user_input + ("\n" + extracted_content if extracted_content else ""),
@@ -225,7 +188,6 @@ class NexusAI:
225
  except Exception as e:
226
  return f"❌ Error generating response: {str(e)}"
227
 
228
- # Initialize the AI assistant
229
  nexus_ai = NexusAI()
230
 
231
  def initialize_api_key(api_key: str) -> Tuple[str, str]:
@@ -255,7 +217,6 @@ def process_pdf_input(pdf_file, user_question: str, api_key_status: str) -> str:
255
  if pdf_file is None:
256
  return "Please upload a PDF file first!"
257
 
258
- # Extract text from PDF - pdf_file is already a file path string
259
  extracted_text = nexus_ai.extract_text_from_pdf(pdf_file)
260
 
261
  if user_question.strip():
@@ -263,22 +224,6 @@ def process_pdf_input(pdf_file, user_question: str, api_key_status: str) -> str:
263
  else:
264
  return nexus_ai.generate_response("Please summarize this document", "pdf", extracted_text)
265
 
266
- def process_image_input(image_file, user_question: str, api_key_status: str) -> str:
267
- """Process image input with question"""
268
- if api_key_status != "success":
269
- return "❌ Please initialize your Together AI API key first!"
270
-
271
- if image_file is None:
272
- return "Please upload an image file first!"
273
-
274
- # Analyze image - image_file is already a file path string
275
- image_analysis = nexus_ai.analyze_image(image_file)
276
-
277
- if user_question.strip():
278
- return nexus_ai.generate_response(user_question, "image", image_analysis)
279
- else:
280
- return nexus_ai.generate_response("What can you tell me about this image?", "image", image_analysis)
281
-
282
  def process_audio_input(audio_file, user_question: str, api_key_status: str) -> str:
283
  """Process audio input with question"""
284
  if api_key_status != "success":
@@ -287,7 +232,6 @@ def process_audio_input(audio_file, user_question: str, api_key_status: str) ->
287
  if audio_file is None:
288
  return "Please upload an audio file first!"
289
 
290
- # Transcribe audio - audio_file is already a file path string
291
  transcribed_text = nexus_ai.transcribe_audio(audio_file)
292
 
293
  if user_question.strip():
@@ -324,7 +268,7 @@ def show_conversation_history() -> str:
324
  return "No conversation history yet. Start chatting to build your knowledge base!"
325
 
326
  history = "## πŸ“š Recent Conversation History\n\n"
327
- for i, conv in enumerate(nexus_ai.memory.conversations[-10:], 1): # Show last 10
328
  timestamp = datetime.fromisoformat(conv["timestamp"]).strftime("%H:%M:%S")
329
  history += f"**{i}. [{conv['input_type'].upper()}] {timestamp}**\n"
330
  history += f"Input: {conv['content'][:100]}{'...' if len(conv['content']) > 100 else ''}\n"
@@ -337,20 +281,17 @@ def clear_conversation_history() -> str:
337
  nexus_ai.memory.clear_history()
338
  return "βœ… Conversation history has been cleared!"
339
 
340
- # Create the Gradio interface
341
  def create_nexus_interface():
342
  with gr.Blocks(
343
  theme=gr.themes.Soft(),
344
  title="Nexus AI Assistant",
345
  css="""
346
- /* Center the main container */
347
  .gradio-container {
348
  max-width: 1400px !important;
349
  margin: 0 auto !important;
350
  padding: 20px !important;
351
  }
352
 
353
- /* API Key section styling */
354
  .api-key-section {
355
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
356
  border-radius: 12px;
@@ -360,7 +301,6 @@ def create_nexus_interface():
360
  border: 1px solid #e1e8ed;
361
  }
362
 
363
- /* Button styling */
364
  .primary-button {
365
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
366
  border: none !important;
@@ -395,20 +335,17 @@ def create_nexus_interface():
395
  transition: all 0.3s ease !important;
396
  }
397
 
398
- /* Tab styling */
399
  .tab-nav button {
400
  border-radius: 8px 8px 0 0 !important;
401
  font-weight: 500 !important;
402
  padding: 12px 20px !important;
403
  }
404
 
405
- /* Text area with scrollbar */
406
  .scrollable-textarea textarea {
407
  overflow-y: auto !important;
408
  resize: vertical !important;
409
  }
410
 
411
- /* Card styling for better visual separation */
412
  .input-card {
413
  background: #ffffff;
414
  border-radius: 10px;
@@ -426,7 +363,6 @@ def create_nexus_interface():
426
  border: 1px solid #e9ecef;
427
  }
428
 
429
- /* Header gradient animation */
430
  .header-gradient {
431
  background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #667eea 100%);
432
  background-size: 200% 200%;
@@ -439,7 +375,6 @@ def create_nexus_interface():
439
  100% { background-position: 0% 50%; }
440
  }
441
 
442
- /* Status indicator */
443
  .status-success {
444
  border-left: 4px solid #00b894 !important;
445
  background-color: #d1f2eb !important;
@@ -450,7 +385,6 @@ def create_nexus_interface():
450
  background-color: #fadbd8 !important;
451
  }
452
 
453
- /* Responsive design */
454
  @media (max-width: 768px) {
455
  .gradio-container {
456
  padding: 10px !important;
@@ -459,7 +393,6 @@ def create_nexus_interface():
459
  """
460
  ) as app:
461
 
462
- # Header
463
  gr.HTML("""
464
  <div class="header-gradient" style="text-align: center; padding: 30px; border-radius: 15px; margin-bottom: 25px;">
465
  <h1 style="color: white; margin: 0; font-size: 3em; font-weight: 700; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">
@@ -471,7 +404,6 @@ def create_nexus_interface():
471
  </div>
472
  """)
473
 
474
- # API Key Section
475
  with gr.Group(elem_classes=["api-key-section"]):
476
  gr.HTML("<h3 style='margin-top: 0; color: #2d3748;'>πŸ”‘ API Configuration</h3>")
477
  with gr.Row():
@@ -496,13 +428,10 @@ def create_nexus_interface():
496
  elem_classes=["scrollable-textarea"]
497
  )
498
 
499
- # Hidden state to track API key status
500
  api_key_state = gr.State(value="not_initialized")
501
 
502
- # Main Interface Tabs
503
  with gr.Tabs():
504
 
505
- # Text Chat Tab
506
  with gr.Tab("πŸ’¬ Text Chat"):
507
  with gr.Row():
508
  with gr.Column(scale=1, elem_classes=["input-card"]):
@@ -526,7 +455,6 @@ def create_nexus_interface():
526
  elem_classes=["scrollable-textarea"]
527
  )
528
 
529
- # PDF Analysis Tab
530
  with gr.Tab("πŸ“„ PDF Analysis"):
531
  with gr.Row():
532
  with gr.Column(scale=1, elem_classes=["input-card"]):
@@ -554,35 +482,6 @@ def create_nexus_interface():
554
  elem_classes=["scrollable-textarea"]
555
  )
556
 
557
- # Image Analysis Tab
558
- with gr.Tab("πŸ–ΌοΈ Image Analysis"):
559
- with gr.Row():
560
- with gr.Column(scale=1, elem_classes=["input-card"]):
561
- image_file = gr.Image(
562
- label="Upload Image",
563
- type="filepath"
564
- )
565
- image_question = gr.Textbox(
566
- label="Question about Image (optional)",
567
- placeholder="What would you like to know about this image?",
568
- lines=3,
569
- elem_classes=["scrollable-textarea"]
570
- )
571
- image_btn = gr.Button(
572
- "Analyze Image",
573
- variant="primary",
574
- elem_classes=["primary-button"]
575
- )
576
-
577
- with gr.Column(scale=1, elem_classes=["output-card"]):
578
- image_output = gr.Textbox(
579
- label="Analysis Result",
580
- lines=12,
581
- interactive=False,
582
- elem_classes=["scrollable-textarea"]
583
- )
584
-
585
- # Voice Processing Tab
586
  with gr.Tab("🎀 Voice Processing"):
587
  with gr.Row():
588
  with gr.Column(scale=1, elem_classes=["input-card"]):
@@ -610,7 +509,6 @@ def create_nexus_interface():
610
  elem_classes=["scrollable-textarea"]
611
  )
612
 
613
- # Code Executor Tab
614
  with gr.Tab("⚑ Code Executor"):
615
  with gr.Row():
616
  with gr.Column(scale=1, elem_classes=["input-card"]):
@@ -646,7 +544,6 @@ def create_nexus_interface():
646
  elem_classes=["scrollable-textarea"]
647
  )
648
 
649
- # Memory & History Tab
650
  with gr.Tab("🧠 Memory & History"):
651
  with gr.Column(elem_classes=["input-card"]):
652
  gr.HTML("<h3 style='margin-top: 0;'>Conversation Memory</h3>")
@@ -673,7 +570,6 @@ def create_nexus_interface():
673
  elem_classes=["scrollable-textarea"]
674
  )
675
 
676
- # Event handlers
677
  def update_api_status(api_key):
678
  message, status = initialize_api_key(api_key)
679
  if status == "success":
@@ -699,12 +595,6 @@ def create_nexus_interface():
699
  outputs=[pdf_output]
700
  )
701
 
702
- image_btn.click(
703
- fn=process_image_input,
704
- inputs=[image_file, image_question, api_key_state],
705
- outputs=[image_output]
706
- )
707
-
708
  audio_btn.click(
709
  fn=process_audio_input,
710
  inputs=[audio_file, audio_question, api_key_state],
@@ -727,7 +617,6 @@ def create_nexus_interface():
727
  outputs=[history_output]
728
  )
729
 
730
- # Footer
731
  gr.HTML("""
732
  <div style="text-align: center; padding: 25px; margin-top: 30px; border-top: 2px solid #e9ecef; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 10px;">
733
  <p style="color: #495057; font-size: 1.1em; margin: 0;">
@@ -741,7 +630,6 @@ def create_nexus_interface():
741
 
742
  return app
743
 
744
- # Launch the application
745
  if __name__ == "__main__":
746
  app = create_nexus_interface()
747
  app.launch(
 
12
  try:
13
  from together import Together
14
  import PyPDF2
 
15
  import speech_recognition as sr
16
  import io
17
  import subprocess
18
  import sys
19
  except ImportError as e:
20
  print(f"Missing dependency: {e}")
21
+ print("Install with: pip install together PyPDF2 speechrecognition pyaudio")
22
  sys.exit(1)
23
 
24
  class ConversationMemory:
 
33
  interaction = {
34
  "timestamp": datetime.now().isoformat(),
35
  "input_type": input_type,
36
+ "content": content[:500] + "..." if len(content) > 500 else content,
37
  "response": response[:1000] + "..." if len(response) > 1000 else response,
38
  "metadata": metadata or {}
39
  }
 
46
  self.session_data = {}
47
 
48
  def get_relevant_context(self, query: str, limit: int = 3) -> List[Dict]:
 
49
  relevant = []
50
  query_lower = query.lower()
51
 
52
+ for conv in reversed(self.conversations[-10:]):
53
  score = 0
54
  content_lower = conv["content"].lower()
55
  response_lower = conv["response"].lower()
56
 
 
57
  for word in query_lower.split():
58
+ if len(word) > 3:
59
  if word in content_lower or word in response_lower:
60
  score += 1
61
 
62
  if score > 0:
63
  relevant.append((score, conv))
64
 
 
65
  relevant.sort(key=lambda x: x[0], reverse=True)
66
  return [conv for score, conv in relevant[:limit]]
67
 
 
97
  except Exception as e:
98
  return f"Error reading PDF: {str(e)}"
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  def transcribe_audio(self, audio_path: str) -> str:
101
  """Transcribe audio to text"""
102
  try:
 
112
  """Execute code safely (basic implementation)"""
113
  try:
114
  if language.lower() == "python":
 
115
  with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
116
  f.write(code)
117
  temp_file = f.name
118
 
 
119
  try:
120
  result = subprocess.run([sys.executable, temp_file],
121
  capture_output=True, text=True, timeout=10)
 
136
  """Build context messages for the AI model"""
137
  messages = []
138
 
 
139
  system_msg = """You are Nexus AI, a creative multimodal assistant that helps users across different types of content.
140
+ You excel at connecting insights across text, documents, voice, and code. Always provide helpful,
141
  contextual responses that build on previous interactions when relevant."""
142
 
143
  messages.append({"role": "system", "content": system_msg})
144
 
 
145
  relevant_context = self.memory.get_relevant_context(user_input)
146
  for context in relevant_context:
147
  messages.append({
 
149
  "content": f"[Previous {context['input_type']} interaction] {context['response'][:200]}..."
150
  })
151
 
 
152
  current_content = f"Input Type: {input_type}\n\n"
153
 
154
  if extracted_content:
 
177
 
178
  ai_response = response.choices[0].message.content
179
 
 
180
  self.memory.add_interaction(
181
  input_type=input_type,
182
  content=user_input + ("\n" + extracted_content if extracted_content else ""),
 
188
  except Exception as e:
189
  return f"❌ Error generating response: {str(e)}"
190
 
 
191
  nexus_ai = NexusAI()
192
 
193
  def initialize_api_key(api_key: str) -> Tuple[str, str]:
 
217
  if pdf_file is None:
218
  return "Please upload a PDF file first!"
219
 
 
220
  extracted_text = nexus_ai.extract_text_from_pdf(pdf_file)
221
 
222
  if user_question.strip():
 
224
  else:
225
  return nexus_ai.generate_response("Please summarize this document", "pdf", extracted_text)
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  def process_audio_input(audio_file, user_question: str, api_key_status: str) -> str:
228
  """Process audio input with question"""
229
  if api_key_status != "success":
 
232
  if audio_file is None:
233
  return "Please upload an audio file first!"
234
 
 
235
  transcribed_text = nexus_ai.transcribe_audio(audio_file)
236
 
237
  if user_question.strip():
 
268
  return "No conversation history yet. Start chatting to build your knowledge base!"
269
 
270
  history = "## πŸ“š Recent Conversation History\n\n"
271
+ for i, conv in enumerate(nexus_ai.memory.conversations[-10:], 1):
272
  timestamp = datetime.fromisoformat(conv["timestamp"]).strftime("%H:%M:%S")
273
  history += f"**{i}. [{conv['input_type'].upper()}] {timestamp}**\n"
274
  history += f"Input: {conv['content'][:100]}{'...' if len(conv['content']) > 100 else ''}\n"
 
281
  nexus_ai.memory.clear_history()
282
  return "βœ… Conversation history has been cleared!"
283
 
 
284
  def create_nexus_interface():
285
  with gr.Blocks(
286
  theme=gr.themes.Soft(),
287
  title="Nexus AI Assistant",
288
  css="""
 
289
  .gradio-container {
290
  max-width: 1400px !important;
291
  margin: 0 auto !important;
292
  padding: 20px !important;
293
  }
294
 
 
295
  .api-key-section {
296
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
297
  border-radius: 12px;
 
301
  border: 1px solid #e1e8ed;
302
  }
303
 
 
304
  .primary-button {
305
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
306
  border: none !important;
 
335
  transition: all 0.3s ease !important;
336
  }
337
 
 
338
  .tab-nav button {
339
  border-radius: 8px 8px 0 0 !important;
340
  font-weight: 500 !important;
341
  padding: 12px 20px !important;
342
  }
343
 
 
344
  .scrollable-textarea textarea {
345
  overflow-y: auto !important;
346
  resize: vertical !important;
347
  }
348
 
 
349
  .input-card {
350
  background: #ffffff;
351
  border-radius: 10px;
 
363
  border: 1px solid #e9ecef;
364
  }
365
 
 
366
  .header-gradient {
367
  background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #667eea 100%);
368
  background-size: 200% 200%;
 
375
  100% { background-position: 0% 50%; }
376
  }
377
 
 
378
  .status-success {
379
  border-left: 4px solid #00b894 !important;
380
  background-color: #d1f2eb !important;
 
385
  background-color: #fadbd8 !important;
386
  }
387
 
 
388
  @media (max-width: 768px) {
389
  .gradio-container {
390
  padding: 10px !important;
 
393
  """
394
  ) as app:
395
 
 
396
  gr.HTML("""
397
  <div class="header-gradient" style="text-align: center; padding: 30px; border-radius: 15px; margin-bottom: 25px;">
398
  <h1 style="color: white; margin: 0; font-size: 3em; font-weight: 700; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">
 
404
  </div>
405
  """)
406
 
 
407
  with gr.Group(elem_classes=["api-key-section"]):
408
  gr.HTML("<h3 style='margin-top: 0; color: #2d3748;'>πŸ”‘ API Configuration</h3>")
409
  with gr.Row():
 
428
  elem_classes=["scrollable-textarea"]
429
  )
430
 
 
431
  api_key_state = gr.State(value="not_initialized")
432
 
 
433
  with gr.Tabs():
434
 
 
435
  with gr.Tab("πŸ’¬ Text Chat"):
436
  with gr.Row():
437
  with gr.Column(scale=1, elem_classes=["input-card"]):
 
455
  elem_classes=["scrollable-textarea"]
456
  )
457
 
 
458
  with gr.Tab("πŸ“„ PDF Analysis"):
459
  with gr.Row():
460
  with gr.Column(scale=1, elem_classes=["input-card"]):
 
482
  elem_classes=["scrollable-textarea"]
483
  )
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  with gr.Tab("🎀 Voice Processing"):
486
  with gr.Row():
487
  with gr.Column(scale=1, elem_classes=["input-card"]):
 
509
  elem_classes=["scrollable-textarea"]
510
  )
511
 
 
512
  with gr.Tab("⚑ Code Executor"):
513
  with gr.Row():
514
  with gr.Column(scale=1, elem_classes=["input-card"]):
 
544
  elem_classes=["scrollable-textarea"]
545
  )
546
 
 
547
  with gr.Tab("🧠 Memory & History"):
548
  with gr.Column(elem_classes=["input-card"]):
549
  gr.HTML("<h3 style='margin-top: 0;'>Conversation Memory</h3>")
 
570
  elem_classes=["scrollable-textarea"]
571
  )
572
 
 
573
  def update_api_status(api_key):
574
  message, status = initialize_api_key(api_key)
575
  if status == "success":
 
595
  outputs=[pdf_output]
596
  )
597
 
 
 
 
 
 
 
598
  audio_btn.click(
599
  fn=process_audio_input,
600
  inputs=[audio_file, audio_question, api_key_state],
 
617
  outputs=[history_output]
618
  )
619
 
 
620
  gr.HTML("""
621
  <div style="text-align: center; padding: 25px; margin-top: 30px; border-top: 2px solid #e9ecef; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 10px;">
622
  <p style="color: #495057; font-size: 1.1em; margin: 0;">
 
630
 
631
  return app
632
 
 
633
  if __name__ == "__main__":
634
  app = create_nexus_interface()
635
  app.launch(