Chia Woon Yap commited on
Commit
dfc0561
·
verified ·
1 Parent(s): afbd38c

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -554
app.py DELETED
@@ -1,554 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- """app
4
-
5
- Automatically generated by Colab.
6
-
7
- Original file is located at
8
- https://colab.research.google.com/drive/1pwwcBb5Zlw1DA3u5K8W8mjrwBTBWXc1L
9
- """
10
-
11
- import gradio as gr
12
- import numpy as np
13
- from transformers import pipeline
14
- import os
15
- import time
16
- import groq
17
- import uuid # For generating unique filenames
18
-
19
- # LangChain imports with compatibility handling
20
- try:
21
- from langchain_groq import ChatGroq
22
- from langchain_core.messages import HumanMessage
23
- from langchain.text_splitter import RecursiveCharacterTextSplitter
24
- from langchain_community.vectorstores import Chroma
25
- from langchain_community.embeddings import HuggingFaceEmbeddings
26
- from langchain_core.documents import Document
27
- except ImportError:
28
- # Fallback for older versions
29
- try:
30
- from langchain_groq import ChatGroq
31
- from langchain.schema import HumanMessage
32
- from langchain.text_splitter import RecursiveCharacterTextSplitter
33
- from langchain_community.vectorstores import Chroma
34
- from langchain_community.embeddings import HuggingFaceEmbeddings
35
- from langchain.docstore.document import Document
36
- except ImportError as e:
37
- print(f"Import warning: {e}")
38
- # Define fallback classes
39
- class HumanMessage:
40
- def __init__(self, content):
41
- self.content = content
42
- class Document:
43
- def __init__(self, page_content):
44
- self.page_content = page_content
45
-
46
- # Basic imports
47
- import chardet
48
- import fitz # PyMuPDF for PDFs
49
- import docx # python-docx for Word files
50
- import gtts # Google Text-to-Speech library
51
- from pptx import Presentation # python-pptx for PowerPoint files
52
- import re
53
-
54
- print("🚀 Initializing AI Tutor Application...")
55
-
56
- # Initialize Whisper for speech-to-text
57
- try:
58
- transcriber = pipeline(
59
- "automatic-speech-recognition",
60
- model="openai/whisper-base.en"
61
- )
62
- print("✅ Whisper model loaded successfully")
63
- except Exception as e:
64
- print(f"❌ Error loading Whisper: {e}")
65
- transcriber = None
66
-
67
- # Initialize Groq
68
- groq_api_key = os.getenv("GROQ_API_KEY")
69
- if groq_api_key:
70
- try:
71
- chat_model = ChatGroq(
72
- model_name="llama-3.3-70b-versatile",
73
- api_key=groq_api_key,
74
- temperature=0.7
75
- )
76
- CHAT_MODEL_AVAILABLE = True
77
- print("✅ Groq chat model initialized")
78
- except Exception as e:
79
- print(f"❌ Error initializing Groq: {e}")
80
- CHAT_MODEL_AVAILABLE = False
81
- else:
82
- print("⚠️ GROQ_API_KEY not found in environment variables")
83
- CHAT_MODEL_AVAILABLE = False
84
-
85
- # Initialize Vector Store
86
- try:
87
- os.makedirs("chroma_db", exist_ok=True)
88
- embedding_model = HuggingFaceEmbeddings(
89
- model_name="sentence-transformers/all-MiniLM-L6-v2"
90
- )
91
- vectorstore = Chroma(
92
- embedding_function=embedding_model,
93
- persist_directory="chroma_db"
94
- )
95
- VECTORSTORE_AVAILABLE = True
96
- print("✅ Vector store initialized")
97
- except Exception as e:
98
- print(f"❌ Error initializing vector store: {e}")
99
- VECTORSTORE_AVAILABLE = False
100
-
101
- # Application state
102
- chat_memory = []
103
-
104
- # Quiz generation prompt
105
- quiz_prompt = """
106
- You are an AI assistant specialized in education. Given document content, generate a quiz with 10 questions mixing multiple-choice and fill-in-the-blank.
107
-
108
- Requirements:
109
- - 10 total questions
110
- - Mix of MCQs and fill-in-the-blank
111
- - Based on key concepts from the document
112
- - Include answer key
113
- - Remove all markdown formatting
114
-
115
- Output format:
116
- 1. [Question text]
117
- Options (if MCQ): a) b) c) d)
118
- Answer: [Correct answer]
119
- """
120
-
121
- def clean_response(response):
122
- """Clean AI response from unwanted formatting."""
123
- if not response:
124
- return ""
125
-
126
- cleaned = re.sub(r"<think>.*?</think>", "", response, flags=re.DOTALL)
127
- cleaned = re.sub(r"(\*\*|\*|\[|\]|#+|\\)", "", cleaned)
128
- return cleaned.strip()
129
-
130
- def generate_quiz(content):
131
- """Generate quiz from document content."""
132
- if not CHAT_MODEL_AVAILABLE:
133
- return "❌ Chat model not available. Please check GROQ_API_KEY configuration."
134
-
135
- # Limit content length to avoid token limits
136
- if len(content) > 8000:
137
- content = content[:8000] + "... [content truncated for efficiency]"
138
-
139
- try:
140
- prompt = f"{quiz_prompt}\n\nDocument content:\n{content}"
141
- response = chat_model([HumanMessage(content=prompt)])
142
- return clean_response(response.content)
143
- except Exception as e:
144
- return f"❌ Error generating quiz: {str(e)}"
145
-
146
- def retrieve_documents(query):
147
- """Retrieve relevant documents for context."""
148
- if not VECTORSTORE_AVAILABLE or not query.strip():
149
- return []
150
-
151
- try:
152
- results = vectorstore.similarity_search(query, k=2)
153
- return [doc.page_content for doc in results]
154
- except Exception as e:
155
- print(f"Document retrieval error: {e}")
156
- return []
157
-
158
- def chat_with_groq(user_input, chat_history):
159
- """Handle chat interactions with the AI."""
160
- try:
161
- if not user_input.strip():
162
- return chat_history, "", None
163
-
164
- if not CHAT_MODEL_AVAILABLE:
165
- error_msg = "🤖 Chat service is currently unavailable. Please check your API configuration."
166
- chat_history.append({"role": "user", "content": user_input})
167
- chat_history.append({"role": "assistant", "content": error_msg})
168
- return chat_history, "", None
169
-
170
- # Get relevant context from documents
171
- relevant_docs = retrieve_documents(user_input)
172
- context = "\n".join(relevant_docs) if relevant_docs else "No specific context available."
173
-
174
- # Build enhanced prompt
175
- system_msg = "You are a helpful AI tutor. Provide accurate, educational, and concise responses. If you don't know something, admit it honestly."
176
- prompt = f"{system_msg}\n\nRelevant Context:\n{context}\n\nUser Question: {user_input}\n\nAssistant Response:"
177
-
178
- # Get AI response
179
- response = chat_model([HumanMessage(content=prompt)])
180
- cleaned_response = clean_response(response.content)
181
-
182
- # Update chat history
183
- chat_history.append({"role": "user", "content": user_input})
184
- chat_history.append({"role": "assistant", "content": cleaned_response})
185
-
186
- # Generate speech output
187
- audio_file = speech_playback(cleaned_response)
188
-
189
- return chat_history, "", audio_file
190
-
191
- except Exception as e:
192
- error_msg = f"❌ Error processing your request: {str(e)}"
193
- chat_history.append({"role": "user", "content": user_input})
194
- chat_history.append({"role": "assistant", "content": error_msg})
195
- return chat_history, "", None
196
-
197
- def speech_playback(text):
198
- """Convert text to speech using gTTS."""
199
- try:
200
- if not text or len(text.strip()) < 10:
201
- return None
202
-
203
- # Limit text length for audio generation
204
- if len(text) > 400:
205
- text = text[:400] + "..."
206
-
207
- unique_id = str(uuid.uuid4())[:8]
208
- audio_file = f"audio_{unique_id}.mp3"
209
-
210
- tts = gtts.gTTS(text=text, lang='en', slow=False)
211
- tts.save(audio_file)
212
-
213
- return audio_file
214
- except Exception as e:
215
- print(f"🔇 TTS Error: {e}")
216
- return None
217
-
218
- def detect_encoding(file_path):
219
- """Detect file encoding."""
220
- try:
221
- with open(file_path, "rb") as f:
222
- raw_data = f.read(4096)
223
- detected = chardet.detect(raw_data)
224
- return detected.get("encoding", "utf-8")
225
- except Exception:
226
- return "utf-8"
227
-
228
- def extract_text_from_pdf(pdf_path):
229
- """Extract text from PDF files."""
230
- try:
231
- doc = fitz.open(pdf_path)
232
- text = ""
233
- for page in doc:
234
- text += page.get_text()
235
- return text.strip() if text.strip() else "No extractable text found in PDF."
236
- except Exception as e:
237
- return f"PDF extraction error: {str(e)}"
238
-
239
- def extract_text_from_docx(docx_path):
240
- """Extract text from Word documents."""
241
- try:
242
- doc = docx.Document(docx_path)
243
- text = "\n".join([para.text for para in doc.paragraphs if para.text.strip()])
244
- return text.strip() if text.strip() else "No text found in Word document."
245
- except Exception as e:
246
- return f"Word extraction error: {str(e)}"
247
-
248
- def extract_text_from_pptx(pptx_path):
249
- """Extract text from PowerPoint files."""
250
- try:
251
- prs = Presentation(pptx_path)
252
- text = ""
253
- for slide in prs.slides:
254
- for shape in slide.shapes:
255
- if hasattr(shape, "text") and shape.text:
256
- text += shape.text + "\n"
257
- return text.strip() if text.strip() else "No text found in PowerPoint."
258
- except Exception as e:
259
- return f"PowerPoint extraction error: {str(e)}"
260
-
261
- def process_document(file):
262
- """Process uploaded document and generate quiz."""
263
- try:
264
- if not file:
265
- return "📁 Please upload a document file first."
266
-
267
- filename = file.name
268
- file_ext = os.path.splitext(filename)[-1].lower()
269
-
270
- print(f"Processing {file_ext} file: {filename}")
271
-
272
- # Extract text based on file type
273
- if file_ext == ".pdf":
274
- content = extract_text_from_pdf(filename)
275
- elif file_ext == ".docx":
276
- content = extract_text_from_docx(filename)
277
- elif file_ext == ".pptx":
278
- content = extract_text_from_pptx(filename)
279
- elif file_ext in [".txt", ".md"]:
280
- encoding = detect_encoding(filename)
281
- with open(filename, "r", encoding=encoding, errors="ignore") as f:
282
- content = f.read()
283
- else:
284
- return f"❌ Unsupported file type: {file_ext}. Please upload PDF, Word, PowerPoint, or text files."
285
-
286
- if not content or "error" in content.lower() or "no text" in content.lower():
287
- return f"❌ Could not extract meaningful content from this file. Error: {content}"
288
-
289
- # Store in vector database for future queries
290
- if VECTORSTORE_AVAILABLE and len(content) > 100:
291
- try:
292
- text_splitter = RecursiveCharacterTextSplitter(
293
- chunk_size=500,
294
- chunk_overlap=50
295
- )
296
- texts = text_splitter.split_text(content)
297
- documents = [Document(page_content=text) for text in texts]
298
- vectorstore.add_documents(documents)
299
- except Exception as e:
300
- print(f"Vector store addition warning: {e}")
301
-
302
- # Generate quiz from content
303
- quiz = generate_quiz(content)
304
-
305
- success_msg = f"""
306
- ✅ **Document Processed Successfully!**
307
-
308
- 📄 **File Type**: {file_ext.upper()}
309
- 📝 **Content Preview**: {content[:200]}...
310
-
311
- 📋 **Generated Quiz**:
312
- {quiz}
313
- """
314
-
315
- return success_msg
316
-
317
- except Exception as e:
318
- return f"❌ Error processing document: {str(e)}"
319
-
320
- def transcribe_audio(audio):
321
- """Transcribe audio to text using Whisper."""
322
- try:
323
- if audio is None:
324
- return "🎤 No audio detected. Please record or upload audio."
325
-
326
- if transcriber is None:
327
- return "🔇 Speech-to-text service is currently unavailable."
328
-
329
- sample_rate, audio_data = audio
330
-
331
- # Basic audio preprocessing
332
- if audio_data.ndim > 1:
333
- audio_data = np.mean(audio_data, axis=1) # Convert to mono
334
-
335
- audio_data = audio_data.astype(np.float32)
336
-
337
- # Normalize audio
338
- max_val = np.max(np.abs(audio_data))
339
- if max_val > 0:
340
- audio_data = audio_data / max_val
341
-
342
- # Check audio length
343
- audio_duration = len(audio_data) / sample_rate
344
- if audio_duration < 0.5:
345
- return "⏱️ Audio too short. Please record at least 1 second."
346
- if audio_duration > 30:
347
- return "⏱️ Audio too long. Please keep under 30 seconds."
348
-
349
- # Transcribe
350
- result = transcriber({"sampling_rate": sample_rate, "raw": audio_data})
351
- text = result.get("text", "").strip()
352
-
353
- if not text:
354
- return "🔇 No speech detected. Please try again with clearer audio."
355
-
356
- return f"🎤 Transcribed: {text}"
357
-
358
- except Exception as e:
359
- return f"❌ Transcription error: {str(e)}"
360
-
361
- def clear_chat():
362
- """Clear chat history."""
363
- chat_memory.clear()
364
- return [], None
365
-
366
- def create_interface():
367
- """Create and configure the Gradio interface."""
368
- with gr.Blocks(
369
- theme=gr.themes.Soft(),
370
- title="AI Tutor - Learning Assistant",
371
- css="""
372
- .gradio-container {
373
- max-width: 1200px !important;
374
- }
375
- """
376
- ) as app:
377
- gr.Markdown("""
378
- # 🎓 AI Tutor Assistant
379
- *Your personal learning companion with speech-to-text capabilities*
380
- """)
381
-
382
- # Main chat interface
383
- with gr.Tab("💬 AI Chatbot"):
384
- gr.Markdown("Chat with your AI tutor using text or voice input!")
385
-
386
- with gr.Row():
387
- with gr.Column(scale=3):
388
- chatbot = gr.Chatbot(
389
- label="Conversation History",
390
- height=500,
391
- type="messages",
392
- show_copy_button=True,
393
- avatar_images=("👤", "🤖")
394
- )
395
-
396
- with gr.Column(scale=1):
397
- audio_output = gr.Audio(
398
- label="Audio Response",
399
- type="filepath",
400
- visible=True,
401
- autoplay=True
402
- )
403
-
404
- with gr.Row():
405
- msg = gr.Textbox(
406
- label="Your message",
407
- placeholder="Type your question here or use voice input below...",
408
- scale=4,
409
- container=False,
410
- max_lines=3
411
- )
412
- send_btn = gr.Button("🚀 Send", scale=1, variant="primary")
413
-
414
- with gr.Row():
415
- with gr.Column(scale=1):
416
- audio_input = gr.Audio(
417
- sources=["microphone"],
418
- type="numpy",
419
- label="🎤 Record Audio Question",
420
- show_download_button=False
421
- )
422
-
423
- with gr.Accordion("💡 Tips for Better Experience", open=False):
424
- gr.Markdown("""
425
- **🎤 Voice Input Tips:**
426
- - Speak clearly in a quiet environment
427
- - Keep microphone 10-15 cm from your mouth
428
- - Record for 2-5 seconds for best results
429
-
430
- **📚 Document Tips:**
431
- - Upload PDF, Word, or PowerPoint files
432
- - Clear text documents work best
433
- - Process documents before asking questions about them
434
-
435
- **💬 Chat Tips:**
436
- - Ask specific questions for better answers
437
- - Use the clear button to start fresh conversations
438
- - The AI remembers context from uploaded documents
439
- """)
440
-
441
- with gr.Row():
442
- clear_btn = gr.Button("🧹 Clear Chat History", variant="secondary")
443
- gr.Button("🔄 Refresh Page").click(
444
- lambda: None,
445
- None,
446
- None,
447
- js="() => window.location.reload()"
448
- )
449
-
450
- # Document processing tab
451
- with gr.Tab("📚 Upload & Generate Quiz"):
452
- gr.Markdown("Upload your study materials and generate custom quizzes automatically!")
453
-
454
- with gr.Row():
455
- with gr.Column(scale=1):
456
- file_upload = gr.File(
457
- label="📁 Upload Study Materials",
458
- file_types=[".pdf", ".docx", ".pptx", ".txt", ".md"],
459
- file_count="single",
460
- height=100
461
- )
462
- process_btn = gr.Button("⚡ Process & Generate Quiz", variant="primary")
463
-
464
- gr.Markdown("""
465
- **Supported Formats:**
466
- - PDF documents
467
- - Word documents (.docx)
468
- - PowerPoint (.pptx)
469
- - Text files (.txt, .md)
470
- """)
471
-
472
- with gr.Column(scale=2):
473
- quiz_display = gr.Textbox(
474
- label="📋 Generated Quiz",
475
- lines=20,
476
- max_lines=25,
477
- show_copy_button=True,
478
- placeholder="Your generated quiz will appear here after processing a document..."
479
- )
480
-
481
- # Instructions tab
482
- with gr.Tab("ℹ️ How to Use"):
483
- gr.Markdown("""
484
- ## 🎓 Getting Started with AI Tutor
485
-
486
- ### 🎤 Using Voice Input
487
- 1. Go to the **AI Chatbot** tab
488
- 2. Click the microphone button
489
- 3. Allow microphone access in your browser
490
- 4. Speak clearly and wait for transcription
491
- 5. Review the text and click Send
492
-
493
- ### 📚 Processing Documents
494
- 1. Go to the **Upload & Generate Quiz** tab
495
- 2. Upload your study materials (PDF, Word, PowerPoint)
496
- 3. Click "Process & Generate Quiz"
497
- 4. Get instant quiz questions based on your content
498
- 5. Use the chat to ask questions about your documents
499
-
500
- ### 💬 Chat Features
501
- - Ask questions about uploaded documents
502
- - Get detailed explanations
503
- - Receive audio responses
504
- - Clear chat when needed
505
-
506
- ### 🔧 Technical Requirements
507
- - Modern web browser with microphone access
508
- - Stable internet connection
509
- - Groq API key (set as environment variable)
510
- """)
511
-
512
- # Event handlers
513
- send_btn.click(
514
- fn=chat_with_groq,
515
- inputs=[msg, chatbot],
516
- outputs=[chatbot, msg, audio_output]
517
- )
518
-
519
- msg.submit(
520
- fn=chat_with_groq,
521
- inputs=[msg, chatbot],
522
- outputs=[chatbot, msg, audio_output]
523
- )
524
-
525
- audio_input.change(
526
- fn=transcribe_audio,
527
- inputs=[audio_input],
528
- outputs=[msg]
529
- )
530
-
531
- process_btn.click(
532
- fn=process_document,
533
- inputs=[file_upload],
534
- outputs=[quiz_display]
535
- )
536
-
537
- clear_btn.click(
538
- fn=clear_chat,
539
- outputs=[chatbot, audio_output]
540
- )
541
-
542
- return app
543
-
544
- # Launch the application
545
- if __name__ == "__main__":
546
- print("🌈 Starting AI Tutor Application...")
547
- app = create_interface()
548
- app.launch(
549
- server_name="0.0.0.0",
550
- server_port=7860,
551
- share=False,
552
- show_error=True,
553
- debug=True
554
- )