Spaces:
Running
Running
import streamlit as st | |
import sympy as sp | |
from solver import solve_equation, generate_steps | |
from plotter import plot_function | |
from utils import load_css, initialize_session_state | |
from auth import ( | |
login_user, signup_user, is_logged_in, logout_user, | |
update_profile, get_user_profile, change_password | |
) | |
from models import History, SessionLocal, init_db | |
import base64 | |
from io import BytesIO | |
# Initialize database | |
init_db() | |
def save_to_history(equation: str, solution: str): | |
"""Save equation and solution to user's history.""" | |
if not is_logged_in(): | |
return | |
db = SessionLocal() | |
try: | |
history = History( | |
user_id=st.session_state.user_id, | |
equation=equation, | |
solution=solution | |
) | |
db.add(history) | |
db.commit() | |
finally: | |
db.close() | |
def load_user_history(): | |
"""Load user's solution history.""" | |
if not is_logged_in(): | |
return [] | |
db = SessionLocal() | |
try: | |
return db.query(History).filter( | |
History.user_id == st.session_state.user_id | |
).order_by(History.created_at.desc()).all() | |
finally: | |
db.close() | |
def render_math_symbols(): | |
"""Render mathematical symbols for input.""" | |
st.markdown("### Mathematical Operators") | |
cols = st.columns(8) | |
all_symbols = { | |
# Basic arithmetic | |
'×': '*', | |
'÷': '/', | |
'^': '^', | |
'=': '=', | |
'(': '(', | |
')': ')', | |
# Functions and special operators | |
'√': '√', | |
'∫': '∫', | |
'd/dx': 'd/dx', | |
'!': '!', | |
'ℒ': 'L', | |
'∑': 'sum', | |
'∏': 'prod', | |
'|': '|', | |
# Constants | |
'π': 'pi', | |
'e': 'e', | |
'i': 'i', | |
'∞': 'oo', | |
# Trigonometric | |
'sin': 'sin(', | |
'cos': 'cos(', | |
'tan': 'tan(', | |
'csc': 'csc(', | |
'sec': 'sec(', | |
'cot': 'cot(', | |
# Inverse trigonometric | |
'sin⁻¹': 'sin⁻¹(', | |
'cos⁻¹': 'cos⁻¹(', | |
'tan⁻¹': 'tan⁻¹(', | |
# Other functions | |
'ln': 'ln(', | |
'log': 'log(', | |
'e^': 'e^', | |
'|x|': 'abs(', | |
} | |
for i, (label, symbol) in enumerate(all_symbols.items()): | |
col_idx = i % 8 | |
if cols[col_idx].button(label, key=f"btn_{label}", help=f"Insert {label}"): | |
if 'equation' not in st.session_state: | |
st.session_state.equation = '' | |
st.session_state.equation += symbol | |
def render_profile_settings(): | |
"""Render user profile settings page.""" | |
st.title("Profile Settings") | |
user = get_user_profile(st.session_state.user_id) | |
# Profile photo upload | |
st.subheader("Profile Photo") | |
uploaded_file = st.file_uploader("Choose a profile photo", type=['jpg', 'jpeg', 'png']) | |
if uploaded_file: | |
# Convert to base64 | |
bytes_data = uploaded_file.getvalue() | |
base64_image = base64.b64encode(bytes_data).decode() | |
success, message = update_profile(st.session_state.user_id, profile_photo=base64_image) | |
if success: | |
st.success("Profile photo updated!") | |
else: | |
st.error(message) | |
# Display current photo if exists | |
if user.profile_photo: | |
st.image(base64.b64decode(user.profile_photo), width=150) | |
# Personal Information | |
st.subheader("Personal Information") | |
with st.form("profile_form"): | |
full_name = st.text_input("Full Name", value=user.full_name or "") | |
email = st.text_input("Email", value=user.email or "") | |
school = st.text_input("School", value=user.school or "") | |
grade = st.text_input("Grade/Year", value=user.grade or "") | |
if st.form_submit_button("Update Profile"): | |
success, message = update_profile( | |
st.session_state.user_id, | |
full_name=full_name, | |
email=email, | |
school=school, | |
grade=grade | |
) | |
if success: | |
st.success("Profile updated successfully!") | |
else: | |
st.error(message) | |
# Password Change | |
st.subheader("Change Password") | |
with st.form("password_form"): | |
current_password = st.text_input("Current Password", type="password") | |
new_password = st.text_input("New Password", type="password") | |
confirm_password = st.text_input("Confirm New Password", type="password") | |
if st.form_submit_button("Change Password"): | |
if new_password != confirm_password: | |
st.error("New passwords do not match") | |
else: | |
success, message = change_password( | |
st.session_state.user_id, | |
current_password, | |
new_password | |
) | |
if success: | |
st.success("Password updated successfully!") | |
else: | |
st.error(message) | |
def render_auth_page(): | |
"""Render login/signup page.""" | |
st.title("Mathematical Problem Solver") | |
tab1, tab2 = st.tabs(["Login", "Sign Up"]) | |
with tab1: | |
st.header("Login") | |
login_username = st.text_input("Username", key="login_username") | |
login_password = st.text_input("Password", type="password", key="login_password") | |
if st.button("Login"): | |
if login_user(login_username, login_password): | |
st.success("Successfully logged in!") | |
st.rerun() | |
else: | |
st.error("Invalid username or password") | |
with tab2: | |
st.header("Sign Up") | |
signup_username = st.text_input("Username", key="signup_username") | |
signup_password = st.text_input("Password", type="password", key="signup_password") | |
confirm_password = st.text_input("Confirm Password", type="password") | |
st.info("Password must be at least 8 characters long and contain at least one uppercase letter.") | |
if st.button("Sign Up"): | |
if signup_password != confirm_password: | |
st.error("Passwords do not match") | |
else: | |
success, message = signup_user(signup_username, signup_password) | |
if success: | |
st.success("Account created successfully!") | |
st.rerun() | |
else: | |
st.error(message) | |
def main(): | |
# Initialize session state and load CSS | |
initialize_session_state() | |
load_css() | |
if not is_logged_in(): | |
render_auth_page() | |
return | |
# Main app header with settings and logout buttons | |
col1, col2, col3 = st.columns([6, 1, 1]) | |
with col1: | |
st.title("Mathematical Problem Solver") | |
with col2: | |
if st.button("Settings"): | |
st.session_state.show_settings = True | |
st.rerun() | |
with col3: | |
if st.button("Logout"): | |
logout_user() | |
st.rerun() | |
st.markdown(f"Welcome, {st.session_state.username}!") | |
# Show settings or main app | |
if st.session_state.get('show_settings', False): | |
render_profile_settings() | |
if st.button("Back to Calculator"): | |
st.session_state.show_settings = False | |
st.rerun() | |
else: | |
# Main calculator interface | |
# Sidebar for history | |
with st.sidebar: | |
st.header("Solution History") | |
history = load_user_history() | |
if history: | |
for idx, item in enumerate(history): | |
with st.expander(f"Problem {idx + 1}"): | |
st.write(f"Input: {item.equation}") | |
st.write(f"Solution: {item.solution}") | |
st.write(f"Date: {item.created_at.strftime('%Y-%m-%d %H:%M')}") | |
# Input method selection | |
input_method = st.radio( | |
"Choose input method:", | |
["Type equation/expression", "Use camera", "Example problems"] | |
) | |
if input_method == "Type equation/expression": | |
# Add math symbols | |
render_math_symbols() | |
# Equation input | |
if 'equation' not in st.session_state: | |
st.session_state.equation = '' | |
equation = st.text_input( | |
"Enter your equation or expression:", | |
value=st.session_state.equation, | |
help="""Examples: | |
- Equation: x^2 + 2x + 1 = 0 | |
- Integration: ∫sin x | |
- Derivative: d/dx(x^2) | |
- Factorial: 5! | |
- Laplace: ℒ(t^2)""" | |
) | |
st.session_state.equation = equation | |
elif input_method == "Use camera": | |
st.info("📸 Camera input feature is coming soon! For now, please type your equation or choose from examples.") | |
equation = "" | |
else: | |
equation = st.selectbox( | |
"Select an example:", | |
[ | |
"x^2 + 2x + 1 = 0", | |
"∫sin x", | |
"d/dx(x^3)", | |
"sin^2 x + cos^2 x", | |
"5!", | |
"2x + 3 = 7", | |
"e^x + 1 = 0", | |
"log(x) = 1" | |
] | |
) | |
if st.button("Solve"): | |
if equation: | |
try: | |
# Solve the equation or expression | |
solution = solve_equation(equation) | |
steps = generate_steps(equation) | |
# Display solution | |
st.markdown("### Solution") | |
st.write(solution) | |
# Display steps | |
st.markdown("### Step-by-step Solution") | |
for step in steps: | |
st.write(step) | |
# Plot the function if possible | |
try: | |
st.markdown("### Function Visualization") | |
fig = plot_function(equation) | |
st.plotly_chart(fig) | |
except Exception as plot_error: | |
st.info("Visualization not available for this type of expression.") | |
# Save to history | |
save_to_history(equation, solution) | |
except Exception as e: | |
st.error(f"Error: {str(e)}") | |
else: | |
st.warning("Please enter an equation or expression") | |
if __name__ == "__main__": | |
main() |