retvq commited on
Commit
a23f94d
Β·
verified Β·
1 Parent(s): 62dc64e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -87
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import gradio as gr
2
  import os
 
3
  from langchain_community.document_loaders import PyPDFLoader
4
  from langchain_text_splitters import RecursiveCharacterTextSplitter
5
  from langchain_community.embeddings.fastembed import FastEmbedEmbeddings
@@ -7,133 +8,174 @@ from langchain_community.vectorstores import FAISS
7
  from langchain_huggingface import HuggingFaceEndpoint
8
  from langchain_core.prompts import ChatPromptTemplate
9
 
10
- # --- 1. Model Setup using HF Inference API ---
11
- # Get the HF token from environment variables (set in Space secrets)
12
- HF_TOKEN = os.environ.get("HF_TOKEN", "")
13
 
14
- if not HF_TOKEN:
15
- print("⚠️ Warning: HF_TOKEN not set. The app may not work properly.")
16
- print("Please add your Hugging Face token in Space Settings > Repository secrets")
17
-
18
- llm = HuggingFaceEndpoint(
19
- repo_id="meta-llama/Meta-Llama-3-8B-Instruct",
20
- temperature=0.7,
21
- max_new_tokens=2000,
22
- huggingfacehub_api_token=HF_TOKEN
23
- )
24
 
25
- # --- 2. The Core Logic ---
26
  def generate_question_paper(pdf_file, difficulty, num_questions):
27
- if not pdf_file:
28
- return "❌ Please upload a PDF file first."
29
-
30
  if not HF_TOKEN:
31
- return "❌ Error: HF_TOKEN not configured. Please add your Hugging Face token in Space Settings > Repository secrets."
32
 
 
 
 
33
  try:
34
- # A. Load PDF
 
35
  loader = PyPDFLoader(pdf_file.name)
36
  pages = loader.load()
37
 
38
  if not pages:
39
- return "❌ Error: Could not extract text from PDF. Please ensure it's a valid PDF with text content."
40
-
41
- # B. Split Text
42
  text_splitter = RecursiveCharacterTextSplitter(
43
  chunk_size=1000,
44
  chunk_overlap=100
45
  )
46
  chunks = text_splitter.split_documents(pages)
47
-
48
- # C. Vector Store (FAISS)
49
  embeddings = FastEmbedEmbeddings()
50
  vector_store = FAISS.from_documents(chunks, embeddings)
51
 
52
- # D. Retrieve Context
53
- retriever = vector_store.as_retriever(search_kwargs={"k": 7})
54
- context_docs = retriever.invoke("Key concepts and definitions")
55
  context_text = "\n\n".join([doc.page_content for doc in context_docs])
56
-
57
- # E. Prompt
58
- template = """You are an expert academic examiner. Create a formal Question Paper based ONLY on the context provided below.
59
-
60
- CONTEXT:
61
- {context}
62
-
63
- INSTRUCTIONS:
64
- - Difficulty: {difficulty}
65
- - Total Questions: {num_questions}
66
- - Format:
67
- Section A: Multiple Choice Questions (MCQs)
68
- Section B: Short Answer Questions
69
- Section C: Long Answer/Essay Questions
70
- - Provide the Answer Key for MCQs at the very end.
71
 
72
- Do not output conversational text. Output ONLY the exam paper in a well-formatted structure."""
 
 
73
 
74
- prompt = ChatPromptTemplate.from_template(template)
 
 
 
 
 
 
 
 
 
 
75
 
76
- # F. Generate
 
 
 
 
77
  chain = prompt | llm
 
 
78
  response = chain.invoke({
79
  "context": context_text,
80
  "difficulty": difficulty,
81
  "num_questions": num_questions
82
  })
83
 
84
- return response
85
 
86
  except Exception as e:
87
- return f"❌ Error processing PDF: {str(e)}\n\nPlease check:\n1. PDF is valid and contains text\n2. HF_TOKEN is correctly set\n3. You have access to Llama 3"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
- # --- 3. The UI ---
90
- with gr.Blocks(title="AI Question Paper Generator") as demo:
91
- gr.Markdown("# πŸ“„ AI Question Paper Generator")
92
- gr.Markdown("Powered by **Llama 3 (8B)** via Hugging Face Inference API")
93
- gr.Markdown("⚑ Fast β€’ 🎯 Accurate β€’ πŸ“š Context-Aware")
94
 
95
- with gr.Row():
96
- with gr.Column(scale=1):
97
- pdf_input = gr.File(
98
- label="πŸ“„ Upload Study Material (PDF)",
99
- file_types=[".pdf"]
100
- )
101
-
102
- with gr.Group():
103
- difficulty = gr.Radio(
104
- ["Easy", "Medium", "Hard"],
105
- label="🎚️ Difficulty Level",
106
- value="Medium"
 
 
 
 
 
 
107
  )
108
- num_questions = gr.Slider(
109
- 5, 20, value=10, step=1,
110
- label="πŸ“Š Total Questions"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  )
112
-
113
- btn = gr.Button("✨ Generate Question Paper", variant="primary", size="lg")
114
-
115
- gr.Markdown("""
116
- ### πŸ“ Instructions:
117
- 1. Upload a PDF containing study material
118
- 2. Select difficulty level
119
- 3. Choose number of questions
120
- 4. Click Generate!
121
- """)
122
-
123
- with gr.Column(scale=2):
124
- output = gr.Markdown(label="Generated Question Paper")
125
 
 
126
  btn.click(
127
  fn=generate_question_paper,
128
  inputs=[pdf_input, difficulty, num_questions],
129
- outputs=output
 
 
 
 
 
 
 
 
 
130
  )
131
-
132
- gr.Markdown("""
133
- ---
134
- **Note:** This app requires a Hugging Face token with access to Llama 3.
135
- Set `HF_TOKEN` in your Space's repository secrets.
136
- """)
137
 
138
  if __name__ == "__main__":
139
  demo.launch()
 
1
  import gradio as gr
2
  import os
3
+ import time
4
  from langchain_community.document_loaders import PyPDFLoader
5
  from langchain_text_splitters import RecursiveCharacterTextSplitter
6
  from langchain_community.embeddings.fastembed import FastEmbedEmbeddings
 
8
  from langchain_huggingface import HuggingFaceEndpoint
9
  from langchain_core.prompts import ChatPromptTemplate
10
 
11
+ # --- 1. Model Setup ---
12
+ HF_TOKEN = os.environ.get("HF_TOKEN")
 
13
 
14
+ # Setup the Model (Llama 3 8B via API)
15
+ if HF_TOKEN:
16
+ llm = HuggingFaceEndpoint(
17
+ repo_id="meta-llama/Meta-Llama-3-8B-Instruct",
18
+ temperature=0.5,
19
+ max_new_tokens=4096,
20
+ huggingfacehub_api_token=HF_TOKEN,
21
+ )
22
+ else:
23
+ llm = None
24
 
25
+ # --- 2. Logic ---
26
  def generate_question_paper(pdf_file, difficulty, num_questions):
27
+ # Error Handling for missing token
 
 
28
  if not HF_TOKEN:
29
+ return "⚠️ Error: HF_TOKEN is missing. Please add it in Space Settings > Secrets.", "Error"
30
 
31
+ if not pdf_file:
32
+ return "⚠️ Please upload a PDF file first.", "Input Error"
33
+
34
  try:
35
+ # Progress updates (simulated for UI feedback)
36
+ yield "πŸ“‚ Reading PDF...", "Processing"
37
  loader = PyPDFLoader(pdf_file.name)
38
  pages = loader.load()
39
 
40
  if not pages:
41
+ return "❌ Error: The PDF appears to be empty or unreadable.", "Error"
42
+
43
+ yield f"βœ‚οΈ Splitting {len(pages)} pages...", "Processing"
44
  text_splitter = RecursiveCharacterTextSplitter(
45
  chunk_size=1000,
46
  chunk_overlap=100
47
  )
48
  chunks = text_splitter.split_documents(pages)
49
+
50
+ yield "🧠 Analyzing content...", "Embedding"
51
  embeddings = FastEmbedEmbeddings()
52
  vector_store = FAISS.from_documents(chunks, embeddings)
53
 
54
+ yield "πŸ” Retrieving key concepts...", "Retrieving"
55
+ retriever = vector_store.as_retriever(search_kwargs={"k": 5})
56
+ context_docs = retriever.invoke("Summary of key topics, definitions, and important details")
57
  context_text = "\n\n".join([doc.page_content for doc in context_docs])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ # Prompt
60
+ template = """
61
+ You are an expert academic examiner. Create a rigorous Question Paper based ONLY on the provided context.
62
 
63
+ CONTEXT:
64
+ {context}
65
+
66
+ INSTRUCTIONS:
67
+ - Difficulty: {difficulty}
68
+ - Total Questions: {num_questions}
69
+ - Structure:
70
+ * Part A: Multiple Choice ({num_questions} questions)
71
+ * Part B: Short Answer (2 questions)
72
+ * Part C: Essay/Long Answer (1 question)
73
+ - Include an "Answer Key" section at the very bottom.
74
 
75
+ OUTPUT FORMAT:
76
+ Return valid Markdown. Use bold headers. Do not output conversational filler.
77
+ """
78
+
79
+ prompt = ChatPromptTemplate.from_template(template)
80
  chain = prompt | llm
81
+
82
+ yield "✨ Generating final paper...", "Generating"
83
  response = chain.invoke({
84
  "context": context_text,
85
  "difficulty": difficulty,
86
  "num_questions": num_questions
87
  })
88
 
89
+ yield response, "Complete"
90
 
91
  except Exception as e:
92
+ yield f"❌ System Error: {str(e)}", "Failed"
93
+
94
+ # --- 3. Custom UI ---
95
+ # Custom CSS for a professional look
96
+ custom_css = """
97
+ .container { max-width: 1200px; margin: auto; padding-top: 20px; }
98
+ .header-text { text-align: center; font-family: 'Helvetica', sans-serif; }
99
+ .header-text h1 { color: #2D3748; font-size: 3em; margin-bottom: 0px; }
100
+ .header-text h3 { color: #718096; font-weight: 300; }
101
+ .submit-btn { background: linear-gradient(90deg, #4F46E5 0%, #7C3AED 100%) !important; color: white !important; border: none !important; }
102
+ .status-bar { border: 1px solid #e2e8f0; background: #f7fafc; padding: 10px; border-radius: 8px; color: #4a5568; }
103
+ """
104
+
105
+ theme = gr.themes.Soft(
106
+ primary_hue="indigo",
107
+ secondary_hue="blue",
108
+ neutral_hue="slate",
109
+ text_size="lg"
110
+ )
111
 
112
+ with gr.Blocks(theme=theme, css=custom_css, title="AI Exam Gen") as demo:
 
 
 
 
113
 
114
+ with gr.Column(elem_classes="container"):
115
+ # Header
116
+ gr.HTML("""
117
+ <div class="header-text">
118
+ <h1>πŸ“ AI Question Paper Generator</h1>
119
+ <h3>Upload study material, get a formatted exam in seconds.</h3>
120
+ </div>
121
+ """)
122
+
123
+ with gr.Row(variant="panel", equal_height=True):
124
+ # Left Column: Inputs
125
+ with gr.Column(scale=1):
126
+ gr.Markdown("### πŸ› οΈ Configuration")
127
+ pdf_input = gr.File(
128
+ label="Upload PDF (Study Notes/Book)",
129
+ file_types=[".pdf"],
130
+ file_count="single",
131
+ height=100
132
  )
133
+
134
+ with gr.Group():
135
+ difficulty = gr.Radio(
136
+ ["Easy", "Medium", "Hard"],
137
+ label="Difficulty Level",
138
+ value="Medium",
139
+ info="Adjusts complexity of questions."
140
+ )
141
+
142
+ num_questions = gr.Slider(
143
+ minimum=5,
144
+ maximum=20,
145
+ value=10,
146
+ step=1,
147
+ label="Number of MCQs",
148
+ info="How many objective questions?"
149
+ )
150
+
151
+ btn = gr.Button("✨ Generate Question Paper", elem_classes="submit-btn", variant="primary")
152
+ status = gr.Textbox(label="Status", placeholder="Ready", interactive=False, max_lines=1)
153
+
154
+ # Right Column: Output
155
+ with gr.Column(scale=2):
156
+ gr.Markdown("### πŸ“„ Generated Exam")
157
+ output = gr.Markdown(
158
+ label="Exam Paper",
159
+ value="_Your generated question paper will appear here..._",
160
+ show_copy_button=True,
161
+ line_breaks=True
162
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
+ # Logic
165
  btn.click(
166
  fn=generate_question_paper,
167
  inputs=[pdf_input, difficulty, num_questions],
168
+ outputs=[output, status]
169
+ )
170
+
171
+ # Footer
172
+ gr.Markdown(
173
+ """
174
+ <div style="text-align: center; color: #a0aec0; margin-top: 40px;">
175
+ Powered by Llama 3 β€’ LangChain β€’ Hugging Face
176
+ </div>
177
+ """
178
  )
 
 
 
 
 
 
179
 
180
  if __name__ == "__main__":
181
  demo.launch()