MathSolver / app.py
Taizun's picture
Update app.py
9e39984 verified
raw
history blame
10.5 kB
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()