Hifzamudassar commited on
Commit
d67f47d
·
verified ·
1 Parent(s): fad1104

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -155
app.py CHANGED
@@ -1,45 +1,52 @@
1
- # =========================== #
2
- # AI Study Wizard #
3
- # =========================== #
4
 
5
  import os
6
  import tempfile
7
  import random
8
- import requests
9
  import pytesseract
10
- from urllib.parse import quote_plus
11
 
12
  from PIL import Image, ImageDraw, ImageFont
13
  from gtts import gTTS
14
 
15
- # MoviePy SAFE Imports for HuggingFace
16
  from moviepy.video.VideoClip import ImageClip
17
  from moviepy.audio.io.AudioFileClip import AudioFileClip
18
  from moviepy.video.compositing.concatenate import concatenate_videoclips
19
 
 
 
 
20
  import gradio as gr
 
21
 
22
- # =========================== #
23
- # Load GROQ API Key (HF Secret)
24
- # =========================== #
25
- GROQ_API_KEY = os.getenv("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")
 
26
  GROQ_MODEL = "llama-3.3-70b-versatile"
27
 
28
- # =========================== #
29
- # Users Database / State
30
- # =========================== #
 
31
  users_db = {}
32
  verification_codes = {}
33
 
34
- # =========================== #
35
- # Signup / Verify / Login
36
- # =========================== #
 
37
  def signup_user(username, email, password, contact):
38
  if email in users_db:
39
  return "Email already registered.", ""
40
 
41
  code = str(random.randint(100000, 999999))
42
  verification_codes[email] = code
 
43
  users_db[email] = {
44
  "username": username,
45
  "password": password,
@@ -74,18 +81,17 @@ def login_user(email, password):
74
  return False, "Account not verified."
75
 
76
  if user["password"] != password:
77
- return False, "Incorrect password."
78
 
79
  return True, f"Welcome {user['username']}!"
80
 
81
- # =========================== #
82
- # Groq API
83
- # =========================== #
84
- def call_groq(prompt, max_tokens=500):
85
- if not GROQ_API_KEY:
86
- return "API key missing. Add GROQ_API_KEY in HuggingFace Secrets."
87
 
 
 
 
 
88
  url = "https://api.groq.com/openai/v1/chat/completions"
 
89
  headers = {
90
  "Authorization": f"Bearer {GROQ_API_KEY}",
91
  "Content-Type": "application/json"
@@ -99,83 +105,72 @@ def call_groq(prompt, max_tokens=500):
99
 
100
  try:
101
  r = requests.post(url, json=payload, headers=headers)
102
- data = r.json()
103
- return data["choices"][0]["message"]["content"]
104
  except Exception as e:
105
  return f"Groq API Error: {e}"
106
 
107
 
108
- def generate_mcqs_from_text(text, n=5):
109
- prompt = f"Generate {n} MCQs with 4 options and correct answer:\n\n{text}"
110
- return call_groq(prompt)
111
 
112
 
113
- def answer_text_query(q):
114
- prompt = f"Answer clearly:\n\n{q}"
115
- return call_groq(prompt)
116
 
117
- # =========================== #
118
- # Video Generation Function
119
- # =========================== #
 
120
  def create_video_simple(text, tts_lang="en", preview=False):
121
- try:
122
- text = text.strip()
123
- if not text:
124
- return None
125
 
126
- tmp = tempfile.gettempdir()
 
127
 
128
- # Split into slides
129
- lines = [l.strip() for l in text.split("\n") if l.strip()]
130
- if preview:
131
- lines = lines[:1]
132
 
133
- chunks = [lines[i:i+2] for i in range(0, len(lines), 2)]
134
- clips = []
135
 
136
- for idx, chunk in enumerate(chunks):
137
- slide_text = " ".join(chunk)
 
138
 
139
- img_path = os.path.join(tmp, f"slide_{idx}.png")
140
- audio_path = os.path.join(tmp, f"audio_{idx}.mp3")
 
 
141
 
142
- # Slide image
143
- W, H = 480, 320
144
- img = Image.new("RGB", (W, H), (255, 182, 193))
145
- draw = ImageDraw.Draw(img)
146
 
147
- try:
148
- font = ImageFont.truetype("DejaVuSans-Bold.ttf", 22)
149
- except:
150
- font = ImageFont.load_default()
151
 
152
- draw.text((20, 20), slide_text, fill="black", font=font)
153
- img.save(img_path)
154
 
155
- # Audio
156
- gTTS(text=slide_text, lang=tts_lang).save(audio_path)
157
 
158
- duration = max(3, min(len(slide_text) // 12 + 2, 7))
 
 
159
 
160
- clip = ImageClip(img_path).set_duration(duration)
161
- clip = clip.set_audio(AudioFileClip(audio_path))
162
- clips.append(clip)
163
 
164
- out_path = os.path.join(tmp, "preview.mp4" if preview else "video.mp4")
165
- final = concatenate_videoclips(clips, method="compose")
166
- final.write_videofile(out_path, fps=24, codec="libx264", audio_codec="aac", verbose=False)
167
 
168
- return out_path
169
 
170
- except Exception as e:
171
- print("Video Error:", e)
172
- return None
173
-
174
- # =========================== #
175
- # Notes + Flowchart
176
- # =========================== #
177
  def generate_notes_flowchart(text):
178
- notes = call_groq(f"Summarize into concise study notes:\n\n{text}")
179
 
180
  img = Image.new("RGB", (480, 320), (144, 238, 144))
181
  draw = ImageDraw.Draw(img)
@@ -187,16 +182,33 @@ def generate_notes_flowchart(text):
187
 
188
  y = 20
189
  for line in notes.split("\n"):
190
- if y > 290: break
 
191
  draw.text((10, y), line, fill="black", font=font)
192
  y += 18
193
 
194
  return notes, img
195
 
196
 
197
- # =========================== #
198
- # Links
199
- # =========================== #
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  def get_youtube_link(q):
201
  return f"https://www.youtube.com/results?search_query={quote_plus(q)}"
202
 
@@ -206,39 +218,44 @@ def get_google_link(q):
206
 
207
 
208
  def get_links_clickable(topic):
209
- if not topic.strip():
210
- return "Enter a topic", ""
211
-
212
  yt = "\n".join([f"[YouTube {i+1}]({get_youtube_link(topic)})" for i in range(3)])
213
  gg = "\n".join([f"[Google {i+1}]({get_google_link(topic)})" for i in range(3)])
214
  return yt, gg
215
 
216
- # =========================== #
217
- # UI
218
- # =========================== #
219
- with gr.Blocks() as demo:
220
 
221
- gr.Markdown("## 🎓 AI Study Wizard — Smart Student Assistant")
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
- # --------- Signup --------- #
 
 
224
  with gr.Tab("Sign Up"):
225
  su_name = gr.Textbox(label="Username")
226
  su_email = gr.Textbox(label="Email")
227
  su_pass = gr.Textbox(label="Password", type="password")
228
  su_contact = gr.Textbox(label="Contact Number")
229
-
230
  su_btn = gr.Button("Sign Up")
231
- msg = gr.Textbox(label="Message", interactive=False)
232
- code_show = gr.Textbox(label="Verification Code", interactive=False)
233
 
234
- su_btn.click(
235
- signup_user,
236
- inputs=[su_name, su_email, su_pass, su_contact],
237
- outputs=[msg, code_show]
238
- )
239
 
240
- # --------- Verify --------- #
241
- with gr.Tab("Verify Account"):
 
 
 
242
  v_email = gr.Textbox(label="Email")
243
  v_code = gr.Textbox(label="Verification Code")
244
  v_btn = gr.Button("Verify")
@@ -246,66 +263,51 @@ with gr.Blocks() as demo:
246
 
247
  v_btn.click(verify_user, inputs=[v_email, v_code], outputs=v_msg)
248
 
249
- # --------- Login --------- #
250
  with gr.Tab("Login"):
251
  li_email = gr.Textbox(label="Email")
252
  li_pass = gr.Textbox(label="Password", type="password")
253
  li_btn = gr.Button("Login")
254
  li_msg = gr.Textbox(label="Login Status")
255
 
256
- def login_wrapper(e, p):
257
  ok, msg = login_user(e, p)
258
  return msg
259
 
260
- li_btn.click(login_wrapper, inputs=[li_email, li_pass], outputs=li_msg)
 
 
 
 
 
 
 
 
 
261
 
262
- # --------- Question --------- #
263
- with gr.Tab("Ask a Question"):
264
- q_in = gr.Textbox(label="Your Question")
265
- ans_out = gr.Textbox(label="Answer")
266
- mcq_out = gr.Textbox(label="MCQs")
267
 
268
- prev_vid = gr.Video(label="Preview Video")
269
- full_vid = gr.Video(label="Full Video")
270
 
271
- ask_btn = gr.Button("Generate")
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
- def ask_system(q):
274
- answer = answer_text_query(q)
275
- mcqs = generate_mcqs_from_text(answer)
276
- return (
277
- answer,
278
- mcqs,
279
- create_video_simple(answer, preview=True),
280
- create_video_simple(answer, preview=False)
281
- )
282
-
283
- ask_btn.click(ask_system, inputs=q_in,
284
- outputs=[ans_out, mcq_out, prev_vid, full_vid])
285
-
286
- # --------- Upload --------- #
287
- with gr.Tab("Upload Document"):
288
- file_in = gr.File()
289
- options = gr.CheckboxGroup(
290
- ["Extracted Text", "MCQs", "Video", "Notes"]
291
- )
292
- video_lang = gr.Dropdown(
293
- ["en", "ur", "hi"], value="en", label="Video Language"
294
- )
295
-
296
- o_text = gr.Textbox(label="Extracted Text", lines=8)
297
- o_mcq = gr.Textbox(label="MCQs", lines=8)
298
- o_prev = gr.Video(label="Preview Video")
299
- o_vid = gr.Video(label="Full Video")
300
- o_notes = gr.Textbox(label="Notes")
301
- o_flow = gr.Image(label="Flowchart")
302
-
303
- def process(file, opts, lang):
304
- text = ""
305
- try:
306
- text = pytesseract.image_to_string(Image.open(file.name))
307
- except:
308
- pass
309
 
310
  mcq = ""
311
  prev = None
@@ -317,8 +319,8 @@ with gr.Blocks() as demo:
317
  mcq = generate_mcqs_from_text(text)
318
 
319
  if "Video" in opts:
320
- prev = create_video_simple(text, lang, preview=True)
321
- full = create_video_simple(text, lang, preview=False)
322
 
323
  if "Notes" in opts:
324
  notes, flow = generate_notes_flowchart(text)
@@ -326,13 +328,10 @@ with gr.Blocks() as demo:
326
  return text, mcq, prev, full, notes, flow
327
 
328
  btn = gr.Button("Process")
329
- btn.click(
330
- process,
331
- inputs=[file_in, options, video_lang],
332
- outputs=[o_text, o_mcq, o_prev, o_vid, o_notes, o_flow]
333
- )
334
 
335
- # --------- Links --------- #
336
  with gr.Tab("Search Links"):
337
  topic = gr.Textbox(label="Topic")
338
  yt = gr.Markdown()
 
1
+ # ============================== #
2
+ # AI Study Wizard v2 #
3
+ # ============================== #
4
 
5
  import os
6
  import tempfile
7
  import random
 
8
  import pytesseract
9
+ import requests
10
 
11
  from PIL import Image, ImageDraw, ImageFont
12
  from gtts import gTTS
13
 
14
+ # Safe MoviePy Imports for HuggingFace
15
  from moviepy.video.VideoClip import ImageClip
16
  from moviepy.audio.io.AudioFileClip import AudioFileClip
17
  from moviepy.video.compositing.concatenate import concatenate_videoclips
18
 
19
+ # PDF support
20
+ from pdf2image import convert_from_path
21
+
22
  import gradio as gr
23
+ from urllib.parse import quote_plus
24
 
25
+
26
+ # ==========================================================
27
+ # HARD-CODED GROQ API KEY (Replace with your real API key)
28
+ # ==========================================================
29
+ GROQ_API_KEY = "YOUR_GROQ_API_KEYgsk_GHftv8pvXaU7yeIltEaxWGdyb3FYlEDMH09TDRgJz5yzGQdVE7Rf"
30
  GROQ_MODEL = "llama-3.3-70b-versatile"
31
 
32
+
33
+ # ==========================================================
34
+ # USERS DB / STATE
35
+ # ==========================================================
36
  users_db = {}
37
  verification_codes = {}
38
 
39
+
40
+ # ==========================================================
41
+ # SIGNUP / VERIFY / LOGIN SYSTEM
42
+ # ==========================================================
43
  def signup_user(username, email, password, contact):
44
  if email in users_db:
45
  return "Email already registered.", ""
46
 
47
  code = str(random.randint(100000, 999999))
48
  verification_codes[email] = code
49
+
50
  users_db[email] = {
51
  "username": username,
52
  "password": password,
 
81
  return False, "Account not verified."
82
 
83
  if user["password"] != password:
84
+ return False, "Wrong password."
85
 
86
  return True, f"Welcome {user['username']}!"
87
 
 
 
 
 
 
 
88
 
89
+ # ==========================================================
90
+ # GROQ API CALL
91
+ # ==========================================================
92
+ def call_groq(prompt, max_tokens=600):
93
  url = "https://api.groq.com/openai/v1/chat/completions"
94
+
95
  headers = {
96
  "Authorization": f"Bearer {GROQ_API_KEY}",
97
  "Content-Type": "application/json"
 
105
 
106
  try:
107
  r = requests.post(url, json=payload, headers=headers)
108
+ return r.json()["choices"][0]["message"]["content"]
 
109
  except Exception as e:
110
  return f"Groq API Error: {e}"
111
 
112
 
113
+ def answer_text_query(q):
114
+ return call_groq(f"Answer very clearly:\n\n{q}")
 
115
 
116
 
117
+ def generate_mcqs_from_text(text, n=5):
118
+ return call_groq(f"Generate {n} MCQs with 4 options + correct answer:\n\n{text}")
 
119
 
120
+
121
+ # ==========================================================
122
+ # VIDEO GENERATION
123
+ # ==========================================================
124
  def create_video_simple(text, tts_lang="en", preview=False):
 
 
 
 
125
 
126
+ if not text.strip():
127
+ return None
128
 
129
+ tmp = tempfile.gettempdir()
130
+ lines = [l.strip() for l in text.split("\n") if l.strip()]
131
+ if preview:
132
+ lines = lines[:1]
133
 
134
+ clips = []
 
135
 
136
+ for i, line in enumerate(lines):
137
+ img_path = os.path.join(tmp, f"slide_{i}.png")
138
+ audio_path = os.path.join(tmp, f"audio_{i}.mp3")
139
 
140
+ # Slide image
141
+ W, H = 480, 320
142
+ img = Image.new("RGB", (W, H), (255, 182, 193))
143
+ draw = ImageDraw.Draw(img)
144
 
145
+ try:
146
+ font = ImageFont.truetype("DejaVuSans-Bold.ttf", 22)
147
+ except:
148
+ font = ImageFont.load_default()
149
 
150
+ draw.text((20, 20), line, fill="black", font=font)
151
+ img.save(img_path)
 
 
152
 
153
+ # Audio
154
+ gTTS(text=line, lang=tts_lang).save(audio_path)
155
 
156
+ duration = max(3, min(len(line) // 10 + 2, 8))
 
157
 
158
+ clip = ImageClip(img_path).set_duration(duration)
159
+ clip = clip.set_audio(AudioFileClip(audio_path))
160
+ clips.append(clip)
161
 
162
+ out_path = os.path.join(tmp, "prev.mp4" if preview else "full.mp4")
163
+ final = concatenate_videoclips(clips, method="compose")
164
+ final.write_videofile(out_path, fps=24, codec="libx264", audio_codec="aac", verbose=False)
165
 
166
+ return out_path
 
 
167
 
 
168
 
169
+ # ==========================================================
170
+ # NOTES + FLOWCHART
171
+ # ==========================================================
 
 
 
 
172
  def generate_notes_flowchart(text):
173
+ notes = call_groq(f"Summarize into bullet study notes:\n\n{text}")
174
 
175
  img = Image.new("RGB", (480, 320), (144, 238, 144))
176
  draw = ImageDraw.Draw(img)
 
182
 
183
  y = 20
184
  for line in notes.split("\n"):
185
+ if y > 290:
186
+ break
187
  draw.text((10, y), line, fill="black", font=font)
188
  y += 18
189
 
190
  return notes, img
191
 
192
 
193
+ # ==========================================================
194
+ # PDF + IMAGE OCR
195
+ # ==========================================================
196
+ def extract_text_from_file(file):
197
+
198
+ if file.name.endswith(".pdf"):
199
+ pages = convert_from_path(file.name)
200
+ text = ""
201
+ for page in pages:
202
+ text += pytesseract.image_to_string(page) + "\n"
203
+ return text
204
+
205
+ else:
206
+ return pytesseract.image_to_string(Image.open(file.name))
207
+
208
+
209
+ # ==========================================================
210
+ # LINKS
211
+ # ==========================================================
212
  def get_youtube_link(q):
213
  return f"https://www.youtube.com/results?search_query={quote_plus(q)}"
214
 
 
218
 
219
 
220
  def get_links_clickable(topic):
 
 
 
221
  yt = "\n".join([f"[YouTube {i+1}]({get_youtube_link(topic)})" for i in range(3)])
222
  gg = "\n".join([f"[Google {i+1}]({get_google_link(topic)})" for i in range(3)])
223
  return yt, gg
224
 
 
 
 
 
225
 
226
+ # ==========================================================
227
+ # UI — GRADIENT BACKGROUND (Green + Light Pink)
228
+ # ==========================================================
229
+ custom_css = """
230
+ body {
231
+ background: linear-gradient(to bottom right, #90ee90, #ffb6c1);
232
+ }
233
+ """
234
+
235
+
236
+ # ==========================================================
237
+ # GRADIO UI
238
+ # ==========================================================
239
+ with gr.Blocks(css=custom_css) as demo:
240
 
241
+ gr.Markdown("## 🌸 **AI Study Wizard** — Pink + Green Themed Student Assistant")
242
+
243
+ # ---------------- SIGN UP ---------------- #
244
  with gr.Tab("Sign Up"):
245
  su_name = gr.Textbox(label="Username")
246
  su_email = gr.Textbox(label="Email")
247
  su_pass = gr.Textbox(label="Password", type="password")
248
  su_contact = gr.Textbox(label="Contact Number")
 
249
  su_btn = gr.Button("Sign Up")
 
 
250
 
251
+ su_msg = gr.Textbox(label="Message", interactive=False)
252
+ su_code = gr.Textbox(label="Your Verification Code", interactive=False)
 
 
 
253
 
254
+ su_btn.click(signup_user, inputs=[su_name, su_email, su_pass, su_contact],
255
+ outputs=[su_msg, su_code])
256
+
257
+ # ---------------- VERIFY ---------------- #
258
+ with gr.Tab("Verify"):
259
  v_email = gr.Textbox(label="Email")
260
  v_code = gr.Textbox(label="Verification Code")
261
  v_btn = gr.Button("Verify")
 
263
 
264
  v_btn.click(verify_user, inputs=[v_email, v_code], outputs=v_msg)
265
 
266
+ # ---------------- LOGIN ---------------- #
267
  with gr.Tab("Login"):
268
  li_email = gr.Textbox(label="Email")
269
  li_pass = gr.Textbox(label="Password", type="password")
270
  li_btn = gr.Button("Login")
271
  li_msg = gr.Textbox(label="Login Status")
272
 
273
+ def login_wrap(e, p):
274
  ok, msg = login_user(e, p)
275
  return msg
276
 
277
+ li_btn.click(login_wrap, inputs=[li_email, li_pass], outputs=li_msg)
278
+
279
+ # ---------------- QUESTION ---------------- #
280
+ with gr.Tab("Ask Question"):
281
+ q_in = gr.Textbox(label="Ask Any Question")
282
+ a_out = gr.Textbox(label="Answer")
283
+ m_out = gr.Textbox(label="MCQs")
284
+ pv = gr.Video(label="Preview")
285
+ fv = gr.Video(label="Full Video")
286
+ ask_btn = gr.Button("Generate")
287
 
288
+ def run_question(q):
289
+ ans = answer_text_query(q)
290
+ mcqs = generate_mcqs_from_text(ans)
291
+ return ans, mcqs, create_video_simple(ans, preview=True), create_video_simple(ans)
 
292
 
293
+ ask_btn.click(run_question, inputs=q_in, outputs=[a_out, m_out, pv, fv])
 
294
 
295
+ # ---------------- UPLOAD ---------------- #
296
+ with gr.Tab("Upload Document (PDF/Image)"):
297
+
298
+ f_in = gr.File()
299
+ options = gr.CheckboxGroup(["Extracted Text", "MCQs", "Video", "Notes"])
300
+ lang = gr.Dropdown(["en", "ur", "hi"], value="en", label="Video Language")
301
+
302
+ t_out = gr.Textbox(label="Extracted Text", lines=8)
303
+ mc_out = gr.Textbox(label="MCQs", lines=8)
304
+ pv2 = gr.Video(label="Preview Video")
305
+ fv2 = gr.Video(label="Full Video")
306
+ notes_out = gr.Textbox(label="Notes")
307
+ flow_out = gr.Image(label="Flowchart")
308
 
309
+ def process_file(file, opts, lg):
310
+ text = extract_text_from_file(file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
  mcq = ""
313
  prev = None
 
319
  mcq = generate_mcqs_from_text(text)
320
 
321
  if "Video" in opts:
322
+ prev = create_video_simple(text, lg, preview=True)
323
+ full = create_video_simple(text, lg)
324
 
325
  if "Notes" in opts:
326
  notes, flow = generate_notes_flowchart(text)
 
328
  return text, mcq, prev, full, notes, flow
329
 
330
  btn = gr.Button("Process")
331
+ btn.click(process_file, inputs=[f_in, options, lang],
332
+ outputs=[t_out, mc_out, pv2, fv2, notes_out, flow_out])
 
 
 
333
 
334
+ # ---------------- LINKS ---------------- #
335
  with gr.Tab("Search Links"):
336
  topic = gr.Textbox(label="Topic")
337
  yt = gr.Markdown()