Coverage for src/ollamapy/parameter_utils.py: 34%

56 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-01 12:29 -0400

1"""Shared utilities for parameter handling and conversion.""" 

2 

3import re 

4from typing import Any, Dict, Union 

5 

6 

7def convert_parameter_value(value: Any, param_type: str) -> Any: 

8 """Convert a parameter value to the expected type. 

9 

10 Args: 

11 value: The value to convert 

12 param_type: The expected type ('number' or 'string') 

13 

14 Returns: 

15 The converted value, or the original value if conversion fails 

16 """ 

17 if param_type == "number" and value is not None: 

18 try: 

19 # Try to convert to number 

20 if isinstance(value, str): 

21 # Remove any whitespace 

22 value = value.strip() 

23 # Handle both int and float 

24 value = float(value) 

25 # Convert to int if it's a whole number 

26 if value.is_integer(): 

27 value = int(value) 

28 except (ValueError, AttributeError): 

29 # Return None to indicate conversion failure 

30 return None 

31 

32 return value 

33 

34 

35def validate_required_parameters( 

36 parameters: Dict[str, Any], expected_params: Dict[str, Dict[str, Any]] 

37) -> bool: 

38 """Validate that all required parameters are present. 

39 

40 Args: 

41 parameters: The actual parameters provided 

42 expected_params: The expected parameter specifications 

43 

44 Returns: 

45 True if all required parameters are present, False otherwise 

46 """ 

47 for param_name, param_spec in expected_params.items(): 

48 if param_spec.get("required", False) and param_name not in parameters: 

49 return False 

50 return True 

51 

52 

53def extract_numbers_from_text(text: str) -> list: 

54 """Extract numbers from text using regex. 

55 

56 Args: 

57 text: The text to extract numbers from 

58 

59 Returns: 

60 List of numbers found in the text 

61 """ 

62 numbers = re.findall(r"-?\d+\.?\d*", text) 

63 result = [] 

64 for num_str in numbers: 

65 try: 

66 value = float(num_str) 

67 result.append(int(value) if value.is_integer() else value) 

68 except ValueError: 

69 continue 

70 return result 

71 

72 

73def extract_expressions_from_text(text: str) -> list: 

74 """Extract mathematical expressions from text. 

75 

76 Args: 

77 text: The text to extract expressions from 

78 

79 Returns: 

80 List of mathematical expressions found 

81 """ 

82 # Simple pattern for basic arithmetic 

83 expressions = re.findall(r"(\d+\s*[+\-*/]\s*\d+)", text) 

84 return [expr.replace(" ", "") for expr in expressions] 

85 

86 

87def prepare_function_parameters( 

88 parameters: Dict[str, Any], expected_params: Dict[str, Dict[str, Any]] 

89) -> Dict[str, Any]: 

90 """Prepare parameters for function call by converting types and validating. 

91 

92 Args: 

93 parameters: The raw parameters 

94 expected_params: The expected parameter specifications 

95 

96 Returns: 

97 Dictionary of prepared parameters ready for function call 

98 """ 

99 call_params = {} 

100 

101 for param_name, param_spec in expected_params.items(): 

102 if param_name in parameters: 

103 value = parameters[param_name] 

104 

105 # Type conversion 

106 converted_value = convert_parameter_value(value, param_spec["type"]) 

107 if converted_value is None and param_spec["type"] == "number": 

108 # Conversion failed for required number 

109 raise ValueError( 

110 f"Parameter '{param_name}' must be a number, got '{value}'" 

111 ) 

112 

113 call_params[param_name] = converted_value 

114 elif param_spec.get("required", False): 

115 raise ValueError(f"Required parameter '{param_name}' not provided") 

116 

117 return call_params 

118 

119 

120def extract_parameter_from_response(response_content: str, param_type: str) -> Any: 

121 """Extract parameter value from AI response content. 

122 

123 Args: 

124 response_content: The cleaned response from AI 

125 param_type: The expected parameter type 

126 

127 Returns: 

128 The extracted parameter value, or None if not found 

129 """ 

130 # Check if not found 

131 if "NOT_FOUND" in response_content.upper() or not response_content: 

132 return None 

133 

134 # Process based on type 

135 if param_type == "number": 

136 # Try to extract a number from the response 

137 # First try to convert the whole response 

138 try: 

139 value = float(response_content) 

140 return int(value) if value.is_integer() else value 

141 except: 

142 # Try to find a number in the response 

143 numbers = extract_numbers_from_text(response_content) 

144 if numbers: 

145 return numbers[0] 

146 return None 

147 else: 

148 # For string type, return the cleaned response 

149 return response_content