Vipul Swarup
scaffolding for student input
609654e
Raw
History Blame Contribute Delete
8.82 kB
# This is an app that uses the OpenAI API and the Chat GPT 4 model.
# It generates Free Response Questions for students based on a Common Core Standard and Area of Interest
# It takes as input: (1) The common core standard to use, (2) The area of interest
import streamlit as st
import json
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
AIMessage,
HumanMessage,
SystemMessage
)
#App UI starts here
st.set_page_config(page_title="FRQ Generator", page_icon=":robot:")
st.header("FRQs using GPT-4")
st.subheader("IMPORTANT: Please wait 60-70 seconds between responses. Chat GPT takes time to think.")
header_text=str('''
Paste a JSON file here, with the following information:
1. The name of the common core standard,
2. The student's area of interest.
E.g.
```
{
"input":"frq-generator",
"entries":[
{"cc-standard": "CCSS.ELA-LITERACY.W.4.9", "area-of-interest": "Baseball" },
{"cc-standard": "CCSS.ELA-LITERACY.W.5.8", "area-of-interest": "Hiking" }
]
}
```
''')
st.markdown(header_text)
if "sessionMessages" not in st.session_state:
st.session_state.sessionMessages = [
SystemMessage(content = "You are a bot that generates 'free response questions' for assesing school students based on the input of a Common Core Standard, and area of interest.")
]
#Function to return the response
def generateQuestion(question):
questionPassageJSON=""
ccStandard = question['cc-standard']
#st.session_state.sessionMessages.append(HumanMessage(content="Common Core standard is: {question[0]}, and the area of interest is: {question[1]}"))
## Ask the model to understand the common core standard specified
st.session_state.sessionMessages.append(HumanMessage(content="Read the common core standard :"+ccStandard+" and summarize its key requirements for a student in 3 bullet points. what year grade is the above standard applicable to? Answer in simple one word. E.g. '4th grade',' or 'Kindergarten', or 'Nursery'.\
Also tell if the student needs to read a passage to complete an assessment related to this standard. \
Also tell if the student needs to independently research a topic to complete an assessment related to this standard. \
Also tell if the standard requires testing on a math problem. \
Return the result in JSON format, with keys including 'grade-level', 'standard-requirement', 'is-passage-required', 'is-research-required', 'is-math-problem'."))
assistant_answer = chat(st.session_state.sessionMessages)
st.session_state.sessionMessages.append(AIMessage(content=assistant_answer.content))
passagePrompt="The area of interest to consider for the exercise is "+question['area-of-interest']+". "
# Create a JSON Object out of the Chat response
chatResponseDict = json.loads(assistant_answer.content)
if (not chatResponseDict['is-math-problem']):
allChecksPassed=False
repCount =0;
while not allChecksPassed and repCount<3:
#If a passage is required, generate a 300 word passage, for the appropriate grade level.
if (chatResponseDict['is-passage-required']):
passagePrompt+="Generate a 300 word passage on the given area of interest. It should cover the key points being tested in the common core standard specified. It should draw on real life incidents. Make it about one particular incident that highlights various things about "+question['area-of-interest']+"."
#If external research is required, inform the student what to do research on.
if (chatResponseDict['is-research-required']):
passagePrompt+="Also suggest what specific topic or idea the student can do external research on, to be able to answer questions related to the common core standard specified. Use language as if you are speaking to the student directly, in the formal tone of a teacher or examiner."
passagePrompt+="Make sure any passage or topics generated are appropriate in terms of vocabulary and comprehensibility for grade "+chatResponseDict['grade-level']
passagePrompt+="Return the response in JSON format."
# Ask the model
st.session_state.sessionMessages.append(HumanMessage(content=passagePrompt))
passage_and_research = chat(st.session_state.sessionMessages)
st.session_state.sessionMessages.append(AIMessage(content=passage_and_research.content))
# Based on the above generated passage and research topic, we will now generate 3 FRQs and their grading rubrics
frqPrompt='Generate 3 questions based on the previously discussed common core standard, and the above generated passage. The answers should be available either in the above passage, or the student should be able to find them with easy web research. Good questions have: introduction, context, and open-ended question. Remember, the student is in grade: '+chatResponseDict['grade-level']
frqPrompt+='Generate a rubric for evaluating the student responses for the above questions. Return the result in JSON format. E.g. { "rubric":[{"question":"..text of the question", "rubric":".. text of the rubric"}] etc.'
frqPrompt+='In the final response JSON, also incldue the passage and research JSONs created above.'
# Ask the model
st.session_state.sessionMessages.append(HumanMessage(content=frqPrompt))
question_and_rubric = chat(st.session_state.sessionMessages)
st.session_state.sessionMessages.append(AIMessage(content=question_and_rubric.content))
#questionPassageJSON=json.loads(question_and_rubric.content)
## Do the QC Step
qcPrompt='For the JSON generated in the previous step, please evaluate for each question and rubric:\
- Does the FRQ have an introduction, context, and an open-ended question\
- Does the Rubric prescribe checking for things that can be found in the passage, or suggested research areas.\
\
Pass and Fail answers only.\
Return the response in JSON Form. E.g.:\
{\
"type-of-response":"quality control",\
"qc-for-each-question":[\
{"FRQ":"Pass", "Rubric":"Fail"}\
]\
}'
# Ask the model
st.session_state.sessionMessages.append(HumanMessage(content=qcPrompt))
qcResponseJson = json.loads(chat(st.session_state.sessionMessages).content)
## Write QC results
st.write(qcResponseJson)
## Qc Response doesn't need to into the session state
# Create a Array of qcResponses, and loop through them
qcResponseArray = qcResponseJson['qc-for-each-question']
# If any of the QC checks have failed, we set allChecksPassed to False, and the while loop starts again.
allChecksPassed=True
for row in qcResponseArray:
if (row["FRQ"]=="Fail" or row["Rubric"]=="Fail"):
allChecksPassed=False
## Increase the repCount - we break the While loop after 3 reps, because using GPT4 is expensive, and we don't want it to go into a never ending loop
repCount+=1
return question_and_rubric.content
#Gets the user input
def get_text(textAreaKey):
input_text = st.text_area(label="Paste/Write here",key=textAreaKey)
textAreaKey+=1
return input_text
## Temperature kept at 0.9, so that generated passages and questions are not too similar to each other.
chat = ChatOpenAI(temperature=0.9, model_name="gpt-4")
user_input = get_text(1)
submit = st.button('Generate')
#If generate button is clicked
if submit:
# Create a dict object from the JSON input
inputDict = json.loads(user_input)
questionArray=inputDict['entries']
responseArray=[]
# iterate through the dict, and create a new dict with each response from the LLM
responseDict=[]
for row in questionArray:
st.write(row)
response = generateQuestion(row)
responseArray.append(response)
st.subheader("AI Generated Question & Rubric (Note - in a real world scenario, the rubric won't be shown to the student):")
st.write(responseArray)