Hifzamudassar commited on
Commit
dcbcba8
·
verified ·
1 Parent(s): 2c0e8d1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +233 -157
app.py CHANGED
@@ -1,40 +1,45 @@
 
 
 
 
1
  import os
2
  import tempfile
3
  import random
4
  import requests
 
5
  from urllib.parse import quote_plus
 
6
  from PIL import Image, ImageDraw, ImageFont
7
- import pytesseract
8
  from gtts import gTTS
9
- from moviepy.editor import ImageClip, AudioFileClip, concatenate_videoclips
10
- import gradio as gr
11
 
12
- # ===========================
13
- # Environment Variables
14
- # ===========================
15
- GROQ_API_KEY = os.getenv("GROQ_API_KEY", "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")
16
- GROQ_MODEL = "llama-3.3-70b-versatile"
17
 
18
- if not GROQ_API_KEY:
19
- print("⚠️ WARNING: GROQ_API_KEY is missing. Add it in HuggingFace Secrets!")
20
 
 
 
 
 
 
21
 
22
- # ===========================
23
- # Users Database
24
- # ===========================
25
  users_db = {}
26
  verification_codes = {}
27
 
28
-
29
- # ===========================
30
- # Authentication Functions
31
- # ===========================
32
  def signup_user(username, email, password, contact):
33
  if email in users_db:
34
  return "Email already registered.", ""
 
35
  code = str(random.randint(100000, 999999))
36
  verification_codes[email] = code
37
-
38
  users_db[email] = {
39
  "username": username,
40
  "password": password,
@@ -42,12 +47,13 @@ def signup_user(username, email, password, contact):
42
  "verified": False
43
  }
44
 
45
- return "Signup successful! Verification code:", code
46
 
47
 
48
  def verify_user(email, code):
49
  if email not in users_db:
50
- return "Email not registered."
 
51
  if users_db[email]["verified"]:
52
  return "Already verified."
53
 
@@ -55,6 +61,7 @@ def verify_user(email, code):
55
  users_db[email]["verified"] = True
56
  verification_codes.pop(email)
57
  return "Verification successful!"
 
58
  return "Invalid verification code."
59
 
60
 
@@ -62,22 +69,27 @@ def login_user(email, password):
62
  user = users_db.get(email)
63
  if not user:
64
  return False, "User not found."
 
65
  if not user["verified"]:
66
  return False, "Account not verified."
 
67
  if user["password"] != password:
68
  return False, "Incorrect password."
69
- return True, f"Welcome {user['username']}!"
70
 
 
71
 
72
- # ===========================
73
- # Groq API Call
74
- # ===========================
75
  def call_groq(prompt, max_tokens=500):
76
  if not GROQ_API_KEY:
77
- return " Missing GROQ_API_KEY in environment variables."
78
 
79
  url = "https://api.groq.com/openai/v1/chat/completions"
80
- headers = {"Authorization": f"Bearer {GROQ_API_KEY}", "Content-Type": "application/json"}
 
 
 
81
 
82
  payload = {
83
  "model": GROQ_MODEL,
@@ -86,184 +98,248 @@ def call_groq(prompt, max_tokens=500):
86
  }
87
 
88
  try:
89
- r = requests.post(url, json=payload, headers=headers, timeout=20)
90
- if r.status_code == 200:
91
- return r.json()["choices"][0]["message"]["content"]
92
- return f"API Error {r.status_code}: {r.text}"
93
  except Exception as e:
94
- return f"API Exception: {e}"
95
 
96
 
97
- # ===========================
98
- # AI Helper Functions
99
- # ===========================
100
  def generate_mcqs_from_text(text, n=5):
101
- prompt = f"Create {n} MCQs with 4 options and answers:\n\n{text}"
102
  return call_groq(prompt)
103
 
104
 
105
- def answer_text_query(query):
106
- prompt = f"Answer clearly:\n\n{query}"
107
  return call_groq(prompt)
108
 
109
-
110
- # ===========================
111
- # Video Generator
112
- # ===========================
113
  def create_video_simple(text, tts_lang="en", preview=False):
114
- if not text.strip():
115
- return None
 
 
116
 
117
- tmp = tempfile.gettempdir()
118
 
119
- lines = [l.strip() for l in text.split(".") if l.strip()]
120
- if preview:
121
- lines = lines[:1] # one slide preview
 
122
 
123
- clips = []
 
124
 
125
- for i, chunk in enumerate(lines):
126
- slide_path = os.path.join(tmp, f"slide_{i}.png")
127
 
128
- # Create slide
129
- img = Image.new("RGB", (480, 320), (255, 182, 193))
130
- draw = ImageDraw.Draw(img)
131
- font = ImageFont.load_default()
 
 
 
132
 
133
- draw.text((20, 20), "AI Generated Slide", fill="blue", font=font)
134
- draw.text((20, 80), chunk[:220], fill="black", font=font)
 
 
 
 
 
135
 
136
- img.save(slide_path)
 
137
 
138
- # Audio
139
- audio_path = os.path.join(tmp, f"audio_{i}.mp3")
140
- gTTS(text=chunk, lang=tts_lang).save(audio_path)
141
 
142
- # Clip
143
- clip = ImageClip(slide_path).set_duration(4)
144
- clip = clip.set_audio(AudioFileClip(audio_path))
145
- clips.append(clip)
146
 
147
- output_path = os.path.join(tmp, f"video_preview.mp4" if preview else "video_full.mp4")
148
- video = concatenate_videoclips(clips)
149
- video.write_videofile(output_path, fps=24, codec="libx264", audio_codec="aac")
150
 
151
- return output_path
152
 
 
 
 
153
 
154
- # ===========================
155
- # Notes + Flowchart
156
- # ===========================
157
  def generate_notes_flowchart(text):
158
- notes = call_groq(f"Summarize into clean notes:\n\n{text}")
159
- img = Image.new("RGB", (500, 350), (180, 250, 180))
 
160
  draw = ImageDraw.Draw(img)
161
- font = ImageFont.load_default()
 
 
 
 
162
 
163
  y = 20
164
  for line in notes.split("\n"):
165
- draw.text((10, y), line[:60], fill="black", font=font)
 
166
  y += 18
167
- if y > 300:
168
- break
169
  return notes, img
170
 
171
 
172
- # ===========================
173
- # Quick Search Links
174
- # ===========================
175
- def get_links(topic):
176
- yt = f"https://www.youtube.com/results?search_query={quote_plus(topic)}"
177
- gg = f"https://www.google.com/search?q={quote_plus(topic)}"
178
- return yt, gg
179
 
 
 
180
 
181
- # ===========================
182
- # UI
183
- # ===========================
184
- with gr.Blocks(title="AI Study Wizard") as demo:
185
 
186
- gr.Markdown("# 🎓 AI Study Wizard — Full Assistant")
 
 
187
 
188
- # Signup
 
 
 
 
 
 
 
 
 
 
 
189
  with gr.Tab("Sign Up"):
190
- name = gr.Textbox(label="Name")
191
- email = gr.Textbox(label="Email")
192
- pwd = gr.Textbox(label="Password", type="password")
193
- contact = gr.Textbox(label="Contact")
194
- btn = gr.Button("Create Account")
195
- msg = gr.Textbox(label="Message")
196
- code_out = gr.Textbox(label="Verification Code (demo)")
197
- btn.click(signup_user, [name, email, pwd, contact], [msg, code_out])
198
-
199
- # Verify
200
- with gr.Tab("Verify"):
 
 
 
 
 
 
201
  v_email = gr.Textbox(label="Email")
202
- v_code = gr.Textbox(label="Code")
203
  v_btn = gr.Button("Verify")
204
- v_msg = gr.Textbox(label="Status")
205
- v_btn.click(verify_user, [v_email, v_code], v_msg)
 
206
 
207
- # Login
208
  with gr.Tab("Login"):
209
- l_email = gr.Textbox(label="Email")
210
- l_pass = gr.Textbox(label="Password", type="password")
211
- l_btn = gr.Button("Login")
212
- l_msg = gr.Textbox(label="Message")
213
- l_btn.click(lambda e, p: login_user(e, p), [l_email, l_pass], l_msg)
214
-
215
- # Ask Question
216
- with gr.Tab("Ask AI"):
217
- q = gr.Textbox(label="Your Question")
218
- ans = gr.Textbox(label="Answer", lines=8)
219
- mcq = gr.Textbox(label="MCQs", lines=8)
220
- pv = gr.Video(label="Preview Video")
221
- fv = gr.Video(label="Full Video")
222
- b = gr.Button("Generate")
223
-
224
- def process_query(q):
225
- a = answer_text_query(q)
226
- m = generate_mcqs_from_text(a)
227
- prev = create_video_simple(a, preview=True)
228
- full = create_video_simple(a, preview=False)
229
- return a, m, prev, full
230
-
231
- b.click(process_query, q, [ans, mcq, pv, fv])
232
-
233
- # Upload Notes
234
- with gr.Tab("Upload Image"):
235
- file = gr.File(label="Upload Image")
236
- lang = gr.Dropdown(["en", "ur", "hi"], value="en")
237
- out_text = gr.Textbox(label="Extracted Text", lines=6)
238
- out_mcq = gr.Textbox(label="MCQs", lines=6)
239
- out_notes = gr.Textbox(label="Notes", lines=6)
240
- out_flow = gr.Image(label="Flowchart")
241
- out_prev = gr.Video(label="Preview Video")
242
- out_full = gr.Video(label="Full Video")
243
-
244
- def process_upload(f, language):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  try:
246
- text = pytesseract.image_to_string(Image.open(f.name))
247
  except:
248
- text = ""
249
 
250
- mcqs = generate_mcqs_from_text(text) if text else ""
251
- notes, img = generate_notes_flowchart(text) if text else ("", None)
252
- prev = create_video_simple(text, tts_lang=language, preview=True) if text else None
253
- full = create_video_simple(text, tts_lang=language, preview=False) if text else None
 
254
 
255
- return text, mcqs, notes, img, prev, full
 
256
 
257
- btn = gr.Button("Process")
258
- btn.click(process_upload, [file, lang],
259
- [out_text, out_mcq, out_notes, out_flow, out_prev, out_full])
260
 
261
- # Search Links
262
- with gr.Tab("Search"):
 
 
 
 
 
 
 
 
 
 
 
 
263
  topic = gr.Textbox(label="Topic")
264
- yt = gr.Textbox(label="YouTube", interactive=False)
265
- gg = gr.Textbox(label="Google", interactive=False)
266
- btn = gr.Button("Search")
267
- btn.click(get_links, topic, [yt, gg])
 
 
268
 
269
  demo.launch()
 
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,
 
47
  "verified": False
48
  }
49
 
50
+ return "Signup successful! Your verification code:", code
51
 
52
 
53
  def verify_user(email, code):
54
  if email not in users_db:
55
+ return "Email not found."
56
+
57
  if users_db[email]["verified"]:
58
  return "Already verified."
59
 
 
61
  users_db[email]["verified"] = True
62
  verification_codes.pop(email)
63
  return "Verification successful!"
64
+
65
  return "Invalid verification code."
66
 
67
 
 
69
  user = users_db.get(email)
70
  if not user:
71
  return False, "User not found."
72
+
73
  if not user["verified"]:
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"
92
+ }
93
 
94
  payload = {
95
  "model": GROQ_MODEL,
 
98
  }
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)
182
+
183
+ try:
184
+ font = ImageFont.truetype("DejaVuSans.ttf", 16)
185
+ except:
186
+ font = ImageFont.load_default()
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
+
 
203
 
204
+ def get_google_link(q):
205
+ return f"https://www.google.com/search?q={quote_plus(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")
245
+ v_msg = gr.Textbox(label="Status", interactive=False)
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
312
+ full = None
313
+ notes = ""
314
+ flow = None
315
 
316
+ if "MCQs" in opts:
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)
325
+
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()
339
+ gg = gr.Markdown()
340
+ link_btn = gr.Button("Get Links")
341
+
342
+ link_btn.click(get_links_clickable, inputs=topic, outputs=[yt, gg])
343
+
344
 
345
  demo.launch()