import gradio as gr from fastapi import FastAPI, HTTPException from pydantic import BaseModel, field_validator from frontend import create_interface import math import re import os app = FastAPI() ALLOWED_FUNCTIONS = {'sin', 'cos', 'tan', 'log', 'ln', 'sqrt', 'abs', 'pow'} ALLOWED_CONSTANTS = {'pi', 'e'} class Expression(BaseModel): expr: str @field_validator('expr') @classmethod def validate_expression(cls, v: str) -> str: if not v: raise ValueError("Expression cannot be empty") # Check for invalid characters valid_chars = set('0123456789.+-*/()^ \t\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') invalid_chars = set(v) - valid_chars if invalid_chars: raise ValueError(f"Invalid characters found: {', '.join(invalid_chars)}") # Check for invalid function names or constants tokens = re.findall(r'\b[a-zA-Z_]\w*\b', v) invalid_tokens = [token for token in tokens if token not in ALLOWED_FUNCTIONS and token not in ALLOWED_CONSTANTS] if invalid_tokens: raise ValueError(f"Invalid function or constant names: {', '.join(invalid_tokens)}") return v @app.post("/calculate") async def calculate_api(expression: Expression): try: result = evaluate_expression(expression.expr) return {"result": result} except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}") def evaluate_expression(expr: str) -> float: safe_dict = { 'sin': math.sin, 'cos': math.cos, 'tan': math.tan, 'log': math.log10, 'ln': math.log, 'sqrt': math.sqrt, 'pi': math.pi, 'e': math.e, 'abs': abs, 'pow': pow } try: # Replace '^' with '**' for exponentiation expr = expr.replace('^', '**') return eval(expr, {"__builtins__": None}, safe_dict) except ZeroDivisionError: raise ValueError("Division by zero is not allowed") except ValueError as e: raise ValueError(f"Math domain error: {str(e)}") except Exception as e: raise ValueError(f"Invalid expression: {str(e)}") # Create the Gradio interface iface = create_interface() # Mount the Gradio app app = gr.mount_gradio_app(app, iface, path="/") if __name__ == "__main__": import uvicorn port = int(os.environ.get("PORT", 7860)) uvicorn.run(app, host="0.0.0.0", port=port)