"""Offline/simple tools: exact calculator and weather.""" import ast import operator import requests _OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv, ast.FloorDiv: operator.floordiv, ast.Mod: operator.mod, ast.Pow: operator.pow, ast.USub: operator.neg, ast.UAdd: operator.pos} def _eval(node): if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)): return node.value if isinstance(node, ast.BinOp) and type(node.op) in _OPS: if isinstance(node.op, ast.Pow) and abs(_eval(node.right)) > 1000: raise ValueError("exponent too large") return _OPS[type(node.op)](_eval(node.left), _eval(node.right)) if isinstance(node, ast.UnaryOp) and type(node.op) in _OPS: return _OPS[type(node.op)](_eval(node.operand)) raise ValueError("unsupported expression") def calculator(expression: str) -> str: """Evaluate an arithmetic expression exactly. Supports + - * / // % ** and parentheses. Args: expression: The arithmetic expression, for example '(1500 * 18) / 100'. """ try: expr = expression.replace("×", "*").replace("÷", "/").replace("^", "**").replace(",", "") r = _eval(ast.parse(expr, mode="eval").body) return str(round(r, 10) if isinstance(r, float) else r) except Exception as e: return f"Could not calculate: {e}" def weather(place: str) -> str: """Get the current weather and a 3-day forecast for a town or city. Args: place: Town or city name, for example 'Aluva' or 'Kochi'. """ try: g = requests.get("https://geocoding-api.open-meteo.com/v1/search", timeout=10, params={"name": place, "count": 1}).json().get("results") if not g: return f"Place not found: {place}" g = g[0] w = requests.get("https://api.open-meteo.com/v1/forecast", timeout=10, params={ "latitude": g["latitude"], "longitude": g["longitude"], "timezone": "auto", "forecast_days": 3, "current": "temperature_2m,relative_humidity_2m,precipitation,wind_speed_10m", "daily": "temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max"}).json() c, d = w["current"], w["daily"] lines = [f"{g['name']}, {g.get('admin1', '')}, {g.get('country', '')}", f"Now: {c['temperature_2m']}°C, humidity {c['relative_humidity_2m']}%, " f"rain {c['precipitation']} mm, wind {c['wind_speed_10m']} km/h"] for i, day in enumerate(d["time"]): lines.append(f"{day}: {d['temperature_2m_min'][i]}–{d['temperature_2m_max'][i]}°C, " f"rain {d['precipitation_sum'][i]} mm ({d['precipitation_probability_max'][i]}%)") return "\n".join(lines) except Exception as e: return f"Weather lookup failed: {e}"