Nitish035 commited on
Commit
a317a55
·
verified ·
1 Parent(s): 3492243

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +215 -14
src/streamlit_app.py CHANGED
@@ -1,31 +1,204 @@
1
- import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- # 1) create a writable cache folder
4
- os.makedirs("/tmp/hf_cache", exist_ok=True)
 
5
 
6
- # 2) point HF env vars at it
7
- os.environ["HF_HOME"] = "/tmp/hf_cache"
8
- os.environ["HF_HUB_CACHE"] = "/tmp/hf_cache"
9
- # For older versions, you can also set:
10
- # os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
 
 
13
 
14
  import streamlit as st
15
  import json
16
  import re
17
  import random
 
18
  from typing import Dict, List, Optional, Set
19
  from huggingface_hub import hf_hub_download
20
  from llama_cpp import Llama
21
 
 
 
 
 
22
  @st.cache_resource
23
  def load_model():
24
  model_path = hf_hub_download(
25
  repo_id="Nitish035/gguf_4",
26
  filename="unsloth.Q4_K_M.gguf",
27
-
 
28
  )
 
29
  model = Llama(
30
  model_path=model_path,
31
  n_ctx=4096,
@@ -83,27 +256,22 @@ def generate_response(prompt_dict, max_tokens=3024):
83
 
84
  prompt = f"""<|im_start|>user
85
  Generate a {prompt_dict['Difficulty']} difficulty math multiple-choice question with options and correct answer with these specifications:
86
-
87
  * Grade Level: {prompt_dict['Grade']}
88
  * Topic: {prompt_dict['Topic']} (align with appropriate CCSS standard)
89
  * Depth of Knowledge (DOK): Level {prompt_dict['DOK']} ({dok_descriptions[prompt_dict['DOK']]})
90
  * Difficulty: {prompt_dict['Difficulty']} ({difficulty_levels[prompt_dict['Difficulty']]})
91
  * Context: {random.choice(contexts)}
92
  * Math Operations: {random.choice(operations)}
93
-
94
  1. Create a unique word problem based on the context and operations
95
  2. Design a question that matches DOK level {prompt_dict['DOK']}
96
  3. Create four plausible options with one clearly correct answer
97
  4. Format as a clean multiple-choice question
98
-
99
  # Requirements:
100
-
101
  1. The question must be unique and different from previous questions
102
  2. Make sure the final answer computed in the explanation is inserted into one of the 4 options
103
  3. The `correct_answer` key must match the option letter that holds the correct answer
104
  4. Options should reflect common student misconceptions
105
  5. Format the response as a JSON object with these keys: 'question', 'options', 'correct_answer', 'explanation'
106
-
107
  <|im_end|>
108
  <|im_start|>assistant
109
  """
@@ -148,10 +316,20 @@ def main():
148
  difficulty = get_difficulty(dok_level)
149
  all_questions = []
150
  generated_questions = set()
 
 
 
 
151
 
152
  for i in range(no_of_questions):
 
 
 
153
  attempts = 0
154
  while attempts < 3:
 
 
 
155
  prompt_dict = {
156
  "Grade": str(grade_level),
157
  "Topic": topic,
@@ -162,15 +340,38 @@ def main():
162
  response_text = generate_response(prompt_dict)
163
  parsed_json = try_parse_json(response_text)
164
 
 
 
 
165
  if parsed_json and parsed_json.get('question') and parsed_json['question'] not in generated_questions:
166
  generated_questions.add(parsed_json['question'])
167
  all_questions.append(parsed_json)
 
 
 
 
 
168
  break
169
  attempts += 1
 
 
 
 
 
170
 
171
  st.subheader("Generated Questions:")
172
  if all_questions:
173
  st.json(all_questions)
 
 
 
 
 
 
 
 
 
 
174
  else:
175
  st.error("Failed to generate unique questions. Please try again.")
176
 
 
1
+ # import os
2
+
3
+ # # 1) create a writable cache folder
4
+ # os.makedirs("/tmp/hf_cache", exist_ok=True)
5
+
6
+ # # 2) point HF env vars at it
7
+ # os.environ["HF_HOME"] = "/tmp/hf_cache"
8
+ # os.environ["HF_HUB_CACHE"] = "/tmp/hf_cache"
9
+ # # For older versions, you can also set:
10
+ # # os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache"
11
+
12
+
13
+
14
+ # import streamlit as st
15
+ # import json
16
+ # import re
17
+ # import random
18
+ # from typing import Dict, List, Optional, Set
19
+ # from huggingface_hub import hf_hub_download
20
+ # from llama_cpp import Llama
21
+
22
+ # @st.cache_resource
23
+ # def load_model():
24
+ # model_path = hf_hub_download(
25
+ # repo_id="Nitish035/gguf_4",
26
+ # filename="unsloth.Q4_K_M.gguf",
27
+
28
+ # )
29
+ # model = Llama(
30
+ # model_path=model_path,
31
+ # n_ctx=4096,
32
+ # n_gpu_layers=35,
33
+ # verbose=False,
34
+ # )
35
+ # return model
36
+
37
+ # model = load_model()
38
+
39
+ # def get_difficulty(dok):
40
+ # difficulty_map = {
41
+ # 1: "Easy",
42
+ # 2: "Medium",
43
+ # 3: "Hard",
44
+ # 4: "Very Hard"
45
+ # }
46
+ # return difficulty_map.get(dok, "Medium")
47
+
48
+ # def generate_response(prompt_dict, max_tokens=3024):
49
+ # dok_descriptions = {
50
+ # 1: "Basic recall of math facts, definitions, or simple calculations",
51
+ # 2: "Application of math concepts requiring 1-2 step procedures",
52
+ # 3: "Multi-step math problems requiring analysis and justification",
53
+ # 4: "Complex math problems needing synthesis and creative approaches"
54
+ # }
55
+
56
+ # difficulty_levels = {
57
+ # "Easy": "Multi-step problems requiring reasoning and understanding of concepts - easy; Straightforward problems with obvious approaches.",
58
+ # "Medium": "Multi-step problems requiring moderate reasoning and understanding of concepts - medium; Requires careful analysis but standard methods apply.",
59
+ # "Hard": "Complex multi-step problems with multiple variables and operations - hard; Demands innovative thinking and multiple concepts.",
60
+ # "Very Hard": "Advanced problems requiring systems of equations, conditional logic, and optimization - very hard; Requires advanced reasoning, optimization strategies, and integration of multiple topics."
61
+ # }
62
+
63
+ # contexts = [
64
+ # "a school fundraiser",
65
+ # "a community bake sale",
66
+ # "a sports team's snack stand",
67
+ # "a charity event",
68
+ # "a classroom project",
69
+ # "",
70
+ # "",
71
+ # ""
72
+ # ]
73
+
74
+ # operations = [
75
+ # "addition and subtraction",
76
+ # "multiplication and division",
77
+ # "fractions and percentages",
78
+ # "ratios and proportions",
79
+ # "algebraic equations",
80
+ # "",
81
+ # ""
82
+ # ]
83
+
84
+ # prompt = f"""<|im_start|>user
85
+ # Generate a {prompt_dict['Difficulty']} difficulty math multiple-choice question with options and correct answer with these specifications:
86
+
87
+ # * Grade Level: {prompt_dict['Grade']}
88
+ # * Topic: {prompt_dict['Topic']} (align with appropriate CCSS standard)
89
+ # * Depth of Knowledge (DOK): Level {prompt_dict['DOK']} ({dok_descriptions[prompt_dict['DOK']]})
90
+ # * Difficulty: {prompt_dict['Difficulty']} ({difficulty_levels[prompt_dict['Difficulty']]})
91
+ # * Context: {random.choice(contexts)}
92
+ # * Math Operations: {random.choice(operations)}
93
+
94
+ # 1. Create a unique word problem based on the context and operations
95
+ # 2. Design a question that matches DOK level {prompt_dict['DOK']}
96
+ # 3. Create four plausible options with one clearly correct answer
97
+ # 4. Format as a clean multiple-choice question
98
+
99
+ # # Requirements:
100
+
101
+ # 1. The question must be unique and different from previous questions
102
+ # 2. Make sure the final answer computed in the explanation is inserted into one of the 4 options
103
+ # 3. The `correct_answer` key must match the option letter that holds the correct answer
104
+ # 4. Options should reflect common student misconceptions
105
+ # 5. Format the response as a JSON object with these keys: 'question', 'options', 'correct_answer', 'explanation'
106
 
107
+ # <|im_end|>
108
+ # <|im_start|>assistant
109
+ # """
110
 
111
+ # response = model.create_completion(
112
+ # prompt=prompt,
113
+ # max_tokens=max_tokens,
114
+ # temperature=0.7,
115
+ # top_p=0.9,
116
+ # echo=False
117
+ # )
118
+
119
+ # return response['choices'][0]['text']
120
+
121
+ # def try_parse_json(response_text):
122
+ # try:
123
+ # match = re.search(r'{.*}', response_text, re.DOTALL)
124
+ # if match:
125
+ # return json.loads(match.group())
126
+ # return None
127
+ # except json.JSONDecodeError as e:
128
+ # st.error(f"Failed to parse JSON response: {e}")
129
+ # return None
130
+
131
+ # def main():
132
+ # st.title("DOK-Based Math Question Generator")
133
+ # st.write("Generate math questions based on a Depth of Knowledge level")
134
+
135
+ # dok_level = st.selectbox("Select DOK Level:", [1, 2, 3, 4])
136
+ # no_of_questions = st.slider("Number of Questions:", 1, 2)
137
+ # topic = st.selectbox("Select Topic:", [
138
+ # "Functions",
139
+ # "Statistics and Probability",
140
+ # "Geometry",
141
+ # "Expressions and Equations",
142
+ # "Number System",
143
+ # "Ratios and Proportional"
144
+ # ])
145
+ # grade_level = st.selectbox("Select Grade Level:", [6, 7, 8])
146
+
147
+ # if st.button("Generate Questions"):
148
+ # difficulty = get_difficulty(dok_level)
149
+ # all_questions = []
150
+ # generated_questions = set()
151
 
152
+ # for i in range(no_of_questions):
153
+ # attempts = 0
154
+ # while attempts < 3:
155
+ # prompt_dict = {
156
+ # "Grade": str(grade_level),
157
+ # "Topic": topic,
158
+ # "DOK": dok_level,
159
+ # "Difficulty": difficulty
160
+ # }
161
+
162
+ # response_text = generate_response(prompt_dict)
163
+ # parsed_json = try_parse_json(response_text)
164
+
165
+ # if parsed_json and parsed_json.get('question') and parsed_json['question'] not in generated_questions:
166
+ # generated_questions.add(parsed_json['question'])
167
+ # all_questions.append(parsed_json)
168
+ # break
169
+ # attempts += 1
170
+
171
+ # st.subheader("Generated Questions:")
172
+ # if all_questions:
173
+ # st.json(all_questions)
174
+ # else:
175
+ # st.error("Failed to generate unique questions. Please try again.")
176
 
177
+ # if __name__ == "__main__":
178
+ # main()
179
 
180
  import streamlit as st
181
  import json
182
  import re
183
  import random
184
+ import os
185
  from typing import Dict, List, Optional, Set
186
  from huggingface_hub import hf_hub_download
187
  from llama_cpp import Llama
188
 
189
+ # Use /tmp directory which is writable in the Docker container
190
+ MODEL_CACHE_DIR = "/tmp/model_cache"
191
+ os.makedirs(MODEL_CACHE_DIR, exist_ok=True)
192
+
193
  @st.cache_resource
194
  def load_model():
195
  model_path = hf_hub_download(
196
  repo_id="Nitish035/gguf_4",
197
  filename="unsloth.Q4_K_M.gguf",
198
+ local_dir=MODEL_CACHE_DIR,
199
+ cache_dir=MODEL_CACHE_DIR,
200
  )
201
+
202
  model = Llama(
203
  model_path=model_path,
204
  n_ctx=4096,
 
256
 
257
  prompt = f"""<|im_start|>user
258
  Generate a {prompt_dict['Difficulty']} difficulty math multiple-choice question with options and correct answer with these specifications:
 
259
  * Grade Level: {prompt_dict['Grade']}
260
  * Topic: {prompt_dict['Topic']} (align with appropriate CCSS standard)
261
  * Depth of Knowledge (DOK): Level {prompt_dict['DOK']} ({dok_descriptions[prompt_dict['DOK']]})
262
  * Difficulty: {prompt_dict['Difficulty']} ({difficulty_levels[prompt_dict['Difficulty']]})
263
  * Context: {random.choice(contexts)}
264
  * Math Operations: {random.choice(operations)}
 
265
  1. Create a unique word problem based on the context and operations
266
  2. Design a question that matches DOK level {prompt_dict['DOK']}
267
  3. Create four plausible options with one clearly correct answer
268
  4. Format as a clean multiple-choice question
 
269
  # Requirements:
 
270
  1. The question must be unique and different from previous questions
271
  2. Make sure the final answer computed in the explanation is inserted into one of the 4 options
272
  3. The `correct_answer` key must match the option letter that holds the correct answer
273
  4. Options should reflect common student misconceptions
274
  5. Format the response as a JSON object with these keys: 'question', 'options', 'correct_answer', 'explanation'
 
275
  <|im_end|>
276
  <|im_start|>assistant
277
  """
 
316
  difficulty = get_difficulty(dok_level)
317
  all_questions = []
318
  generated_questions = set()
319
+ time_stats = []
320
+
321
+ st.subheader("Generating questions...")
322
+ progress_bar = st.progress(0)
323
 
324
  for i in range(no_of_questions):
325
+ question_placeholder = st.empty()
326
+ question_placeholder.text(f"Generating question {i+1}/{no_of_questions}...")
327
+
328
  attempts = 0
329
  while attempts < 3:
330
+ import time
331
+ start_time = time.time()
332
+
333
  prompt_dict = {
334
  "Grade": str(grade_level),
335
  "Topic": topic,
 
340
  response_text = generate_response(prompt_dict)
341
  parsed_json = try_parse_json(response_text)
342
 
343
+ end_time = time.time()
344
+ generation_time = end_time - start_time
345
+
346
  if parsed_json and parsed_json.get('question') and parsed_json['question'] not in generated_questions:
347
  generated_questions.add(parsed_json['question'])
348
  all_questions.append(parsed_json)
349
+ time_stats.append({
350
+ "question_number": i+1,
351
+ "generation_time_seconds": round(generation_time, 2),
352
+ "attempts": attempts+1
353
+ })
354
  break
355
  attempts += 1
356
+
357
+ progress_bar.progress((i+1)/no_of_questions)
358
+ question_placeholder.empty()
359
+
360
+ progress_bar.empty()
361
 
362
  st.subheader("Generated Questions:")
363
  if all_questions:
364
  st.json(all_questions)
365
+
366
+ # Display timing information
367
+ st.subheader("Generation Time Statistics:")
368
+ for stat in time_stats:
369
+ st.write(f"Question {stat['question_number']}: Generated in {stat['generation_time_seconds']} seconds (after {stat['attempts']} attempt(s))")
370
+
371
+ # Calculate and display average generation time
372
+ if time_stats:
373
+ avg_time = sum(stat['generation_time_seconds'] for stat in time_stats) / len(time_stats)
374
+ st.write(f"Average generation time: {round(avg_time, 2)} seconds per question")
375
  else:
376
  st.error("Failed to generate unique questions. Please try again.")
377