fix
Browse files- app.py +154 -65
- requirements.txt +1 -2
app.py
CHANGED
|
@@ -3,22 +3,33 @@ import re
|
|
| 3 |
import streamlit as st
|
| 4 |
from openai import OpenAI
|
| 5 |
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
load_dotenv()
|
| 7 |
|
| 8 |
-
# Initialize
|
| 9 |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 10 |
|
| 11 |
-
def
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
| 22 |
You are a math teacher. Create a comprehensive lecture script for a lesson in "{math_subject}" on the topic "{topic}"
|
| 23 |
that transitions seamlessly from start to finish. Deliver the lecture in a {speaking_style} style,
|
| 24 |
appropriate for a(n) {difficulty} audience, using English only.
|
|
@@ -73,34 +84,15 @@ The script must be fluent with smooth transitions and detailed explanations of t
|
|
| 73 |
8. **Engagement, Reinforcement, and Conclusion:**
|
| 74 |
Summarize the key points and offer additional tips or alternative approaches for deeper understanding.
|
| 75 |
End with a motivational wrap-up, leaving the audience with a final thought or question.
|
| 76 |
-
|
| 77 |
Begin your response now.
|
| 78 |
"""
|
| 79 |
-
response = client.chat.completions.create(
|
| 80 |
-
model="gpt-4o-2024-08-06",
|
| 81 |
-
messages=[{"role": "user", "content": prompt}],
|
| 82 |
-
max_tokens=max_tokens,
|
| 83 |
-
temperature=temperature
|
| 84 |
-
)
|
| 85 |
-
return response.choices[0].message.content.strip()
|
| 86 |
|
| 87 |
-
def
|
| 88 |
-
"""
|
| 89 |
-
Processes the lecture script through another LLM call to add smooth transitions between sections.
|
| 90 |
-
IMPORTANT: Retain all the detailed, numbered step-by-step breakdowns exactly as they are.
|
| 91 |
-
Only add transitional sentences to improve the overall flow of the narrative.
|
| 92 |
-
"""
|
| 93 |
-
transition_prompt = f"""
|
| 94 |
-
You are an expert editor for academic lecture scripts. Below is a lecture script that contains detailed, numbered step-by-step explanations. Rewrite the script to add smooth, natural transitions between the different sections while preserving all the detailed steps and numbered instructions exactly as they are. Do not remove or alter any of the numbered steps or explanations—only insert transitional sentences and connect the sections into one seamless narrative. Please ensure transitions are added to the common pitfalls, alternative methods, and other sections so that it is fit for a lecture script.
|
| 95 |
-
|
| 96 |
-
Lecture Script:
|
| 97 |
-
{text}
|
| 98 |
-
|
| 99 |
-
Rewritten Lecture Script:
|
| 100 |
-
"""
|
| 101 |
response = client.chat.completions.create(
|
| 102 |
model="gpt-4o-2024-08-06",
|
| 103 |
-
messages=[{"role": "user", "content":
|
| 104 |
max_tokens=max_tokens,
|
| 105 |
temperature=temperature
|
| 106 |
)
|
|
@@ -121,9 +113,38 @@ def unify_all_math_as_double_dollars(text: str) -> str:
|
|
| 121 |
text = re.sub(r'__SINGLE__PLACEHOLDER__(.+?)__SINGLE__PLACEHOLDER__', r'$$\1$$', text, flags=re.DOTALL)
|
| 122 |
return text
|
| 123 |
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
st.sidebar.header("Input Settings")
|
| 128 |
math_subject = st.sidebar.text_input("Math Subject", "Algebra 1")
|
| 129 |
topic = st.sidebar.text_input("Topic", "Equation and Relations")
|
|
@@ -131,37 +152,105 @@ difficulty = st.sidebar.selectbox("Difficulty", ["beginner", "intermediate", "ad
|
|
| 131 |
speaking_style = st.sidebar.text_input("Speaking Style", "engaging and detailed")
|
| 132 |
prev_lecture = st.sidebar.text_input("Previous Lecture", "Coordinate Plane")
|
| 133 |
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
"
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
else:
|
| 147 |
-
|
| 148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
if st.button("Generate Lecture Script"):
|
| 150 |
with st.spinner("Generating script..."):
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
lecture_script = build_detailed_lecture_script(
|
| 154 |
-
math_subject=math_subject,
|
| 155 |
-
topic=topic,
|
| 156 |
-
difficulty=difficulty,
|
| 157 |
-
speaking_style=speaking_style,
|
| 158 |
-
example1=example1,
|
| 159 |
-
problem1=problem1,
|
| 160 |
-
wordproblem=wordproblem,
|
| 161 |
-
prev_lecture=prev_lecture
|
| 162 |
-
)
|
| 163 |
-
formatted_script = unify_all_math_as_double_dollars(lecture_script)
|
| 164 |
-
final_script = add_transitions_and_smooth_script(formatted_script)
|
| 165 |
|
| 166 |
st.success("Lecture script generated!")
|
| 167 |
-
st.text_area("Final Lecture Script",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import streamlit as st
|
| 4 |
from openai import OpenAI
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
+
|
| 7 |
+
# For OCR
|
| 8 |
+
import pytesseract
|
| 9 |
+
from PIL import Image
|
| 10 |
+
|
| 11 |
+
# Set page to wide layout so you can see everything
|
| 12 |
+
st.set_page_config(layout="wide")
|
| 13 |
+
|
| 14 |
load_dotenv()
|
| 15 |
|
| 16 |
+
# Initialize OpenAI client
|
| 17 |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 18 |
|
| 19 |
+
def default_prompt_builder(
|
| 20 |
+
math_subject: str,
|
| 21 |
+
topic: str,
|
| 22 |
+
difficulty: str,
|
| 23 |
+
speaking_style: str,
|
| 24 |
+
example1: str,
|
| 25 |
+
problem1: str,
|
| 26 |
+
wordproblem: str,
|
| 27 |
+
prev_lecture: str
|
| 28 |
+
) -> str:
|
| 29 |
+
"""
|
| 30 |
+
Builds the default prompt based on the user inputs.
|
| 31 |
+
"""
|
| 32 |
+
return f"""
|
| 33 |
You are a math teacher. Create a comprehensive lecture script for a lesson in "{math_subject}" on the topic "{topic}"
|
| 34 |
that transitions seamlessly from start to finish. Deliver the lecture in a {speaking_style} style,
|
| 35 |
appropriate for a(n) {difficulty} audience, using English only.
|
|
|
|
| 84 |
8. **Engagement, Reinforcement, and Conclusion:**
|
| 85 |
Summarize the key points and offer additional tips or alternative approaches for deeper understanding.
|
| 86 |
End with a motivational wrap-up, leaving the audience with a final thought or question.
|
| 87 |
+
|
| 88 |
Begin your response now.
|
| 89 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
|
| 91 |
+
def call_openai_chat(prompt: str, max_tokens: int = 2000, temperature: float = 0.4) -> str:
|
| 92 |
+
"""Generic function to call OpenAI chat completions."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
response = client.chat.completions.create(
|
| 94 |
model="gpt-4o-2024-08-06",
|
| 95 |
+
messages=[{"role": "user", "content": prompt}],
|
| 96 |
max_tokens=max_tokens,
|
| 97 |
temperature=temperature
|
| 98 |
)
|
|
|
|
| 113 |
text = re.sub(r'__SINGLE__PLACEHOLDER__(.+?)__SINGLE__PLACEHOLDER__', r'$$\1$$', text, flags=re.DOTALL)
|
| 114 |
return text
|
| 115 |
|
| 116 |
+
def ask_agent_for_improvement(script_text: str, user_request: str, max_tokens: int = 1500, temperature: float = 0.5) -> str:
|
| 117 |
+
"""
|
| 118 |
+
Sends the existing lecture script plus the user's request
|
| 119 |
+
to GPT, allowing the user to ask for improvements, expansions,
|
| 120 |
+
or fluidity checks.
|
| 121 |
+
"""
|
| 122 |
+
prompt = f"""
|
| 123 |
+
You have the following lecture script:
|
| 124 |
+
|
| 125 |
+
{script_text}
|
| 126 |
|
| 127 |
+
A user requests the following improvement or check:
|
| 128 |
+
"{user_request}"
|
| 129 |
+
|
| 130 |
+
Please provide a helpful rewrite that addresses the user's request while preserving all essential details.
|
| 131 |
+
"""
|
| 132 |
+
response = client.chat.completions.create(
|
| 133 |
+
model="gpt-4o-2024-08-06",
|
| 134 |
+
messages=[
|
| 135 |
+
{"role": "system", "content": "You are an expert academic editor specialized in lecture scripts."},
|
| 136 |
+
{"role": "user", "content": prompt}
|
| 137 |
+
],
|
| 138 |
+
max_tokens=max_tokens,
|
| 139 |
+
temperature=temperature
|
| 140 |
+
)
|
| 141 |
+
return response.choices[0].message.content.strip()
|
| 142 |
+
|
| 143 |
+
# ------------------ Streamlit UI ------------------
|
| 144 |
+
|
| 145 |
+
st.title("Lecture Script Generator with OCR and Manual Prompt Editing")
|
| 146 |
+
|
| 147 |
+
# Sidebar: Input settings
|
| 148 |
st.sidebar.header("Input Settings")
|
| 149 |
math_subject = st.sidebar.text_input("Math Subject", "Algebra 1")
|
| 150 |
topic = st.sidebar.text_input("Topic", "Equation and Relations")
|
|
|
|
| 152 |
speaking_style = st.sidebar.text_input("Speaking Style", "engaging and detailed")
|
| 153 |
prev_lecture = st.sidebar.text_input("Previous Lecture", "Coordinate Plane")
|
| 154 |
|
| 155 |
+
# --- OCR + Text for Example Problem ---
|
| 156 |
+
st.sidebar.header("Example Problem")
|
| 157 |
+
uploaded_example_image = st.sidebar.file_uploader("Upload Example Problem Image (optional)", type=["png", "jpg", "jpeg"])
|
| 158 |
+
example_text_input = st.sidebar.text_area(
|
| 159 |
+
"Or type Example Problem text",
|
| 160 |
+
"Given the graph with the points A(2,7), B(-1,5), C(-2,-3), and D(5,-8), determine the domain and range of the graph"
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
if uploaded_example_image is not None:
|
| 164 |
+
image = Image.open(uploaded_example_image)
|
| 165 |
+
extracted_text = pytesseract.image_to_string(image)
|
| 166 |
+
st.sidebar.write("**Extracted text from Example Problem image:**", extracted_text)
|
| 167 |
+
example1 = extracted_text.strip() if extracted_text.strip() else example_text_input
|
| 168 |
+
else:
|
| 169 |
+
example1 = example_text_input
|
| 170 |
+
|
| 171 |
+
# --- OCR + Text for Problem 1 ---
|
| 172 |
+
st.sidebar.header("Problem 1")
|
| 173 |
+
uploaded_problem1_image = st.sidebar.file_uploader("Upload Problem 1 Image (optional)", type=["png", "jpg", "jpeg"])
|
| 174 |
+
problem1_text_input = st.sidebar.text_area(
|
| 175 |
+
"Or type Problem 1 text",
|
| 176 |
+
"Solve the equation when the domain is {-2, -1, 0, 4, 7} for 6x - 3y = 21"
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
if uploaded_problem1_image is not None:
|
| 180 |
+
image = Image.open(uploaded_problem1_image)
|
| 181 |
+
extracted_text = pytesseract.image_to_string(image)
|
| 182 |
+
st.sidebar.write("**Extracted text from Problem 1 image:**", extracted_text)
|
| 183 |
+
problem1 = extracted_text.strip() if extracted_text.strip() else problem1_text_input
|
| 184 |
+
else:
|
| 185 |
+
problem1 = problem1_text_input
|
| 186 |
+
|
| 187 |
+
# --- OCR + Text for Word Problem ---
|
| 188 |
+
st.sidebar.header("Word Problem")
|
| 189 |
+
uploaded_wordproblem_image = st.sidebar.file_uploader("Upload Word Problem Image (optional)", type=["png", "jpg", "jpeg"])
|
| 190 |
+
wordproblem_text_input = st.sidebar.text_area(
|
| 191 |
+
"Or type Word Problem text",
|
| 192 |
+
"On a Friday night, a group of friends decided to go to the movies..."
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
if uploaded_wordproblem_image is not None:
|
| 196 |
+
image = Image.open(uploaded_wordproblem_image)
|
| 197 |
+
extracted_text = pytesseract.image_to_string(image)
|
| 198 |
+
st.sidebar.write("**Extracted text from Word Problem image:**", extracted_text)
|
| 199 |
+
wordproblem = extracted_text.strip() if extracted_text.strip() else wordproblem_text_input
|
| 200 |
+
else:
|
| 201 |
+
wordproblem = wordproblem_text_input
|
| 202 |
+
|
| 203 |
+
# --- Prompt Customization ---
|
| 204 |
+
st.sidebar.header("Prompt Customization")
|
| 205 |
+
edit_prompt_manually = st.sidebar.checkbox("Edit Prompt Manually?")
|
| 206 |
+
|
| 207 |
+
if edit_prompt_manually:
|
| 208 |
+
# Build the default prompt for the user to see and edit
|
| 209 |
+
default_prompt = default_prompt_builder(
|
| 210 |
+
math_subject, topic, difficulty, speaking_style,
|
| 211 |
+
example1, problem1, wordproblem, prev_lecture
|
| 212 |
+
)
|
| 213 |
+
user_custom_prompt = st.sidebar.text_area(
|
| 214 |
+
"Custom Prompt (edit as you like)",
|
| 215 |
+
value=default_prompt,
|
| 216 |
+
height=600
|
| 217 |
+
)
|
| 218 |
else:
|
| 219 |
+
user_custom_prompt = None
|
| 220 |
|
| 221 |
+
# 1) Build the final prompt right away
|
| 222 |
+
if edit_prompt_manually and user_custom_prompt:
|
| 223 |
+
final_prompt = user_custom_prompt
|
| 224 |
+
else:
|
| 225 |
+
final_prompt = default_prompt_builder(
|
| 226 |
+
math_subject, topic, difficulty, speaking_style,
|
| 227 |
+
example1, problem1, wordproblem, prev_lecture
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
# 2) Display the final prompt in the main area
|
| 231 |
+
st.subheader("Current Prompt Preview")
|
| 232 |
+
st.text_area("Prompt Being Used - You may change this if necessary", final_prompt, height=300)
|
| 233 |
+
|
| 234 |
+
# 3) Generate the script
|
| 235 |
if st.button("Generate Lecture Script"):
|
| 236 |
with st.spinner("Generating script..."):
|
| 237 |
+
lecture_script = call_openai_chat(final_prompt, max_tokens=3000, temperature=0.4)
|
| 238 |
+
lecture_script = unify_all_math_as_double_dollars(lecture_script)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
|
| 240 |
st.success("Lecture script generated!")
|
| 241 |
+
st.text_area("Final Lecture Script", lecture_script, height=600)
|
| 242 |
+
st.session_state["final_script"] = lecture_script # store for agent use
|
| 243 |
+
|
| 244 |
+
# --- Agent Interaction Section ---
|
| 245 |
+
st.subheader("Request Further Improvements or Checks")
|
| 246 |
+
user_improvement_request = st.text_input(
|
| 247 |
+
"Request (e.g., 'Add better transitions', 'Improve step-by-step explanation', etc.)"
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
if st.button("Ask the Agent"):
|
| 251 |
+
if "final_script" in st.session_state and st.session_state["final_script"]:
|
| 252 |
+
with st.spinner("Asking agent..."):
|
| 253 |
+
agent_response = ask_agent_for_improvement(st.session_state["final_script"], user_improvement_request)
|
| 254 |
+
st.text_area("Agent's Response", agent_response, height=400)
|
| 255 |
+
else:
|
| 256 |
+
st.warning("Please generate the lecture script first.")
|
requirements.txt
CHANGED
|
@@ -2,5 +2,4 @@ streamlit
|
|
| 2 |
openai
|
| 3 |
python-dotenv
|
| 4 |
pytesseract
|
| 5 |
-
|
| 6 |
-
PIL
|
|
|
|
| 2 |
openai
|
| 3 |
python-dotenv
|
| 4 |
pytesseract
|
| 5 |
+
Pillow
|
|
|