danxh commited on
Commit
8343769
·
verified ·
1 Parent(s): 137fe5e

Fix: Updated app.py with better error handling and compatibility

Browse files
Files changed (1) hide show
  1. app.py +221 -60
app.py CHANGED
@@ -6,50 +6,62 @@ from peft import PeftModel
6
  import re
7
 
8
  # Model configuration
9
- BASE_MODEL = "deepseek-ai/deepseek-math-7b-instruct"
10
  REPO_ID = "danxh/math-mcq-generator-v1"
11
 
12
- # Load model and tokenizer
13
- @torch.no_grad()
 
 
14
  def load_model():
15
- """Load the fine-tuned model"""
16
-
17
- bnb_config = BitsAndBytesConfig(
18
- load_in_4bit=True,
19
- bnb_4bit_use_double_quant=True,
20
- bnb_4bit_quant_type="nf4",
21
- bnb_4bit_compute_dtype="bfloat16"
22
- )
23
-
24
- # Load base model
25
- base_model = AutoModelForCausalLM.from_pretrained(
26
- BASE_MODEL,
27
- quantization_config=bnb_config,
28
- device_map="auto",
29
- torch_dtype=torch.bfloat16
30
- )
31
 
32
- # Load LoRA adapter
33
- model = PeftModel.from_pretrained(base_model, REPO_ID)
34
-
35
- # Load tokenizer
36
- tokenizer = AutoTokenizer.from_pretrained(REPO_ID)
37
- if tokenizer.pad_token is None:
38
- tokenizer.pad_token = tokenizer.eos_token
39
-
40
- return model, tokenizer
41
-
42
- # Initialize model
43
- print("🔄 Loading model...")
44
- model, tokenizer = load_model()
45
- print("✅ Model loaded successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  def generate_mcq(chapter, topics, difficulty="medium", cognitive_skill="direct_application"):
48
  """Generate MCQ using the fine-tuned model"""
49
 
50
- input_text = f"chapter: {chapter}\ntopics: {topics}\nDifficulty: {difficulty}\nCognitive Skill: {cognitive_skill}"
 
51
 
52
- prompt = f"""### Instruction:
 
 
 
53
  Generate a math MCQ similar in style to the provided examples.
54
 
55
  ### Input:
@@ -57,26 +69,29 @@ Generate a math MCQ similar in style to the provided examples.
57
 
58
  ### Response:
59
  """
60
-
61
- inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=512)
62
- inputs = {k: v.to(model.device) for k, v in inputs.items()}
63
-
64
- with torch.no_grad():
65
- outputs = model.generate(
66
- **inputs,
67
- max_new_tokens=300,
68
- temperature=0.7,
69
- do_sample=True,
70
- pad_token_id=tokenizer.eos_token_id,
71
- eos_token_id=tokenizer.eos_token_id,
72
- repetition_penalty=1.1
73
- )
74
-
75
- generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
76
- response_start = generated_text.find("### Response:") + len("### Response:")
77
- response = generated_text[response_start:].strip()
78
-
79
- return response
 
 
 
80
 
81
  def parse_mcq_response(response):
82
  """Parse the model response"""
@@ -112,13 +127,159 @@ def parse_mcq_response(response):
112
  "error": str(e)
113
  }
114
 
115
- # [Include the web interface function here - copy from above]
116
  def generate_mcq_web(chapter, topics_text, difficulty, cognitive_skill, num_questions=1):
117
- # [Copy the function implementation from above]
118
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
- # Create and launch interface
121
- interface = create_gradio_interface()
 
 
122
 
 
123
  if __name__ == "__main__":
124
  interface.launch()
 
6
  import re
7
 
8
  # Model configuration
9
+ BASE_MODEL = "deepseek-ai/deepseek-math-7b-instruct"
10
  REPO_ID = "danxh/math-mcq-generator-v1"
11
 
12
+ # Global variables for model and tokenizer
13
+ model = None
14
+ tokenizer = None
15
+
16
  def load_model():
17
+ """Load the fine-tuned model with error handling"""
18
+ global model, tokenizer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ try:
21
+ print("🔄 Loading model and tokenizer...")
22
+
23
+ # Simplified loading for Hugging Face Spaces
24
+ bnb_config = BitsAndBytesConfig(
25
+ load_in_4bit=True,
26
+ bnb_4bit_use_double_quant=True,
27
+ bnb_4bit_quant_type="nf4",
28
+ bnb_4bit_compute_dtype=torch.float16 # Changed to float16 for better compatibility
29
+ )
30
+
31
+ # Load base model
32
+ base_model = AutoModelForCausalLM.from_pretrained(
33
+ BASE_MODEL,
34
+ quantization_config=bnb_config,
35
+ device_map="auto",
36
+ torch_dtype=torch.float16,
37
+ trust_remote_code=True
38
+ )
39
+
40
+ # Load LoRA adapter
41
+ model = PeftModel.from_pretrained(base_model, REPO_ID)
42
+
43
+ # Load tokenizer
44
+ tokenizer = AutoTokenizer.from_pretrained(REPO_ID)
45
+ if tokenizer.pad_token is None:
46
+ tokenizer.pad_token = tokenizer.eos_token
47
+
48
+ print("✅ Model loaded successfully!")
49
+ return True
50
+
51
+ except Exception as e:
52
+ print(f"❌ Error loading model: {str(e)}")
53
+ return False
54
 
55
  def generate_mcq(chapter, topics, difficulty="medium", cognitive_skill="direct_application"):
56
  """Generate MCQ using the fine-tuned model"""
57
 
58
+ if model is None or tokenizer is None:
59
+ return "❌ Model not loaded. Please wait for initialization."
60
 
61
+ try:
62
+ input_text = f"chapter: {chapter}\ntopics: {topics}\nDifficulty: {difficulty}\nCognitive Skill: {cognitive_skill}"
63
+
64
+ prompt = f"""### Instruction:
65
  Generate a math MCQ similar in style to the provided examples.
66
 
67
  ### Input:
 
69
 
70
  ### Response:
71
  """
72
+
73
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=512)
74
+ inputs = {k: v.to(model.device) for k, v in inputs.items()}
75
+
76
+ with torch.no_grad():
77
+ outputs = model.generate(
78
+ **inputs,
79
+ max_new_tokens=300,
80
+ temperature=0.7,
81
+ do_sample=True,
82
+ pad_token_id=tokenizer.eos_token_id,
83
+ eos_token_id=tokenizer.eos_token_id,
84
+ repetition_penalty=1.1
85
+ )
86
+
87
+ generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
88
+ response_start = generated_text.find("### Response:") + len("### Response:")
89
+ response = generated_text[response_start:].strip()
90
+
91
+ return response
92
+
93
+ except Exception as e:
94
+ return f"❌ Error generating MCQ: {str(e)}"
95
 
96
  def parse_mcq_response(response):
97
  """Parse the model response"""
 
127
  "error": str(e)
128
  }
129
 
 
130
  def generate_mcq_web(chapter, topics_text, difficulty, cognitive_skill, num_questions=1):
131
+ """Web interface wrapper for MCQ generation"""
132
+
133
+ if model is None or tokenizer is None:
134
+ return """
135
+ <div style="border: 2px solid #ffc107; border-radius: 10px; padding: 20px; margin: 10px 0; background: #fff3cd;">
136
+ <h3 style="color: #856404;">⏳ Model Loading</h3>
137
+ <p>The model is still loading. Please wait a moment and try again.</p>
138
+ </div>
139
+ """
140
+
141
+ try:
142
+ # Parse topics
143
+ topics_list = [t.strip() for t in topics_text.split(',') if t.strip()]
144
+ if not topics_list:
145
+ topics_list = ["General"]
146
+
147
+ results = []
148
+
149
+ for i in range(min(num_questions, 3)): # Limit to 3 questions max
150
+ # Generate MCQ
151
+ raw_response = generate_mcq(chapter, topics_list, difficulty, cognitive_skill)
152
+ parsed = parse_mcq_response(raw_response)
153
+
154
+ if "error" not in parsed:
155
+ # Format for web display
156
+ question_html = f"""
157
+ <div style="border: 2px solid #e1e5e9; border-radius: 10px; padding: 20px; margin: 10px 0; background: #f8f9fa;">
158
+ <h3 style="color: #2c3e50; margin-top: 0;">📚 Question {i+1}</h3>
159
+ <p style="font-size: 16px; line-height: 1.6; margin: 15px 0;"><strong>{parsed['question']}</strong></p>
160
+
161
+ <div style="margin: 15px 0;">
162
+ <h4 style="color: #34495e;">Options:</h4>
163
+ <ul style="list-style: none; padding: 0;">
164
+ <li style="margin: 8px 0; padding: 8px; background: #ecf0f1; border-radius: 5px;">
165
+ <strong>(A)</strong> {parsed['options'][0] if len(parsed['options']) > 0 else 'N/A'}
166
+ </li>
167
+ <li style="margin: 8px 0; padding: 8px; background: #ecf0f1; border-radius: 5px;">
168
+ <strong>(B)</strong> {parsed['options'][1] if len(parsed['options']) > 1 else 'N/A'}
169
+ </li>
170
+ <li style="margin: 8px 0; padding: 8px; background: #ecf0f1; border-radius: 5px;">
171
+ <strong>(C)</strong> {parsed['options'][2] if len(parsed['options']) > 2 else 'N/A'}
172
+ </li>
173
+ <li style="margin: 8px 0; padding: 8px; background: #ecf0f1; border-radius: 5px;">
174
+ <strong>(D)</strong> {parsed['options'][3] if len(parsed['options']) > 3 else 'N/A'}
175
+ </li>
176
+ </ul>
177
+ </div>
178
+
179
+ <div style="margin-top: 15px; padding: 10px; background: #d5edda; border-radius: 5px; border-left: 4px solid #28a745;">
180
+ <strong>✅ Correct Answer: {parsed['correct_answer']}</strong>
181
+ </div>
182
+ </div>
183
+ """
184
+ results.append(question_html)
185
+ else:
186
+ error_html = f"""
187
+ <div style="border: 2px solid #dc3545; border-radius: 10px; padding: 20px; margin: 10px 0; background: #f8d7da;">
188
+ <h3 style="color: #721c24;">❌ Error generating question {i+1}</h3>
189
+ <p>{parsed.get('error', 'Unknown error occurred')}</p>
190
+ </div>
191
+ """
192
+ results.append(error_html)
193
+
194
+ return "".join(results)
195
+
196
+ except Exception as e:
197
+ return f"""
198
+ <div style="border: 2px solid #dc3545; border-radius: 10px; padding: 20px; margin: 10px 0; background: #f8d7da;">
199
+ <h3 style="color: #721c24;">❌ System Error</h3>
200
+ <p>Error: {str(e)}</p>
201
+ </div>
202
+ """
203
+
204
+ # Create the interface
205
+ interface = gr.Interface(
206
+ fn=generate_mcq_web,
207
+ inputs=[
208
+ gr.Textbox(
209
+ label="📚 Chapter",
210
+ placeholder="e.g., Applications of Trigonometry, Conic Sections",
211
+ value="Applications of Trigonometry",
212
+ info="Enter the mathematics chapter or topic area"
213
+ ),
214
+ gr.Textbox(
215
+ label="📝 Topics (comma-separated)",
216
+ placeholder="e.g., Heights and Distances, Circle, Tangents",
217
+ value="Heights and Distances",
218
+ info="Enter specific topics within the chapter, separated by commas"
219
+ ),
220
+ gr.Dropdown(
221
+ choices=["easy", "medium", "hard"],
222
+ label="⚡ Difficulty Level",
223
+ value="medium",
224
+ info="Select the difficulty level for the questions"
225
+ ),
226
+ gr.Dropdown(
227
+ choices=["recall", "direct_application", "pattern_recognition", "strategic_reasoning", "trap_aware"],
228
+ label="🧠 Cognitive Skill",
229
+ value="direct_application",
230
+ info="Select the type of thinking skill required"
231
+ ),
232
+ gr.Slider(
233
+ minimum=1,
234
+ maximum=3,
235
+ step=1,
236
+ label="🔢 Number of Questions",
237
+ value=1,
238
+ info="How many questions to generate (max 3)"
239
+ )
240
+ ],
241
+ outputs=gr.HTML(label="Generated MCQ(s)"),
242
+
243
+ title="🧮 Mathematics MCQ Generator",
244
+ description="""
245
+ Generate high-quality mathematics multiple choice questions using AI.
246
+ This model has been fine-tuned specifically for educational content creation.
247
+
248
+ **Note**: Model loading may take a few minutes on first startup.
249
+ """,
250
+
251
+ article="""
252
+ ### 🔬 About This Model
253
+
254
+ This MCQ generator is powered by a fine-tuned version of DeepSeek-Math-7B, specifically adapted for mathematics education.
255
+
256
+ ### 💡 Tips for Best Results:
257
+ - Be specific with chapter and topic names
258
+ - Try different cognitive skill levels for variety
259
+ - Start with 1 question to test, then generate more
260
+
261
+ ### 🤝 Collaboration
262
+ This is part of a collaborative project to create specialized educational AI tools.
263
+ """,
264
+
265
+ theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple"),
266
+
267
+ examples=[
268
+ ["Applications of Trigonometry", "Heights and Distances", "easy", "recall", 1],
269
+ ["Conic Sections", "Circle", "medium", "pattern_recognition", 1],
270
+ ["Applications of Trigonometry", "Angle of Elevation and Depression", "hard", "strategic_reasoning", 1]
271
+ ]
272
+ )
273
+
274
+ # Initialize model loading
275
+ print("🚀 Starting model loading...")
276
+ model_loaded = load_model()
277
 
278
+ if model_loaded:
279
+ print("✅ Ready to generate MCQs!")
280
+ else:
281
+ print("❌ Model loading failed. The interface may not work properly.")
282
 
283
+ # Launch the interface
284
  if __name__ == "__main__":
285
  interface.launch()