Rathapoom commited on
Commit
a7fb4a0
1 Parent(s): eaab3cb

Update app(backup2).py

Browse files
Files changed (1) hide show
  1. app(backup2).py +159 -107
app(backup2).py CHANGED
@@ -4,10 +4,15 @@ from openai import OpenAI
4
  import time
5
  import gspread
6
  from oauth2client.service_account import ServiceAccountCredentials
 
 
7
 
8
  # Set up OpenAI client
9
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
10
 
 
 
 
11
  # Google Sheets setup remains the same
12
  scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
13
  creds = ServiceAccountCredentials.from_json_keyfile_name("genexam-2c8c645ecc0d.json", scope)
@@ -34,52 +39,131 @@ def update_api_usage(username):
34
  except Exception as e:
35
  st.error(f"Error updating API usage: {str(e)}")
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  def generate_questions_with_retry(knowledge_material, question_type, cognitive_level, extra_instructions, case_based, num_choices=None, max_retries=3):
38
  # Adjust number of questions based on type
39
  if question_type == "Multiple Choice":
40
  num_questions = 3
 
 
 
 
 
 
 
 
 
41
  elif question_type == "Fill in the Blank":
42
  num_questions = 10
 
 
 
 
 
 
 
 
43
  elif question_type == "True/False":
44
  num_questions = 5
 
 
 
 
 
 
 
 
45
  else: # Open-ended
46
  num_questions = 3
 
 
 
 
 
 
 
 
 
 
47
 
48
  # Base prompt
49
- prompt = f"Generate {num_questions} {question_type.lower()} exam questions based on {cognitive_level.lower()} level from the following material: {knowledge_material}. {extra_instructions}"
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  # Modify prompt for case-based medical situations
52
  if case_based:
53
- prompt = f"Generate {num_questions} {question_type.lower()} exam questions based on {cognitive_level.lower()} level from the following medical material: {knowledge_material}. The questions should be based on case-based medical situations, such as patient scenarios. {extra_instructions}"
54
- if question_type != "Fill in the Blank":
55
- prompt += " Provide answers with short explanations."
56
 
57
- # Add specific handling for Multiple Choice and True/False
58
- if question_type == "Multiple Choice" and num_choices:
59
- prompt += f" Each multiple choice question should have {num_choices} choices."
60
 
61
- if question_type == "True/False":
62
- prompt += " Provide short explanations for each question based on the given material, without stating True or False explicitly."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  retries = 0
65
  while retries < max_retries:
66
  try:
67
  response = client.chat.completions.create(
68
- model="gpt-4o-mini", # or your preferred model
69
  messages=[
70
- {"role": "system", "content": "You are a helpful assistant for generating exam questions."},
71
  {"role": "user", "content": prompt}
72
- ]
 
 
73
  )
74
  return response.choices[0].message.content
75
  except Exception as e:
76
  retries += 1
 
77
  if retries == max_retries:
78
  st.error(f"Failed to generate questions after {max_retries} attempts. Error: {str(e)}")
79
  return None
80
- time.sleep(2) # Wait before retrying
81
 
82
  # ระบบ login
 
83
  if 'username' not in st.session_state:
84
  st.title("Login")
85
  username_input = st.text_input("Enter your username:")
@@ -94,106 +178,74 @@ if 'username' not in st.session_state:
94
  else:
95
  st.warning("Please enter a valid username.")
96
  else:
97
- # Main App after login
98
  st.title(f"Welcome, {st.session_state['username']}! Generate your exam questions")
99
-
100
- # Input field for knowledge material (text) with 3,000-word limit
101
- knowledge_material = st.text_area("Enter knowledge material to generate exam questions:")
102
 
103
- # Word count check
104
- if len(knowledge_material.split()) > 3000:
105
- st.warning("Please limit the knowledge material to 3,000 words or fewer.")
106
-
107
- # File uploader for PDFs (limited to 5 MB)
108
- uploaded_file = st.file_uploader("Upload a file (PDF)", type="pdf")
109
 
110
- if uploaded_file is not None:
111
- if uploaded_file.size > 5 * 1024 * 1024: # 5 MB limit
112
- st.warning("File size exceeds 5 MB. Please upload a smaller file.")
113
- else:
114
- st.success("File uploaded successfully! (Text extraction not implemented yet.)")
115
-
116
- # Select question type
117
- question_type = st.selectbox("Select question type:",
118
- ["Multiple Choice", "Fill in the Blank", "Open-ended", "True/False"])
119
-
120
- # For multiple choice, let users select the number of choices
121
- num_choices = None
122
- if question_type == "Multiple Choice":
123
- num_choices = st.selectbox("Select the number of choices for each question:", [3, 4, 5])
124
-
125
- # Select cognitive level
126
- cognitive_level = st.selectbox("Select cognitive level:",
127
- ["Recall", "Understanding", "Application", "Analysis", "Synthesis", "Evaluation"])
128
-
129
- # Checkbox for Case-Based Medical Situations
130
- case_based = st.checkbox("Generate case-based medical exam questions")
131
 
132
- # Extra input field for additional instructions (placed below cognitive level)
133
- extra_instructions = st.text_area("Enter additional instructions (e.g., how you want the questions to be phrased):")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  # Generate questions button
136
- if 'previous_questions' not in st.session_state:
137
- st.session_state['previous_questions'] = []
138
-
139
  if st.button("Generate Questions"):
140
- if len(knowledge_material.split()) <= 3000:
141
- # Generate questions with retry logic
142
- questions = generate_questions_with_retry(
143
- knowledge_material,
144
- question_type,
145
- cognitive_level,
146
- extra_instructions,
147
- case_based,
148
- num_choices
149
- )
150
-
151
- if questions:
152
- st.write("Generated Exam Questions:")
153
- st.write(questions)
154
-
155
- # Avoid showing repeated content in future requests
156
- st.session_state['previous_questions'].append(questions)
157
-
158
- # Option to download the questions as a text file
159
- st.download_button(
160
- label="Download Questions",
161
- data=questions,
162
- file_name='generated_questions.txt',
163
- mime='text/plain'
164
- )
165
- else:
166
- st.warning("Please reduce the word count to 3,000 or fewer.")
167
-
168
- # Button to generate more questions based on the same material
169
- if st.button("Generate More Questions"):
170
- if len(knowledge_material.split()) <= 3000:
171
- # Regenerate new questions, trying to avoid repeated content
172
- questions = generate_questions_with_retry(
173
- knowledge_material,
174
- question_type,
175
- cognitive_level,
176
- extra_instructions,
177
- case_based,
178
- num_choices
179
- )
180
-
181
- # Check if the new set of questions is not the same as the previous set
182
- if questions and questions not in st.session_state['previous_questions']:
183
- st.write("Generated More Exam Questions:")
184
- st.write(questions)
185
-
186
- # Append the new questions to the session state
187
- st.session_state['previous_questions'].append(questions)
188
-
189
- # Option to download the new set of questions
190
- st.download_button(
191
- label="Download More Questions",
192
- data=questions,
193
- file_name='more_generated_questions.txt',
194
- mime='text/plain'
195
  )
196
- else:
197
- st.warning("New questions seem to overlap with the previous ones. Try adjusting the instructions.")
 
 
 
 
 
 
 
 
 
 
198
  else:
199
- st.warning("Please reduce the word count to 3,000 or fewer.")
 
4
  import time
5
  import gspread
6
  from oauth2client.service_account import ServiceAccountCredentials
7
+ import PyPDF2
8
+ import io
9
 
10
  # Set up OpenAI client
11
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
12
 
13
+ # Constants
14
+ WORD_LIMIT = 8000
15
+
16
  # Google Sheets setup remains the same
17
  scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
18
  creds = ServiceAccountCredentials.from_json_keyfile_name("genexam-2c8c645ecc0d.json", scope)
 
39
  except Exception as e:
40
  st.error(f"Error updating API usage: {str(e)}")
41
 
42
+ def extract_text_from_pdf(pdf_file):
43
+ """Simple PDF text extraction with word limit check"""
44
+ try:
45
+ pdf_reader = PyPDF2.PdfReader(io.BytesIO(pdf_file.read()))
46
+ text_content = ""
47
+ for page in pdf_reader.pages:
48
+ text_content += page.extract_text() + "\n"
49
+
50
+ word_count = len(text_content.split())
51
+ if word_count > WORD_LIMIT:
52
+ return None, f"PDF content exceeds {WORD_LIMIT:,} words (contains {word_count:,} words). Please use a shorter document."
53
+ return text_content, None
54
+ except Exception as e:
55
+ return None, f"Error processing PDF: {str(e)}"
56
+
57
  def generate_questions_with_retry(knowledge_material, question_type, cognitive_level, extra_instructions, case_based, num_choices=None, max_retries=3):
58
  # Adjust number of questions based on type
59
  if question_type == "Multiple Choice":
60
  num_questions = 3
61
+ format_instructions = f"""
62
+ For each multiple choice question:
63
+ 1. Present the question clearly
64
+ 2. Provide {num_choices} choices labeled with A, B, C{', D' if num_choices > 3 else ''}{', E' if num_choices > 4 else ''} after get new line from question
65
+ 3. After all questions, provide an ANSWER KEY section with:
66
+ - The correct answer letter for each question
67
+ - A brief explanation of why this is the correct answer
68
+ - Why other options are incorrect
69
+ """
70
  elif question_type == "Fill in the Blank":
71
  num_questions = 10
72
+ format_instructions = """
73
+ For each fill-in-the-blank question:
74
+ 1. Present the question with a clear blank space indicated by _____
75
+ 2. After all questions, provide an ANSWER KEY section with:
76
+ - The correct answer for each blank
77
+ - A brief explanation of why this answer is correct
78
+ - Any alternative acceptable answers if applicable
79
+ """
80
  elif question_type == "True/False":
81
  num_questions = 5
82
+ format_instructions = """
83
+ For each true/false question:
84
+ 1. Present the statement clearly
85
+ 2. After all questions, provide an ANSWER KEY section with:
86
+ - Whether the statement is True or False
87
+ - A detailed explanation of why the statement is true or false
88
+ - The specific part of the source material that supports this answer
89
+ """
90
  else: # Open-ended
91
  num_questions = 3
92
+ format_instructions = """
93
+ For each open-ended question:
94
+ 1. Present the question clearly
95
+ 2. After all questions, provide an ANSWER KEY section with:
96
+ - A structured scoring checklist of key points (minimum 3-5 points per question)
97
+ - Each key point should be worth a specific number of marks
98
+ - Total marks available for each question
99
+ - Sample answer that would receive full marks
100
+ - Common points that students might miss
101
+ """
102
 
103
  # Base prompt
104
+ prompt = f"""Generate {num_questions} {question_type.lower()} exam questions based on {cognitive_level.lower()} level from the following material:
105
+
106
+ {knowledge_material}
107
+
108
+ {format_instructions}
109
+
110
+ {extra_instructions}
111
+
112
+ Please format the output clearly with:
113
+ 1. Questions section (numbered 1, 2, 3, etc.)
114
+ 2. Answer Key section (clearly separated from questions)
115
+ 3. Each answer should include explanation for better understanding
116
+
117
+ Make sure all questions and answers are directly related to the provided material."""
118
 
119
  # Modify prompt for case-based medical situations
120
  if case_based:
121
+ prompt = f"""Generate {num_questions} {question_type.lower()} case-based medical exam questions based on {cognitive_level.lower()} level.
 
 
122
 
123
+ Use this material as the medical knowledge base:
124
+ {knowledge_material}
 
125
 
126
+ Each question should:
127
+ 1. Start with a medical case scenario/patient presentation
128
+ 2. Include relevant clinical details
129
+ 3. Ask about diagnosis, treatment, or management
130
+ 4. Be at {cognitive_level.lower()} cognitive level
131
+
132
+ {format_instructions}
133
+
134
+ {extra_instructions}
135
+
136
+ Please format the output with:
137
+ 1. Cases and Questions (numbered 1, 2, 3, etc.)
138
+ 2. Detailed Answer Key section including:
139
+ - Correct answers
140
+ - Clinical reasoning
141
+ - Key diagnostic or treatment considerations
142
+ - Common pitfalls to avoid"""
143
 
144
  retries = 0
145
  while retries < max_retries:
146
  try:
147
  response = client.chat.completions.create(
148
+ model="gpt-4o-mini",
149
  messages=[
150
+ {"role": "system", "content": "You are an expert exam question generator with deep knowledge in medical education. Create clear, well-structured questions with detailed answer keys and explanations."},
151
  {"role": "user", "content": prompt}
152
+ ],
153
+ temperature=0.7,
154
+ max_tokens=3000 # Increased to accommodate answers and explanations
155
  )
156
  return response.choices[0].message.content
157
  except Exception as e:
158
  retries += 1
159
+ st.warning(f"Attempt {retries} failed. Retrying... Error: {str(e)}")
160
  if retries == max_retries:
161
  st.error(f"Failed to generate questions after {max_retries} attempts. Error: {str(e)}")
162
  return None
163
+ time.sleep(2)
164
 
165
  # ระบบ login
166
+ # Main Streamlit interface
167
  if 'username' not in st.session_state:
168
  st.title("Login")
169
  username_input = st.text_input("Enter your username:")
 
178
  else:
179
  st.warning("Please enter a valid username.")
180
  else:
 
181
  st.title(f"Welcome, {st.session_state['username']}! Generate your exam questions")
 
 
 
182
 
183
+ # Create tabs for input methods
184
+ tab1, tab2 = st.tabs(["Text Input", "PDF Upload"])
 
 
 
 
185
 
186
+ with tab1:
187
+ knowledge_material = st.text_area("Enter knowledge material to generate exam questions:")
188
+ word_count = len(knowledge_material.split())
189
+ if word_count > WORD_LIMIT:
190
+ st.error(f"Text exceeds {WORD_LIMIT:,} words. Please shorten your content.")
191
+
192
+ with tab2:
193
+ st.info(f"Maximum content length: {WORD_LIMIT:,} words")
194
+ uploaded_file = st.file_uploader("Upload a PDF file", type="pdf")
195
+
196
+ if uploaded_file is not None:
197
+ pdf_content, error = extract_text_from_pdf(uploaded_file)
198
+ if error:
199
+ st.error(error)
200
+ else:
201
+ st.success("PDF processed successfully!")
202
+ knowledge_material = pdf_content
 
 
 
 
203
 
204
+ # Question generation options
205
+ col1, col2 = st.columns(2)
206
+
207
+ with col1:
208
+ question_type = st.selectbox(
209
+ "Select question type:",
210
+ ["Multiple Choice", "Fill in the Blank", "Open-ended", "True/False"]
211
+ )
212
+
213
+ if question_type == "Multiple Choice":
214
+ num_choices = st.selectbox("Select number of choices:", [3, 4, 5])
215
+
216
+ cognitive_level = st.selectbox(
217
+ "Select cognitive level:",
218
+ ["Recall", "Understanding", "Application", "Analysis", "Synthesis", "Evaluation"]
219
+ )
220
+
221
+ with col2:
222
+ case_based = st.checkbox("Generate case-based medical exam questions")
223
+ extra_instructions = st.text_area("Additional instructions (optional):")
224
 
225
  # Generate questions button
 
 
 
226
  if st.button("Generate Questions"):
227
+ if 'knowledge_material' in locals() and knowledge_material.strip():
228
+ with st.spinner("Generating questions..."):
229
+ # Your existing generate_questions_with_retry function call here
230
+ questions = generate_questions_with_retry(
231
+ knowledge_material,
232
+ question_type,
233
+ cognitive_level,
234
+ extra_instructions,
235
+ case_based,
236
+ num_choices if question_type == "Multiple Choice" else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  )
238
+
239
+ if questions:
240
+ st.write("### Generated Exam Questions:")
241
+ st.write(questions)
242
+
243
+ # Download button
244
+ st.download_button(
245
+ label="Download Questions",
246
+ data=questions,
247
+ file_name='generated_questions.txt',
248
+ mime='text/plain'
249
+ )
250
  else:
251
+ st.warning("Please enter knowledge material or upload a PDF file first.")