Spaces:
Running
Running
| import streamlit as st | |
| import sympy as sp | |
| from solver import solve_equation, laplace_transform_expression,integrate_expression | |
| 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 | |
| if "laplace" in equation.lower(): | |
| solution = laplace_transform_expression(equation) | |
| steps = solution # Since Laplace transform doesn't have steps like solving an equation | |
| elif "integrate" in equation.lower(): | |
| solution = integrate_expression(equation) | |
| steps = solution # Integration steps are handled inside `integrate_expression` | |
| else: | |
| solution = solve_equation(equation) | |
| steps = solution # If neither Laplace nor integration, solve normally | |
| # 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() |