Spaces:
Sleeping
Sleeping
| import math, time | |
| from typing import List, Tuple | |
| import gradio as gr | |
| import numpy as np | |
| HISTORY: List[Tuple[str, str]] = [] | |
| def safe_eval(expr: str): | |
| """ | |
| Evaluate math expressions safely by exposing only math & numpy. | |
| Supports +,-,*,/,**,%, parentheses, and functions like sin, cos, tan, log, sqrt, pi, e. | |
| """ | |
| if not expr or expr.strip() == "": | |
| return "" | |
| allowed = { | |
| "math": math, "np": np, | |
| # common names directly: | |
| "sin": math.sin, "cos": math.cos, "tan": math.tan, | |
| "asin": math.asin, "acos": math.acos, "atan": math.atan, | |
| "sqrt": math.sqrt, "log": math.log, "log10": math.log10, "exp": math.exp, | |
| "pow": pow, "pi": math.pi, "e": math.e, "abs": abs, "round": round | |
| } | |
| # never expose __builtins__ or globals | |
| return eval(expr, {"__builtins__": {}}, allowed) | |
| def calculate(expr, hist): | |
| try: | |
| result = safe_eval(expr) | |
| stamp = time.strftime("%H:%M:%S") | |
| row = (f"{stamp} {expr}", str(result)) | |
| HISTORY.insert(0, row) | |
| if len(HISTORY) > 25: | |
| HISTORY.pop() | |
| return str(result), HISTORY | |
| except Exception as e: | |
| return f"Error: {e}", HISTORY | |
| def scientific(button, value, hist): | |
| piece = button | |
| # map some labeled buttons to functions/tokens | |
| mapping = { | |
| "π":"pi", "e":"e", "√":"sqrt(", "ln":"log(", "log10":"log10(", "sin":"sin(", "cos":"cos(", "tan":"tan(", | |
| "^":"**" | |
| } | |
| piece = mapping.get(button, button) | |
| new_value = (value or "") + piece | |
| return new_value | |
| def clear_all(): | |
| HISTORY.clear() | |
| return "", [] | |
| def matrix_op(a, b, op): | |
| try: | |
| A = np.array(a) | |
| B = np.array(b) | |
| if op == "A + B": | |
| out = A + B | |
| elif op == "A - B": | |
| out = A - B | |
| elif op == "A × B": | |
| out = A @ B | |
| else: | |
| raise ValueError("Unknown op") | |
| return out.tolist() | |
| except Exception as e: | |
| return f"Error: {e}" | |
| def convert_units(value, kind): | |
| try: | |
| x = float(value) | |
| if kind == "Length (m ↔ ft)": | |
| # round-trip toggle: show both | |
| return f"{x} m = {x*3.28084:.6f} ft | {x} ft = {x/3.28084:.6f} m" | |
| if kind == "Weight (kg ↔ lb)": | |
| return f"{x} kg = {x*2.20462:.6f} lb | {x} lb = {x/2.20462:.6f} kg" | |
| if kind == "Temperature (°C ↔ °F)": | |
| c2f = x*9/5 + 32 | |
| f2c = (x-32)*5/9 | |
| return f"{x} °C = {c2f:.2f} °F | {x} °F = {f2c:.2f} °C" | |
| return "Unsupported kind" | |
| except Exception as e: | |
| return f"Error: {e}" | |
| theme = gr.themes.Soft(primary_hue="violet", neutral_hue="slate") | |
| with gr.Blocks(title="Fancy Calculator", theme=theme, css=""" | |
| .kbd {border:1px solid var(--border-color-primary); padding:2px 6px; border-radius:6px;} | |
| .history td {padding: 4px 8px;} | |
| """) as demo: | |
| gr.Markdown("# 🧮 Fancy Calculator\n**Basic, Scientific, Matrix, and Unit tools — with history**") | |
| with gr.Tab("Basic / Scientific"): | |
| with gr.Row(): | |
| expr = gr.Textbox(label="Expression", placeholder="e.g., (2+3)*5, sin(pi/6), sqrt(2)**2", autofocus=True) | |
| with gr.Row(): | |
| out = gr.Textbox(label="Result", interactive=False) | |
| with gr.Row(): | |
| buttons = ["7","8","9","+","sin","cos","tan","(", | |
| "4","5","6","-","√","ln","log10",")", | |
| "1","2","3","*","^","π","e","/", | |
| "0",".","%","//","**","=","C","Back"] | |
| grid = [] | |
| for b in buttons: | |
| grid.append(gr.Button(b, variant="secondary" if b not in ["=","C"] else "primary")) | |
| hist = gr.Dataframe(headers=["Expression","Result"], datatype=["str","str"], | |
| value=HISTORY, interactive=False, row_count=(0,"dynamic"), | |
| label="History (latest first)", elem_classes=["history"]) | |
| # wiring | |
| for btn in grid: | |
| if btn.value == "=": | |
| btn.click(calculate, [expr, hist], [out, hist]) | |
| elif btn.value == "C": | |
| btn.click(lambda: ("", []), None, [expr, hist]).then(fn=clear_all, outputs=[expr, hist]) | |
| elif btn.value == "Back": | |
| btn.click(lambda s: s[:-1] if s else "", expr, expr) | |
| else: | |
| btn.click(scientific, [btn, expr, hist], expr) | |
| # pressing Enter in the textbox calculates | |
| expr.submit(calculate, [expr, hist], [out, hist]) | |
| gr.Markdown( | |
| "Tips: Use functions like `sin, cos, tan, sqrt, log, log10, exp, pi, e`. " | |
| "Keyboard works too — hit **Enter** to evaluate. " | |
| "Use `**` for power, `//` for integer division." | |
| ) | |
| with gr.Tab("Matrix"): | |
| gr.Markdown("Enter matrices as nested lists, e.g. `[[1,2],[3,4]]`") | |
| A = gr.Textbox(value="[[1,2],[3,4]]", label="Matrix A") | |
| B = gr.Textbox(value="[[5,6],[7,8]]", label="Matrix B") | |
| op = gr.Radio(["A + B","A - B","A × B"], value="A + B", label="Operation") | |
| mat_out = gr.Textbox(label="Output") | |
| run = gr.Button("Compute", variant="primary") | |
| run.click(lambda a,b,o: matrix_op(eval(a), eval(b), o), [A,B,op], mat_out) | |
| with gr.Tab("Unit Converter"): | |
| kind = gr.Dropdown(["Length (m ↔ ft)","Weight (kg ↔ lb)","Temperature (°C ↔ °F)"], | |
| value="Length (m ↔ ft)", label="Conversion") | |
| val = gr.Textbox(value="1", label="Value") | |
| conv_btn = gr.Button("Convert", variant="primary") | |
| conv_out = gr.Textbox(label="Result") | |
| conv_btn.click(convert_units, [val, kind], conv_out) | |
| gr.Markdown( | |
| "Built with ❤️ using [Gradio](https://www.gradio.app/)." | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |