Skip to main content
Glama
ImDPS
by ImDPS
calculator.py11.5 kB
""" Enhanced Calculator Tool for Gemini LLM Integration. Provides advanced mathematical calculation capabilities with improved natural language processing. """ import logging import re from typing import Dict, Any, Optional try: from src.tools import ToolDefinition except ImportError: from tools import ToolDefinition logger = logging.getLogger(__name__) class CalculatorTool: """Enhanced tool for performing mathematical calculations with natural language support.""" def __init__(self): logger.info("Enhanced calculator tool initialized") self._initialize_safe_operations() def _initialize_safe_operations(self): """Initialize safe mathematical operations.""" self.safe_dict = { '__builtins__': {}, 'abs': abs, 'round': round, 'min': min, 'max': max, 'sum': sum, 'len': len, 'int': int, 'float': float, 'str': str, 'bool': bool, 'pow': pow, 'divmod': divmod, } # Additional safe mathematical functions import math safe_math_functions = [ 'sqrt', 'ceil', 'floor', 'trunc', 'exp', 'log', 'log10', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'degrees', 'radians', 'pi', 'e' ] for func_name in safe_math_functions: if hasattr(math, func_name): self.safe_dict[func_name] = getattr(math, func_name) async def calculate(self, expression: str) -> str: """Calculate mathematical expressions safely with enhanced natural language processing. This tool can perform advanced mathematical calculations including: - Basic arithmetic: addition, subtraction, multiplication, division - Complex expressions with parentheses and order of operations - Mathematical functions: abs(), round(), min(), max(), sqrt(), sin(), cos(), etc. - Natural language math: "add 15 and 27", "what is 100 minus 45" - Safe evaluation with comprehensive error handling Args: expression: Mathematical expression to evaluate (e.g., "2 + 3 * 4", "add 15 and 27") Returns: The calculated result or detailed error message """ logger.info(f"calculate called with expression: {expression}") try: if not expression or not expression.strip(): raise ValueError("Expression cannot be empty") expression = expression.strip() # Extract mathematical expression from natural language math_expression = self._extract_math_expression(expression) # Validate the extracted expression if not math_expression: raise ValueError("No mathematical expression found in the query") # Security validation self._validate_expression_security(math_expression) # Evaluate the expression safely result = self._safe_evaluate(math_expression) # Format the result formatted_result = self._format_result(result, math_expression) logger.info(f"Calculation completed successfully: {math_expression} = {result}") return formatted_result except Exception as e: logger.error(f"Error in calculation: {e}") raise RuntimeError(f"Calculation failed: {str(e)}") def _extract_math_expression(self, query: str) -> str: """Extract mathematical expression from natural language query with enhanced parsing.""" import re query_lower = query.lower() # Enhanced mathematical patterns math_patterns = [ # Direct mathematical expressions r'(\d+[\+\-\*\/\s]+\d+)', # Basic arithmetic: 15 + 27 r'(\d+\s*[\+\-\*\/]\s*\d+)', # With spaces: 15 + 27 r'(\d+\s*[\+\-\*\/]\s*\d+\s*[\+\-\*\/]\s*\d+)', # Multiple operations: 15 + 27 * 3 # Mathematical functions r'(abs\([^)]+\))', # Absolute value: abs(-42) r'(round\([^)]+\))', # Round function: round(3.7) r'(min\([^)]+\))', # Min function: min(5, 10, 3) r'(max\([^)]+\))', # Max function: max(20, 15, 30) r'(sqrt\([^)]+\))', # Square root: sqrt(16) r'(sin\([^)]+\))', # Sine: sin(45) r'(cos\([^)]+\))', # Cosine: cos(30) r'(tan\([^)]+\))', # Tangent: tan(60) # Complex expressions with parentheses r'(\([^)]*[\+\-\*\/][^)]*\))', # Parenthesized expressions r'(\d+\s*[\+\-\*\/]\s*\([^)]+\))', # Operations with parentheses r'(\([^)]+\)\s*[\+\-\*\/]\s*\d+)', # Parentheses with operations ] # Try to match mathematical patterns for pattern in math_patterns: match = re.search(pattern, query) if match: return match.group(1) # Handle natural language math with enhanced parsing return self._parse_natural_language_math(query) def _parse_natural_language_math(self, query: str) -> str: """Parse natural language mathematical expressions.""" import re query_lower = query.lower() # Extract all numbers from the query numbers = re.findall(r'-?\d+(?:\.\d+)?', query) if len(numbers) < 2: raise ValueError(f"Need at least 2 numbers for calculation in: '{query}'") # Handle different mathematical operations if any(word in query_lower for word in ['add', 'plus', 'sum', '+']): return f"{numbers[0]} + {numbers[1]}" elif any(word in query_lower for word in ['subtract', 'minus', 'difference', '-']): return f"{numbers[0]} - {numbers[1]}" elif any(word in query_lower for word in ['multiply', 'times', 'product', '*']): return f"{numbers[0]} * {numbers[1]}" elif any(word in query_lower for word in ['divide', 'division', 'quotient', '/']): return f"{numbers[0]} / {numbers[1]}" elif any(word in query_lower for word in ['power', 'exponent', 'raised', '^']): return f"{numbers[0]} ** {numbers[1]}" elif any(word in query_lower for word in ['absolute', 'abs']): return f"abs({numbers[0]})" elif any(word in query_lower for word in ['round']): return f"round({numbers[0]})" elif any(word in query_lower for word in ['minimum', 'min']): return f"min({', '.join(numbers[:3])})" # Use up to 3 numbers elif any(word in query_lower for word in ['maximum', 'max']): return f"max({', '.join(numbers[:3])})" # Use up to 3 numbers elif any(word in query_lower for word in ['square root', 'sqrt']): return f"sqrt({numbers[0]})" # If no specific operation is mentioned, try to extract mathematical operators operators = re.findall(r'[\+\-\*\/\^]', query) if operators and len(numbers) >= 2: return f"{numbers[0]} {operators[0]} {numbers[1]}" # Last resort: try to extract just numbers and operators math_chars = re.findall(r'[\d\+\-\*\/\(\)\.]', query) if len(math_chars) >= 3: # At least 2 numbers and 1 operator return ''.join(math_chars) raise ValueError(f"Could not extract mathematical expression from: '{query}'. Please provide a clear mathematical expression or operation.") def _validate_expression_security(self, expression: str): """Validate expression for security concerns.""" dangerous_keywords = [ 'import', 'exec', 'eval', 'open', 'file', '__', 'globals', 'locals', 'compile', 'input', 'raw_input', 'system', 'subprocess', 'os.', 'sys.' ] expression_lower = expression.lower() for keyword in dangerous_keywords: if keyword in expression_lower: raise ValueError(f"'{keyword}' is not allowed for security reasons") # Check for potentially dangerous function calls dangerous_functions = ['eval', 'exec', 'compile', 'input'] for func in dangerous_functions: if f"{func}(" in expression_lower: raise ValueError(f"Function '{func}' is not allowed for security reasons") def _safe_evaluate(self, expression: str): """Safely evaluate mathematical expression.""" try: # Replace common mathematical symbols expression = expression.replace('^', '**') # Handle power operator # Evaluate with restricted environment result = eval(expression, {"__builtins__": {}}, self.safe_dict) # Validate result type if not isinstance(result, (int, float, complex)): raise ValueError("Result must be a number") return result except ZeroDivisionError: raise ValueError("Division by zero is not allowed") except ValueError as e: raise ValueError(f"Invalid mathematical expression: {str(e)}") except SyntaxError as e: raise ValueError(f"Invalid syntax in mathematical expression: {str(e)}") except Exception as e: raise ValueError(f"Error evaluating expression: {str(e)}") def _format_result(self, result, original_expression: str) -> str: """Format the calculation result.""" if isinstance(result, complex): return f"Result: {result} (complex number)" elif isinstance(result, float): # Format float with appropriate precision if result.is_integer(): return f"Result: {int(result)}" else: return f"Result: {result:.6g}" # Use significant figures else: return f"Result: {result}" # Global instance calculator_tool = CalculatorTool() def register_tool() -> ToolDefinition: """Register the enhanced calculator tool.""" return ToolDefinition( name="calculate", description="Calculate mathematical expressions safely with natural language support. Supports basic arithmetic, complex expressions, mathematical functions (abs, round, min, max, sqrt, sin, cos, etc.), and natural language queries.", handler=calculator_tool.calculate, input_schema={ "type": "object", "properties": { "expression": { "type": "string", "description": "Mathematical expression to evaluate (e.g., '2 + 3 * 4', 'add 15 and 27', 'abs(-5)', 'round(3.7)')" } }, "required": ["expression"] }, examples=[ "What is 15 + 27?", "Calculate 100 - 45", "What is 12 * 8?", "Add 15 and 27", "What is the absolute value of -42?", "Round 3.7 to the nearest integer", "What is the minimum of 5, 10, and 3?", "Calculate the square root of 16" ] )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ImDPS/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server