Document / app.py
SlouchyBuffalo's picture
Create app.py
8553eef verified
raw
history blame
8.81 kB
import gradio as gr
import spaces
import PyPDF2
import docx
import io
import requests
import os
from typing import Optional
# Prompts for each operation (keeping same as before)
PROMPTS = {
"Summary": """Write a concise summary of the provided document. The summary should be 150–200 words, capturing the main ideas, key arguments, or findings, and central themes. Exclude minor details or examples unless critical to the core message. Use clear, neutral language, structuring the summary with an introductory sentence stating the document's purpose, followed by main points in a logical order. Conclude with a brief statement on the document's significance or broader implications. Ensure accuracy by directly referencing the document's content and avoid personal opinions. If the document includes specific sections (e.g., abstract, conclusion), prioritize those for key insights.""",
"Outline": """Create a detailed outline of the provided document. The outline should feature a clear hierarchy with main sections, subsections, and bullet points summarizing key concepts, arguments, or findings under each. Use Roman numerals for main sections and letters or numbers for subsections. Include a brief introductory statement (50–100 words) describing the document's scope and purpose. Ensure the outline is comprehensive, logically organized, and captures all major points from the document without extraneous details. If the document has a table of contents or headings, align the outline with its structure.""",
"Analysis": """Provide a critical analysis of the provided document, focusing on its main arguments, evidence, or methodology. The analysis should be 300–400 words, evaluating strengths and weaknesses, the author's assumptions, biases, or rhetorical strategies, and the document's relevance or impact in its field or broader context. Support your points with direct evidence from the document, such as quotes or data. Organize the analysis with an introduction, body paragraphs (strengths, weaknesses, implications), and a conclusion. Maintain an objective tone, avoiding excessive summarization, and ensure all claims are grounded in the document's content.""",
"Study Guide": """Develop a comprehensive study guide for the provided document. The guide should include: (1) a brief overview (50–100 words) of the document's scope and purpose, (2) a list of 5–7 key themes or concepts with concise explanations (50–100 words each), (3) a glossary of 10–15 essential terms from the document with clear definitions, (4) 3–5 critical discussion questions to encourage deeper thinking, and (5) a checklist of key takeaways or study tips. Organize the guide with clear headings and bullet points, ensuring it is student-friendly and focused on retention and understanding, drawing directly from the document's content.""",
"Table": """Create a comparative table based on the provided document, synthesizing key elements (e.g., theories, findings, arguments, or concepts) across relevant criteria (e.g., assumptions, applications, strengths, weaknesses). The table should compare 3–5 elements, using rows for each element and columns for each criterion. Include a brief introductory paragraph (50–100 words) explaining the table's purpose and scope. Ensure the table is concise, visually organized, and populated with precise information directly from the document. If applicable, use data or examples from the document to enhance clarity.""",
"Questions": """Generate a set of 10 high-quality questions based on the provided document. Include: (1) 3 factual questions to test recall of key details, (2) 3 conceptual questions to assess understanding of main ideas or arguments, (3) 2 analytical questions to encourage critical thinking about the document's implications or weaknesses, and (4) 2 open-ended questions to prompt discussion or creative reflection. Label each question by type (factual, conceptual, analytical, open-ended), and ensure questions are clear, specific, and aligned with the document's core themes. Provide a brief introduction (50 words) explaining the questions' purpose, referencing the document's content."""
}
def extract_text_from_file(file) -> str:
"""Extract text from uploaded files"""
if file is None:
return ""
file_path = file.name
text = ""
try:
if file_path.endswith('.pdf'):
with open(file_path, 'rb') as f:
reader = PyPDF2.PdfReader(f)
for page in reader.pages:
text += page.extract_text() + "\n"
elif file_path.endswith('.docx'):
doc = docx.Document(file_path)
for paragraph in doc.paragraphs:
text += paragraph.text + "\n"
elif file_path.endswith('.txt'):
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
except Exception as e:
return f"Error reading file: {str(e)}"
return text
def call_llama_inference(prompt: str, max_tokens: int = 2000) -> str:
"""Call HuggingFace Inference API for Llama 3.3 70B"""
api_token = os.getenv('HF_TOKEN')
if not api_token:
return "Error: HuggingFace token not found. Please set the HF_TOKEN secret in your Space settings."
# Using HuggingFace's hosted inference endpoint for Cerebras/Llama-3.3-70B
api_url = "https://api-inference.huggingface.co/models/Cerebras/Llama-3.3-70B-Instruct"
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
payload = {
"inputs": prompt,
"parameters": {
"max_new_tokens": max_tokens,
"temperature": 0.1,
"do_sample": True,
"return_full_text": False
}
}
try:
response = requests.post(api_url, headers=headers, json=payload, timeout=120)
if response.status_code == 200:
result = response.json()
if isinstance(result, list) and len(result) > 0:
return result[0].get('generated_text', 'No response generated')
else:
return str(result)
else:
return f"Error: API request failed with status {response.status_code}: {response.text}"
except Exception as e:
return f"Error calling HuggingFace API: {str(e)}"
@spaces.GPU
def process_document(document, operation_type, text_input):
"""Main processing function"""
# Extract text from file or use text input
if document is not None:
text = extract_text_from_file(document)
else:
text = text_input
if not text.strip():
return "Please provide either a document or text input."
# Get the appropriate prompt
prompt = PROMPTS.get(operation_type, "")
# Combine prompt with document text
full_prompt = f"{prompt}\n\nDocument content:\n{text}"
# Call HuggingFace Inference API with Cerebras Llama
result = call_llama_inference(full_prompt)
return result
# Create the Gradio interface
with gr.Blocks(title="Study Assistant", theme=gr.themes.Soft()) as demo:
gr.Markdown("# πŸ“š Study Assistant - Document Analysis Tool")
gr.Markdown("Upload a document or paste text, then select the type of analysis you want to perform.")
with gr.Row():
with gr.Column():
document = gr.File(
label="Upload Document",
file_types=[".pdf", ".docx", ".txt"],
file_count="single"
)
text_input = gr.Textbox(
label="Or paste text directly",
lines=5,
placeholder="Paste your text here if you don't want to upload a file..."
)
with gr.Column():
operation_type = gr.Dropdown(
choices=["Summary", "Outline", "Analysis", "Study Guide", "Table", "Questions"],
label="Select Operation",
value="Summary"
)
process_btn = gr.Button("Process Document", variant="primary", size="lg")
output = gr.Textbox(
label="Output",
lines=20,
show_copy_button=True
)
gr.Markdown("---")
gr.Markdown("### Tips:")
gr.Markdown("- Supported formats: PDF, DOCX, TXT")
gr.Markdown("- Maximum file size: 200MB")
gr.Markdown("- Text can be pasted directly if you don't have a file")
gr.Markdown("- Powered by Cerebras Llama-3.3-70B through HuggingFace")
process_btn.click(
fn=process_document,
inputs=[document, operation_type, text_input],
outputs=output
)
if __name__ == "__main__":
demo.launch()