Spaces:
Sleeping
Sleeping
| import re | |
| import ast | |
| import operator | |
| from typing import List, Dict | |
| from groq import Groq | |
| from agents.base_agent import BaseAgent | |
| import config | |
| from utils.logger import get_logger | |
| logger = get_logger(__name__) | |
| _SAFE_OPERATORS = { | |
| ast.Add: operator.add, | |
| ast.Sub: operator.sub, | |
| ast.Mult: operator.mul, | |
| ast.Div: operator.truediv, | |
| ast.Pow: operator.pow, | |
| ast.USub: operator.neg, | |
| ast.Mod: operator.mod, | |
| ast.FloorDiv: operator.floordiv, | |
| } | |
| _PURE_MATH_RE = re.compile( | |
| r"^\s*[\d\s\.\+\-\*\/\(\)\^%]+\s*$" | |
| ) | |
| def _safe_eval(expr: str) -> float | None: | |
| expr = expr.replace("^", "**") | |
| def _eval_node(node): | |
| if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)): | |
| return node.value | |
| elif isinstance(node, ast.BinOp): | |
| op_func = _SAFE_OPERATORS.get(type(node.op)) | |
| if op_func is None: | |
| raise ValueError(f"Unsupported operator: {type(node.op)}") | |
| return op_func(_eval_node(node.left), _eval_node(node.right)) | |
| elif isinstance(node, ast.UnaryOp): | |
| op_func = _SAFE_OPERATORS.get(type(node.op)) | |
| if op_func is None: | |
| raise ValueError(f"Unsupported unary operator: {type(node.op)}") | |
| return op_func(_eval_node(node.operand)) | |
| else: | |
| raise ValueError(f"Unsupported AST node: {type(node)}") | |
| try: | |
| tree = ast.parse(expr.strip(), mode="eval") | |
| result = _eval_node(tree.body) | |
| return result | |
| except Exception: | |
| return None | |
| def _extract_expression(query: str) -> str | None: | |
| cleaned = re.sub( | |
| r"(?i)^(what\s+is|calculate|compute|evaluate|solve|find)\s*:?\s*", "", query.strip() | |
| ) | |
| cleaned = re.sub(r"[?!]+$", "", cleaned).strip() | |
| if _PURE_MATH_RE.match(cleaned): | |
| return cleaned | |
| match = re.search(r"[\d]+\s*[\+\-\*\/\^%]\s*[\d\.\s\+\-\*\/\^\(\)%]+", query) | |
| if match: | |
| return match.group(0).strip() | |
| return None | |
| class MathAgent(BaseAgent): | |
| SYSTEM_PROMPT = """You are a precise mathematical reasoning assistant. | |
| Solve the given problem step by step using chain-of-thought reasoning. | |
| Always: | |
| 1. Identify the mathematical concept involved | |
| 2. Show your working step by step | |
| 3. State your final answer clearly on a new line starting with "Answer:" | |
| Be concise but thorough. Always include a space after bolding (e.g., **Calculation:** result) for correct UI rendering.""" | |
| def __init__(self): | |
| super().__init__(name="Math Agent") | |
| self._client = Groq(api_key=config.GROQ_API_KEY) | |
| logger.info("MathAgent ready.") | |
| def run( | |
| self, | |
| query: str, | |
| context: str = "", | |
| history: List[Dict[str, str]] = None, | |
| session_id: str = "", | |
| ) -> str: | |
| logger.info(f"MathAgent processing: '{query[:80]}'") | |
| expr = _extract_expression(query) | |
| if expr is not None: | |
| result = _safe_eval(expr) | |
| if result is not None: | |
| formatted = int(result) if result == int(result) else round(result, 6) | |
| answer = ( | |
| f"**Calculation:** `{expr.strip()} = {formatted}`\n\n" | |
| f"**Answer: {formatted}**\n\n" | |
| f"*(Computed via Python arithmetic β 100% accurate)*" | |
| ) | |
| logger.info(f" β Computed via Python eval: {formatted}") | |
| return answer | |
| logger.info(" β Falling back to LLM chain-of-thought reasoning.") | |
| messages = [{"role": "system", "content": self.SYSTEM_PROMPT}] | |
| if history: | |
| messages.extend(history[-4:]) | |
| messages.append({"role": "user", "content": query}) | |
| try: | |
| response = self._client.chat.completions.create( | |
| model=config.GROQ_MODEL_NAME, | |
| messages=messages, | |
| temperature=0.1, | |
| max_tokens=config.GROQ_MAX_TOKENS, | |
| ) | |
| answer = response.choices[0].message.content.strip() | |
| logger.info(" β LLM math response received.") | |
| return answer | |
| except Exception as exc: | |
| logger.error(f"MathAgent LLM call failed: {exc}") | |
| return ( | |
| f"I encountered an error processing your math query. " | |
| f"Please try rephrasing it.\n\nError: {exc}" | |
| ) | |