Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| def add_numbers(data): | |
| """Python function that adds two numbers""" | |
| try: | |
| num1 = float(data.get("num1", 0)) | |
| num2 = float(data.get("num2", 0)) | |
| result = num1 + num2 | |
| return {"result": result, "expression": f"{num1} + {num2} = {result}"} | |
| except (ValueError, TypeError) as e: | |
| return {"result": "Error", "expression": f"Invalid input: {e}"} | |
| # HTML for the math calculator | |
| MATH_HTML = """ | |
| <div id="math-app"> | |
| <h1>Math Calculator</h1> | |
| <p class="subtitle">Custom HTML calling Python via Gradio</p> | |
| <div class="calculator"> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label>First Number</label> | |
| <input type="number" id="num1" placeholder="Enter number..." value="0"> | |
| </div> | |
| <div class="operator">+</div> | |
| <div class="input-group"> | |
| <label>Second Number</label> | |
| <input type="number" id="num2" placeholder="Enter number..." value="0"> | |
| </div> | |
| </div> | |
| <button id="calculate-btn">Calculate (calls Python)</button> | |
| <div class="result-box" id="result-box"> | |
| <div class="result-label">Result from Python:</div> | |
| <div class="result-value" id="result-value">${value.result !== undefined ? value.result : '—'}</div> | |
| <div class="result-expression" id="result-expression">${value.expression || ''}</div> | |
| </div> | |
| <div class="status" id="status">Ready</div> | |
| </div> | |
| </div> | |
| """ | |
| # CSS for the math calculator | |
| MATH_CSS = """ | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| html, body { | |
| height: 100%; | |
| width: 100%; | |
| overflow: hidden; | |
| font-family: system-ui, -apple-system, sans-serif; | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); | |
| } | |
| #math-app { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); | |
| color: #fff; | |
| padding: 2rem; | |
| } | |
| h1 { | |
| font-size: 2.5rem; | |
| text-align: center; | |
| background: linear-gradient(90deg, #00d2ff, #3a7bd5); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 0.5rem; | |
| } | |
| .subtitle { | |
| color: #aaa; | |
| font-size: 1.1rem; | |
| margin-bottom: 2rem; | |
| } | |
| .calculator { | |
| background: rgba(255,255,255,0.05); | |
| padding: 2rem; | |
| border-radius: 1rem; | |
| border: 1px solid rgba(255,255,255,0.1); | |
| width: 100%; | |
| max-width: 500px; | |
| } | |
| .input-row { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 1rem; | |
| margin-bottom: 1.5rem; | |
| } | |
| .input-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| .input-group label { | |
| font-size: 0.9rem; | |
| color: #aaa; | |
| } | |
| .input-group input { | |
| width: 120px; | |
| padding: 1rem; | |
| border: 1px solid rgba(255,255,255,0.2); | |
| border-radius: 0.5rem; | |
| background: rgba(255,255,255,0.05); | |
| color: white; | |
| font-size: 1.5rem; | |
| text-align: center; | |
| } | |
| .input-group input:focus { | |
| outline: none; | |
| border-color: #00d2ff; | |
| } | |
| .operator { | |
| font-size: 2rem; | |
| color: #00d2ff; | |
| margin-top: 1.5rem; | |
| } | |
| #calculate-btn { | |
| width: 100%; | |
| padding: 1rem; | |
| border: none; | |
| border-radius: 0.5rem; | |
| background: linear-gradient(135deg, #00d2ff, #3a7bd5); | |
| color: white; | |
| font-size: 1.1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| margin-bottom: 1.5rem; | |
| } | |
| #calculate-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 15px rgba(0, 210, 255, 0.3); | |
| } | |
| #calculate-btn:active { | |
| transform: translateY(0); | |
| } | |
| .result-box { | |
| background: rgba(0, 210, 255, 0.1); | |
| border: 1px solid rgba(0, 210, 255, 0.3); | |
| border-radius: 0.5rem; | |
| padding: 1.5rem; | |
| text-align: center; | |
| margin-bottom: 1rem; | |
| } | |
| .result-label { | |
| font-size: 0.9rem; | |
| color: #aaa; | |
| margin-bottom: 0.5rem; | |
| } | |
| .result-value { | |
| font-size: 3rem; | |
| font-weight: bold; | |
| color: #00d2ff; | |
| } | |
| .result-expression { | |
| font-size: 1rem; | |
| color: #aaa; | |
| margin-top: 0.5rem; | |
| } | |
| .status { | |
| text-align: center; | |
| padding: 0.5rem; | |
| color: #666; | |
| font-size: 0.9rem; | |
| } | |
| /* Hide Gradio chrome */ | |
| footer { display: none !important; } | |
| .gradio-container, [class*="gradio-container"] { | |
| max-width: 100% !important; | |
| width: 100% !important; | |
| padding: 0 !important; | |
| margin: 0 !important; | |
| min-height: 0 !important; | |
| height: 100% !important; | |
| } | |
| main.fillable, main[class*="fillable"], .app { | |
| padding: 0 !important; | |
| margin: 0 !important; | |
| min-height: 0 !important; | |
| } | |
| .block, .block.padded { | |
| padding: 0 !important; | |
| border: none !important; | |
| background: transparent !important; | |
| } | |
| html, body, #root, .gradio-container, .contain, gradio-app { | |
| height: 100% !important; | |
| margin: 0 !important; | |
| padding: 0 !important; | |
| overflow: hidden !important; | |
| min-height: 0 !important; | |
| } | |
| [class*="svelte"] { | |
| padding: 0 !important; | |
| margin: 0 !important; | |
| } | |
| /* Prevent iframe resizer infinite loop */ | |
| .contain, .main, gradio-app { | |
| min-height: 0 !important; | |
| max-height: 100% !important; | |
| } | |
| </style> | |
| """ | |
| # JavaScript that wires up the UI and calls Python via trigger | |
| MATH_JS = """ | |
| (function() { | |
| function $(sel) { return element.querySelector(sel); } | |
| function updateStatus(msg) { | |
| $('#status').textContent = msg; | |
| } | |
| // When calculate button is clicked | |
| $('#calculate-btn').addEventListener('click', function() { | |
| var num1 = parseFloat($('#num1').value) || 0; | |
| var num2 = parseFloat($('#num2').value) || 0; | |
| updateStatus('Calling Python...'); | |
| // Update props.value with the data to send to Python | |
| props.value = { num1: num1, num2: num2 }; | |
| // Trigger the 'submit' event which calls the Python function | |
| trigger('submit'); | |
| }); | |
| // Allow Enter key to trigger calculation | |
| $('#num1').addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') $('#calculate-btn').click(); | |
| }); | |
| $('#num2').addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') $('#calculate-btn').click(); | |
| }); | |
| updateStatus('Ready - Enter numbers and click Calculate'); | |
| })(); | |
| """ | |
| # JavaScript to handle the response from Python | |
| MATH_JS_CHANGE = """ | |
| (function() { | |
| function $(sel) { return element.querySelector(sel); } | |
| // This runs when the component value changes (i.e., when Python returns) | |
| if (props.value && props.value.result !== undefined) { | |
| $('#result-value').textContent = props.value.result; | |
| $('#result-expression').textContent = props.value.expression || ''; | |
| $('#status').textContent = 'Calculated by Python at ' + new Date().toLocaleTimeString(); | |
| } | |
| })(); | |
| """ | |
| # Create the Gradio app | |
| with gr.Blocks(fill_height=True, title="Math Calculator") as demo: | |
| calculator = gr.HTML( | |
| value={}, | |
| html_template=MATH_CSS + MATH_HTML, | |
| js_on_load=MATH_JS, | |
| container=False | |
| ) | |
| # When JS triggers 'submit', call add_numbers and update the component | |
| calculator.submit(add_numbers, inputs=calculator, outputs=calculator) | |
| if __name__ == "__main__": | |
| demo.launch() | |