prathamt commited on
Commit
9da2f0b
·
verified ·
1 Parent(s): e04c711

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +242 -55
app.py CHANGED
@@ -1,90 +1,277 @@
 
 
 
1
  import gradio as gr
2
 
3
- # ===== Logic =====
4
- def calculate(expr):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  try:
6
- return str(eval(expr))
 
 
7
  except:
8
- return "Error"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- def append(current, val):
11
- return current + val
12
 
13
- def clear():
14
- return ""
 
 
 
 
15
 
16
- # ===== UI =====
17
- with gr.Blocks(css="""
18
- body {background:#000;}
19
- .container {
20
- max-width: 360px;
21
- margin: auto;
22
- padding: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
- /* Display */
26
  .display textarea {
27
- background: black !important;
28
- color: white !important;
29
- font-size: 40px !important;
30
- text-align: right;
31
  border: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
 
34
- /* Buttons */
35
  button {
36
- height: 70px !important;
37
- border-radius: 50% !important;
38
- font-size: 22px !important;
 
 
39
  border: none !important;
 
40
  }
41
 
42
- /* Colors */
43
- .gray button {background:#333 !important; color:white;}
44
- .light button {background:#a5a5a5 !important; color:black;}
45
- .orange button {background:#ff9500 !important; color:white;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- /* Zero button */
48
  .zero button {
49
- border-radius: 35px !important;
50
- text-align: left !important;
51
- padding-left: 25px !important;
52
  }
53
- """) as demo:
54
 
55
- with gr.Column(elem_classes="container"):
 
 
 
 
 
 
 
 
 
 
56
 
57
- display = gr.Textbox(label="", elem_classes="display")
 
 
 
 
 
 
 
 
58
 
59
  # Row 1
60
  with gr.Row():
61
- gr.Button("AC", elem_classes="light").click(clear, None, display)
62
- gr.Button("+/-", elem_classes="light")
63
- gr.Button("%", elem_classes="light")
64
- gr.Button("÷", elem_classes="orange").click(append, [display, gr.State("/")], display)
 
 
 
 
65
 
66
  # Row 2
67
- with gr.Row(elem_classes="gray"):
68
- for i in ["7","8","9"]:
69
- gr.Button(i).click(append, [display, gr.State(i)], display)
70
- gr.Button("×", elem_classes="orange").click(append, [display, gr.State("*")], display)
 
 
71
 
72
  # Row 3
73
- with gr.Row(elem_classes="gray"):
74
- for i in ["4","5","6"]:
75
- gr.Button(i).click(append, [display, gr.State(i)], display)
76
- gr.Button("−", elem_classes="orange").click(append, [display, gr.State("-")], display)
 
 
77
 
78
  # Row 4
79
- with gr.Row(elem_classes="gray"):
80
- for i in ["1","2","3"]:
81
- gr.Button(i).click(append, [display, gr.State(i)], display)
82
- gr.Button("+", elem_classes="orange").click(append, [display, gr.State("+")], display)
 
 
83
 
84
  # Row 5
85
- with gr.Row(elem_classes="gray"):
86
- gr.Button("0", elem_classes="zero").click(append, [display, gr.State("0")], display)
87
- gr.Button(".").click(append, [display, gr.State(".")], display)
88
- gr.Button("=", elem_classes="orange").click(calculate, display, display)
 
 
 
 
 
89
 
90
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
+ import ast
2
+ import operator as op
3
+ import re
4
  import gradio as gr
5
 
6
+ # ----------------------------
7
+ # Safe arithmetic evaluator
8
+ # ----------------------------
9
+ ALLOWED_OPERATORS = {
10
+ ast.Add: op.add,
11
+ ast.Sub: op.sub,
12
+ ast.Mult: op.mul,
13
+ ast.Div: op.truediv,
14
+ ast.Mod: op.mod,
15
+ ast.Pow: op.pow,
16
+ ast.UAdd: op.pos,
17
+ ast.USub: op.neg,
18
+ }
19
+
20
+ def _safe_eval_node(node):
21
+ if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
22
+ return node.value
23
+
24
+ if isinstance(node, ast.BinOp) and type(node.op) in ALLOWED_OPERATORS:
25
+ return ALLOWED_OPERATORS[type(node.op)](
26
+ _safe_eval_node(node.left),
27
+ _safe_eval_node(node.right),
28
+ )
29
+
30
+ if isinstance(node, ast.UnaryOp) and type(node.op) in ALLOWED_OPERATORS:
31
+ return ALLOWED_OPERATORS[type(node.op)](_safe_eval_node(node.operand))
32
+
33
+ raise ValueError("Unsupported expression")
34
+
35
+ def safe_eval(expr: str):
36
+ expr = expr.replace("×", "*").replace("÷", "/").replace("−", "-")
37
+ tree = ast.parse(expr, mode="eval")
38
+ return _safe_eval_node(tree.body)
39
+
40
+ def format_result(value):
41
+ if isinstance(value, float) and value.is_integer():
42
+ return str(int(value))
43
+ return str(value)
44
+
45
+ # ----------------------------
46
+ # Calculator actions
47
+ # ----------------------------
48
+ def append_value(current, value):
49
+ if current in ("0", "Error"):
50
+ current = ""
51
+
52
+ if value in "+-*/":
53
+ if not current and value != "-":
54
+ return "0", "0"
55
+ if current.endswith(("+", "-", "*", "/", ".")):
56
+ current = current[:-1]
57
+
58
+ return current + value, current + value
59
+
60
+ def clear_display():
61
+ return "0", "0"
62
+
63
+ def backspace(current):
64
+ if current in ("0", "Error", ""):
65
+ return "0", "0"
66
+ new_value = current[:-1]
67
+ if not new_value:
68
+ new_value = "0"
69
+ return new_value, new_value
70
+
71
+ def evaluate(current):
72
  try:
73
+ result = safe_eval(current)
74
+ result = format_result(result)
75
+ return result, result
76
  except:
77
+ return "Error", "Error"
78
+
79
+ def toggle_sign(current):
80
+ if current in ("0", "Error", ""):
81
+ return "-", "-"
82
+
83
+ m = re.search(r"(-?\d+(?:\.\d+)?)$", current)
84
+ if not m:
85
+ return current, current
86
+
87
+ start, end = m.span()
88
+ num = m.group(0)
89
+
90
+ if num.startswith("-"):
91
+ num = num[1:]
92
+ else:
93
+ num = "-" + num
94
+
95
+ new_value = current[:start] + num
96
+ return new_value, new_value
97
+
98
+ def percent(current):
99
+ if current in ("0", "Error", ""):
100
+ return "0", "0"
101
+
102
+ if current.endswith((".", "+", "-", "*", "/")):
103
+ return current, current
104
+
105
+ new_value = current + "/100"
106
+ return new_value, new_value
107
+
108
+ def parens(current):
109
+ if current in ("0", "Error"):
110
+ current = ""
111
 
112
+ open_count = current.count("(")
113
+ close_count = current.count(")")
114
 
115
+ if not current or current.endswith(("+", "-", "*", "/", "(")):
116
+ ch = "("
117
+ elif open_count > close_count:
118
+ ch = ")"
119
+ else:
120
+ ch = "("
121
 
122
+ new_value = current + ch
123
+ return new_value, new_value
124
+
125
+ def make_append(v):
126
+ def fn(current):
127
+ return append_value(current, v)
128
+ return fn
129
+
130
+ # ----------------------------
131
+ # UI
132
+ # ----------------------------
133
+ CSS = """
134
+ body, .gradio-container {
135
+ background: #000 !important;
136
+ color: white !important;
137
+ }
138
+
139
+ .phone {
140
+ max-width: 390px;
141
+ margin: 0 auto;
142
+ padding: 16px 14px 20px;
143
  }
144
 
 
145
  .display textarea {
146
+ background: #000 !important;
147
+ color: #fff !important;
 
 
148
  border: none !important;
149
+ box-shadow: none !important;
150
+ text-align: right !important;
151
+ font-size: 72px !important;
152
+ font-weight: 300 !important;
153
+ height: 170px !important;
154
+ padding: 10px 0 0 0 !important;
155
+ resize: none !important;
156
+ }
157
+
158
+ .divider {
159
+ height: 1px;
160
+ background: rgba(255,255,255,0.18);
161
+ margin: 10px 0 18px 0;
162
+ }
163
+
164
+ .topbar {
165
+ display: flex;
166
+ justify-content: space-between;
167
+ align-items: center;
168
+ color: rgba(255,255,255,0.8);
169
+ font-size: 18px;
170
+ margin-bottom: 8px;
171
+ opacity: 0.9;
172
  }
173
 
 
174
  button {
175
+ height: 82px !important;
176
+ min-height: 82px !important;
177
+ border-radius: 999px !important;
178
+ font-size: 30px !important;
179
+ font-weight: 500 !important;
180
  border: none !important;
181
+ box-shadow: none !important;
182
  }
183
 
184
+ .digit button {
185
+ background: #272727 !important;
186
+ color: #fff !important;
187
+ }
188
+
189
+ .utility button {
190
+ background: #a5a5a5 !important;
191
+ color: #000 !important;
192
+ }
193
+
194
+ .operator button {
195
+ background: #bfbfbf !important;
196
+ color: #000 !important;
197
+ }
198
+
199
+ .equals button {
200
+ background: #34c759 !important;
201
+ color: #fff !important;
202
+ }
203
 
 
204
  .zero button {
205
+ border-radius: 999px !important;
 
 
206
  }
207
+ """
208
 
209
+ with gr.Blocks(css=CSS, title="Calculator") as demo:
210
+ with gr.Column(elem_classes="phone"):
211
+ display = gr.Textbox(
212
+ value="0",
213
+ show_label=False,
214
+ interactive=False,
215
+ container=False,
216
+ lines=1,
217
+ elem_classes="display",
218
+ )
219
+ state = gr.State("0")
220
 
221
+ gr.HTML("""
222
+ <div class="topbar">
223
+ <span>◔</span>
224
+ <span>⌕</span>
225
+ <span>√π</span>
226
+ <span style="color:#34c759">⌫</span>
227
+ </div>
228
+ <div class="divider"></div>
229
+ """)
230
 
231
  # Row 1
232
  with gr.Row():
233
+ with gr.Column(scale=1, min_width=0):
234
+ gr.Button("C", elem_classes=["utility"]).click(clear_display, None, [state, display])
235
+ with gr.Column(scale=1, min_width=0):
236
+ gr.Button("()", elem_classes=["utility"]).click(parens, state, [state, display])
237
+ with gr.Column(scale=1, min_width=0):
238
+ gr.Button("%", elem_classes=["utility"]).click(percent, state, [state, display])
239
+ with gr.Column(scale=1, min_width=0):
240
+ gr.Button("÷", elem_classes=["operator"]).click(make_append("/"), state, [state, display])
241
 
242
  # Row 2
243
+ with gr.Row():
244
+ for label in ["7", "8", "9"]:
245
+ with gr.Column(scale=1, min_width=0):
246
+ gr.Button(label, elem_classes=["digit"]).click(make_append(label), state, [state, display])
247
+ with gr.Column(scale=1, min_width=0):
248
+ gr.Button("×", elem_classes=["operator"]).click(make_append("*"), state, [state, display])
249
 
250
  # Row 3
251
+ with gr.Row():
252
+ for label in ["4", "5", "6"]:
253
+ with gr.Column(scale=1, min_width=0):
254
+ gr.Button(label, elem_classes=["digit"]).click(make_append(label), state, [state, display])
255
+ with gr.Column(scale=1, min_width=0):
256
+ gr.Button("−", elem_classes=["operator"]).click(make_append("-"), state, [state, display])
257
 
258
  # Row 4
259
+ with gr.Row():
260
+ for label in ["1", "2", "3"]:
261
+ with gr.Column(scale=1, min_width=0):
262
+ gr.Button(label, elem_classes=["digit"]).click(make_append(label), state, [state, display])
263
+ with gr.Column(scale=1, min_width=0):
264
+ gr.Button("+", elem_classes=["operator"]).click(make_append("+"), state, [state, display])
265
 
266
  # Row 5
267
+ with gr.Row():
268
+ with gr.Column(scale=1, min_width=0):
269
+ gr.Button("+/-", elem_classes=["utility"]).click(toggle_sign, state, [state, display])
270
+ with gr.Column(scale=2, min_width=0):
271
+ gr.Button("0", elem_classes=["digit", "zero"]).click(make_append("0"), state, [state, display])
272
+ with gr.Column(scale=1, min_width=0):
273
+ gr.Button(".", elem_classes=["digit"]).click(make_append("."), state, [state, display])
274
+ with gr.Column(scale=1, min_width=0):
275
+ gr.Button("=", elem_classes=["equals"]).click(evaluate, state, [state, display])
276
 
277
  demo.launch(server_name="0.0.0.0", server_port=7860)