Spaces:
Sleeping
Sleeping
Create app(backup2).py
Browse files- app(backup2).py +199 -0
app(backup2).py
ADDED
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import openai
|
3 |
+
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)
|
14 |
+
client_gs = gspread.authorize(creds)
|
15 |
+
sheet = client_gs.open("GeneXam user").sheet1
|
16 |
+
|
17 |
+
def check_user_in_sheet(username):
|
18 |
+
try:
|
19 |
+
users_list = sheet.col_values(1)
|
20 |
+
if username in users_list:
|
21 |
+
return True
|
22 |
+
return False
|
23 |
+
except Exception as e:
|
24 |
+
st.error(f"Error checking user: {str(e)}")
|
25 |
+
return False
|
26 |
+
|
27 |
+
def update_api_usage(username):
|
28 |
+
try:
|
29 |
+
users_list = sheet.col_values(1)
|
30 |
+
row_number = users_list.index(username) + 1
|
31 |
+
api_usage = int(sheet.cell(row_number, 2).value)
|
32 |
+
api_usage += 1
|
33 |
+
sheet.update_cell(row_number, 2, api_usage)
|
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:")
|
86 |
+
if st.button("Login"):
|
87 |
+
if username_input:
|
88 |
+
if check_user_in_sheet(username_input):
|
89 |
+
st.session_state['username'] = username_input
|
90 |
+
st.success(f"Welcome, {username_input}!")
|
91 |
+
update_api_usage(username_input)
|
92 |
+
else:
|
93 |
+
st.warning("Username not found. Please try again.")
|
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.")
|