ha7naa commited on
Commit
b7e6669
Β·
verified Β·
1 Parent(s): fcaa8a2

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +211 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pyttsx3
3
+ import PyPDF2
4
+ import os
5
+ import time
6
+ import uuid
7
+ import numpy as np
8
+ from gtts import gTTS
9
+ from playsound import playsound
10
+ from sentence_transformers import SentenceTransformer
11
+ import chromadb
12
+ from groq import Groq
13
+
14
+
15
+ import os
16
+ from dotenv import load_dotenv
17
+ load_dotenv()
18
+ GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
19
+
20
+ groq_client = Groq(api_key=GROQ_API_KEY)
21
+ model = SentenceTransformer('all-MiniLM-L6-v2')
22
+ client = chromadb.Client()
23
+ collection = client.create_collection("echo_study")
24
+ PDF_FOLDER = "pdfs"
25
+ loaded_files = {}
26
+ pdf_texts = {}
27
+ current_file = {"name": None}
28
+
29
+
30
+ QUESTIONS = {
31
+ "embedded systems": [
32
+ "How does the lecture define an Embedded System?",
33
+ "What are the primary resource constraints in embedded systems?",
34
+ "How do embedded systems interact with the physical world?"
35
+ ],
36
+ "dynamic programming": [
37
+ "What is the simplest way to define Dynamic Programming?",
38
+ "How many times does DP solve each subproblem?",
39
+ "What is the simple formula for Dynamic Programming"
40
+ ],
41
+ "mongol history": [
42
+ "Why did the Empire's huge size lead to its fall?",
43
+ "What was the original goal of the British East India Company?"
44
+ ]
45
+ }
46
+
47
+
48
+ def speak_system(text):
49
+ engine = pyttsx3.init()
50
+ engine.setProperty('rate', 140)
51
+ engine.say(text)
52
+ engine.runAndWait()
53
+
54
+ def speak_user(text):
55
+ audio_path = f"C:/Users/hnaal/Desktop/Echo_study/user_{uuid.uuid4()}.mp3"
56
+ tts = gTTS(text=text, lang='en')
57
+ tts.save(audio_path)
58
+ playsound(audio_path)
59
+ os.remove(audio_path)
60
+
61
+
62
+ def load_all_pdfs():
63
+ speak_system("Welcome back! Ready to tackle your studies?")
64
+ yield "⏳ Processing Embeddings..."
65
+ for filename in os.listdir(PDF_FOLDER):
66
+ if filename.endswith(".pdf"):
67
+ filepath = os.path.join(PDF_FOLDER, filename)
68
+ with open(filepath, "rb") as f:
69
+ reader = PyPDF2.PdfReader(f)
70
+ text = ""
71
+ for page in reader.pages:
72
+ text += page.extract_text()
73
+ pdf_texts[filename] = text
74
+ embedding = model.encode(text[:2000]).tolist()
75
+ collection.add(
76
+ documents=[text[:2000]],
77
+ embeddings=[embedding],
78
+ ids=[filename],
79
+ metadatas=[{"source": filename}]
80
+ )
81
+ name = filename.replace(".pdf", "").replace("_", " ").lower()
82
+ loaded_files[name] = filename
83
+ yield f"⏳ Processing: {filename}..."
84
+ speak_system("All files loaded successfully.")
85
+ yield "βœ… Loaded: " + ", ".join(loaded_files.keys())
86
+
87
+
88
+
89
+ def update_questions(pdf_name):
90
+ pdf_key = pdf_name.lower()
91
+ for key in QUESTIONS:
92
+ if any(word in pdf_key for word in key.split()):
93
+ return gr.Dropdown(choices=QUESTIONS[key], value=QUESTIONS[key][0])
94
+ return gr.Dropdown(choices=[], value=None)
95
+
96
+ def find_best_chunk(question, pdf_text):
97
+ chunks = []
98
+ words = pdf_text.split()
99
+ for i in range(0, len(words), 80):
100
+ chunk = " ".join(words[i:i+80])
101
+ chunks.append(chunk)
102
+ if not chunks:
103
+ return pdf_text[:500]
104
+ question_embedding = model.encode(question)
105
+ chunk_embeddings = [model.encode(chunk) for chunk in chunks]
106
+ similarities = [
107
+ np.dot(question_embedding, ce) / (np.linalg.norm(question_embedding) * np.linalg.norm(ce))
108
+ for ce in chunk_embeddings
109
+ ]
110
+ best_idx = similarities.index(max(similarities))
111
+ return chunks[best_idx]
112
+
113
+
114
+ def ask_groq(question, context, file_name):
115
+ response = groq_client.chat.completions.create(
116
+ model="llama-3.3-70b-versatile",
117
+ messages=[
118
+ {
119
+ "role": "system",
120
+ "content": f"""You are EchoStudy, a warm and encouraging study partner for blind students.
121
+ When answering:
122
+ 1. Start with a different warm phrase each time, like: Great question!, Interesting!, Good thinking!, Let me help you with that!
123
+ 2. Use a simple real-life analogy to explain if needed.
124
+ 3. Answer in 2 short sentences only, very simple and brief.
125
+ 4. Avoid markdown symbols like stars or hashtags.
126
+ 5. End with: Would you like more details?"""
127
+ },
128
+ {
129
+ "role": "user",
130
+ "content": f"Context from {file_name}: {context}\n\nQuestion: {question}"
131
+ }
132
+ ],
133
+ max_tokens=80
134
+ )
135
+ return response.choices[0].message.content
136
+
137
+
138
+ def demo_interaction(pdf_name, question):
139
+ log = ""
140
+ if pdf_name.strip().lower() != current_file["name"]:
141
+ speak_system("Please say the name of your PDF file.")
142
+ log += "πŸ”Š System: Please say the name of your PDF file.\n"
143
+ yield log, ""
144
+ time.sleep(1)
145
+ speak_user(pdf_name)
146
+ log += f"🎀 Student: {pdf_name}\n"
147
+ yield log, ""
148
+ time.sleep(1)
149
+ found = None
150
+ for name in loaded_files:
151
+ if any(word.lower() in name.lower() for word in pdf_name.split()):
152
+ found = name
153
+ break
154
+ if not found:
155
+ speak_system("Sorry, I could not find that file.")
156
+ log += "πŸ”Š System: Sorry, I could not find that file.\n"
157
+ yield log, "Not found"
158
+ return
159
+ current_file["name"] = pdf_name.strip().lower()
160
+ speak_system(f"Found {found}. Ready for your question.")
161
+ log += f"πŸ”Š System: Found {found}. Ready for your question.\n"
162
+ yield log, found
163
+ time.sleep(1)
164
+ else:
165
+ found = None
166
+ for name in loaded_files:
167
+ if any(word.lower() in name.lower() for word in pdf_name.split()):
168
+ found = name
169
+ break
170
+ if not found:
171
+ yield "File not found.", "Not found"
172
+ return
173
+ speak_user(question)
174
+ log += f"🎀 Student: {question}\n"
175
+ yield log, found
176
+ time.sleep(1)
177
+ target_file = loaded_files[found]
178
+ pdf_text = pdf_texts[target_file]
179
+ context = find_best_chunk(question, pdf_text)
180
+ answer = ask_groq(question, context, found)
181
+ speak_system(answer)
182
+ log += f"πŸ”Š System: {answer}\n"
183
+ yield log, found
184
+
185
+
186
+
187
+ with gr.Blocks() as app:
188
+ gr.Markdown("# πŸŽ“ Echo Study – Voice-First Study Assistant")
189
+ gr.Markdown("β™Ώ Designed for visually impaired students")
190
+ with gr.Row():
191
+ load_btn = gr.Button("πŸ“‚ Load Study Materials")
192
+ load_status = gr.Textbox(label="Status")
193
+ gr.Markdown("### 🎀 Demo Interaction")
194
+ pdf_input = gr.Dropdown(
195
+ choices=["embedded systems", "dynamic programming", "mongol history"],
196
+ value="embedded systems",
197
+ label="πŸ“„ Select PDF"
198
+ )
199
+ question_input = gr.Dropdown(
200
+ choices=QUESTIONS["embedded systems"],
201
+ value=QUESTIONS["embedded systems"][0],
202
+ label="❓ Select Question"
203
+ )
204
+ selected_file = gr.Textbox(label="πŸ“‚ Selected File", interactive=False)
205
+ start_btn = gr.Button("▢️ Start Demo", variant="primary")
206
+ conversation_log = gr.Textbox(label="Conversation Log", lines=10)
207
+ pdf_input.change(update_questions, inputs=pdf_input, outputs=question_input)
208
+ load_btn.click(load_all_pdfs, outputs=load_status, show_progress=False)
209
+ start_btn.click(demo_interaction, inputs=[pdf_input, question_input], outputs=[conversation_log, selected_file])
210
+
211
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ pyttsx3
3
+ PyPDF2
4
+ sentence-transformers
5
+ chromadb
6
+ gtts
7
+ playsound==1.2.2
8
+ groq
9
+ python-dotenv
10
+ numpy