retvq commited on
Commit
7ef2d1a
Β·
verified Β·
1 Parent(s): 21dbca6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -132
app.py CHANGED
@@ -1,6 +1,5 @@
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,176 +7,133 @@ from langchain_community.vectorstores import FAISS
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
- # UPDATED: theme and css removed from here
113
- with gr.Blocks(title="AI Exam Gen") as demo:
 
 
 
114
 
115
- with gr.Column(elem_classes="container"):
116
- # Header
117
- gr.HTML("""
118
- <div class="header-text">
119
- <h1>πŸ“ AI Question Paper Generator</h1>
120
- <h3>Upload study material, get a formatted exam in seconds.</h3>
121
- </div>
122
- """)
123
-
124
- with gr.Row(variant="panel", equal_height=True):
125
- # Left Column: Inputs
126
- with gr.Column(scale=1):
127
- gr.Markdown("### πŸ› οΈ Configuration")
128
- pdf_input = gr.File(
129
- label="Upload PDF (Study Notes/Book)",
130
- file_types=[".pdf"],
131
- file_count="single",
132
- height=100
133
  )
134
-
135
- with gr.Group():
136
- difficulty = gr.Radio(
137
- ["Easy", "Medium", "Hard"],
138
- label="Difficulty Level",
139
- value="Medium",
140
- info="Adjusts complexity of questions."
141
- )
142
-
143
- num_questions = gr.Slider(
144
- minimum=5,
145
- maximum=20,
146
- value=10,
147
- step=1,
148
- label="Number of MCQs",
149
- info="How many objective questions?"
150
- )
151
-
152
- btn = gr.Button("✨ Generate Question Paper", elem_classes="submit-btn", variant="primary")
153
- status = gr.Textbox(label="Status", placeholder="Ready", interactive=False, max_lines=1)
154
-
155
- # Right Column: Output
156
- with gr.Column(scale=2):
157
- gr.Markdown("### πŸ“„ Generated Exam")
158
- output = gr.Markdown(
159
- label="Exam Paper",
160
- value="_Your generated question paper will appear here..._",
161
- show_copy_button=True,
162
- line_breaks=True
163
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
- # Logic
166
  btn.click(
167
  fn=generate_question_paper,
168
  inputs=[pdf_input, difficulty, num_questions],
169
- outputs=[output, status]
170
- )
171
-
172
- # Footer
173
- gr.Markdown(
174
- """
175
- <div style="text-align: center; color: #a0aec0; margin-top: 40px;">
176
- Powered by Llama 3 β€’ LangChain β€’ Hugging Face
177
- </div>
178
- """
179
  )
 
 
 
 
 
 
180
 
181
  if __name__ == "__main__":
182
- # UPDATED: theme and css moved here for Gradio 6 compatibility
183
- demo.launch(theme=theme, css=custom_css)
 
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
  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()