magles's picture
Update app.py
970dcae verified
Raw
History Blame Contribute Delete
8.89 kB
import gradio as gr
import os
import re
import requests
from io import BytesIO
from PIL import Image
from pdfminer.high_level import extract_text
from groq import Groq
from docx import Document
from docx.shared import Inches
import time
def extract_text_with_pdfminer(pdf_path):
return extract_text(pdf_path)
def clean_text(text):
text = text.replace('\f', ' ')
text = re.sub(r'\s+\n', '\n', text)
text = re.sub(r'\n+', '\n', text)
return text.strip()
def extract_sections(text):
text = clean_text(text)
pattern = r'^(Section\s+\d+:\s+.*)$'
headings = [(m.start(), m.group(0).strip())
for m in re.finditer(pattern, text, re.MULTILINE)]
sections = {}
if headings:
if headings[0][0] > 0:
preamble = text[:headings[0][0]].strip()
if preamble:
sections["Title"] = preamble
for i, (start, heading) in enumerate(headings):
end = headings[i+1][0] if i+1 < len(headings) else len(text)
section_text = text[start:end].strip()
content = section_text[len(heading):].strip()
sections[heading] = content
else:
sections["FullText"] = text
return sections
def generate_with_groq(prompt, groq_api_key):
client = Groq(api_key=groq_api_key)
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=2000
)
return response.choices[0].message.content
def google_image_search(query, api_key, cx, num=1):
url = "https://www.googleapis.com/customsearch/v1"
params = {"q": query, "key": api_key, "cx": cx, "searchType": "image", "num": num}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
results = response.json()
if "items" in results and len(results["items"]) > 0:
return results["items"][0]["link"]
except Exception as e:
print(f"Image search error: {str(e)}")
return None
def process_pdf(pdf_file, groq_api_key, google_api_key, cx, progress=gr.Progress()):
if not pdf_file:
return None, None, "❌ Please upload a PDF file!"
if not groq_api_key or not google_api_key or not cx:
return None, None, "❌ Please provide all API credentials!"
try:
progress(0.1, desc="πŸ“„ Extracting text from PDF...")
pdf_text = extract_text_with_pdfminer(pdf_file.name)
sections = extract_sections(pdf_text)
formatted_sections = [(h, c) for h, c in sections.items()]
if not formatted_sections:
return None, None, "❌ No text extracted from PDF!"
notes_per_section = {}
images_per_section = {}
total_sections = len(formatted_sections)
for idx, (heading, content) in enumerate(formatted_sections, start=1):
progress_val = 0.1 + (idx/total_sections) * 0.7
progress(progress_val, desc=f"βš™οΈ Processing section {idx}/{total_sections}...")
section = f"{heading}\n\n{content}"
try:
text_prompt = (
"Please transform the following text section into detailed, "
"elaborated lecture notes for students.\n"
"Format: Use '# ' for headings, '## ' for subheadings, '* ' for bullets.\n\n"
f"Text:\n{section}\n"
)
detailed_notes = generate_with_groq(text_prompt, groq_api_key)
notes_per_section[idx] = detailed_notes
time.sleep(2)
image_prompt = f"Generate a 5-word image search query for:\n{section}"
image_query = generate_with_groq(image_prompt, groq_api_key).strip().replace('"', '')
image_url = google_image_search(image_query, google_api_key, cx)
images_per_section[idx] = image_url
except Exception as e:
notes_per_section[idx] = f"# Section {idx}\n\nError: {str(e)}"
images_per_section[idx] = None
progress(0.85, desc="πŸ“ Generating summary...")
all_notes = "\n\n".join(notes_per_section[idx] for idx in sorted(notes_per_section.keys()))
time.sleep(2)
summary_prompt = f"Summarize the following lecture notes:\n\n{all_notes}"
summary = generate_with_groq(summary_prompt, groq_api_key)
progress(0.95, desc="πŸ“„ Creating documents...")
summary_doc = Document()
summary_doc.add_heading("Summary", level=1)
for sentence in re.split(r'(?<=[.!?])\s+', summary.strip()):
if sentence.strip():
summary_doc.add_paragraph(sentence.strip())
summary_doc.save("lecture_summary.docx")
main_doc = Document()
for idx in sorted(notes_per_section.keys()):
section_text = notes_per_section[idx]
lines = section_text.strip().split("\n")
if lines:
main_doc.add_heading(lines[0].lstrip("# ").strip(), level=1)
for line in lines[1:]:
if line.strip():
if line.strip().startswith("## "):
main_doc.add_heading(line.strip().lstrip("## "), level=2)
elif line.strip().startswith("* "):
main_doc.add_paragraph(line.strip().lstrip("* "), style="List Bullet")
else:
main_doc.add_paragraph(line.strip())
image_url = images_per_section.get(idx)
if image_url:
try:
img_response = requests.get(image_url, timeout=10)
img_data = BytesIO(img_response.content)
main_doc.add_picture(img_data, width=Inches(4))
except:
main_doc.add_paragraph("[Image unavailable]")
main_doc.add_page_break()
main_doc.save("lecture_notes.docx")
progress(1.0, desc="βœ… Complete!")
return ("lecture_notes.docx", "lecture_summary.docx",
f"βœ… Processed {total_sections} sections!")
except Exception as e:
return None, None, f"❌ Error: {str(e)}"
# Create interface WITHOUT theme parameter (this was causing the error)
demo = gr.Blocks(title="LectureForge")
with demo:
gr.Markdown("""
# πŸŽ“ LectureForge - AI Lecture Notes Generator
Transform textbook PDFs into detailed, illustrated lecture notes using AI.
**How to use:**
1. Get free API keys:
- [Groq API](https://console.groq.com) (6000 requests/day free)
- [Google API Key](https://console.cloud.google.com) + [Search Engine CX](https://programmablesearchengine.google.com)
2. Upload your textbook PDF (text-based, not scanned)
3. Enter your API credentials
4. Click "Generate Notes" and wait 2-4 minutes
5. Download your notes!
""")
with gr.Row():
with gr.Column():
gr.Markdown("### πŸ“€ Upload & Configure")
pdf_input = gr.File(label="πŸ“„ Upload PDF Textbook", file_types=[".pdf"])
groq_key = gr.Textbox(
label="πŸ”‘ Groq API Key",
type="password",
placeholder="gsk_..."
)
google_key = gr.Textbox(
label="πŸ”‘ Google API Key",
type="password",
placeholder="AIza..."
)
cx_input = gr.Textbox(
label="πŸ” Google Custom Search CX",
placeholder="Your search engine ID"
)
generate_btn = gr.Button("πŸš€ Generate Notes", variant="primary")
with gr.Column():
gr.Markdown("### πŸ“₯ Download Results")
status_output = gr.Textbox(label="πŸ“Š Status", lines=8)
notes_output = gr.File(label="πŸ“ Lecture Notes (.docx)")
summary_output = gr.File(label="πŸ“‹ Summary (.docx)")
gr.Markdown("""
---
### ℹ️ Tips
- Works best with text-based PDFs (not scanned images)
- Processing time: ~12-18 seconds per section
- Free API limits: Groq (6000 req/day), Google (100 searches/day)
---
**Created by:** Ruben Santosh, Vignesh R Nair, Arko Chakraborty
**Institution:** Dayananda Sagar University, Bangalore, India
""")
generate_btn.click(
fn=process_pdf,
inputs=[pdf_input, groq_key, google_key, cx_input],
outputs=[notes_output, summary_output, status_output]
)
if __name__ == "__main__":
demo.launch()