Spaces:
Sleeping
Sleeping
| """ | |
| tool_routing.py | |
| ~~~~~~~~~~~~~~~ | |
| Modular tool implementation and routing engine. | |
| Provides safe execution of calculation, datetime query, web search, | |
| and context QA lookup tools. | |
| Usage | |
| ----- | |
| from models.tool_routing import ToolRouter | |
| router = ToolRouter() | |
| reply, executed = router.route_and_execute("What is the current time?") | |
| if executed: | |
| print("Tool Output:", reply) | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import ast | |
| import operator | |
| from datetime import datetime | |
| import re | |
| from typing import Dict, Any, Tuple | |
| from models.logger_config import logger | |
| # ββ Safe Calculator Evaluation ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Supported AST operators to avoid unsafe eval() execution | |
| _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, | |
| } | |
| def _safe_eval(node) -> float: | |
| """Recursively evaluate AST nodes safely.""" | |
| if isinstance(node, ast.Num): # python < 3.8 compatibility | |
| return node.n | |
| elif isinstance(node, ast.Constant): # python 3.8+ compatibility | |
| if isinstance(node.value, (int, float)): | |
| return node.value | |
| raise TypeError("Unsupported constant type") | |
| elif isinstance(node, ast.BinOp): | |
| op_type = type(node.op) | |
| if op_type in _SAFE_OPERATORS: | |
| return _SAFE_OPERATORS[op_type](_safe_eval(node.left), _safe_eval(node.right)) | |
| raise ValueError(f"Unsupported operator: {op_type}") | |
| elif isinstance(node, ast.UnaryOp): | |
| op_type = type(node.op) | |
| if op_type in _SAFE_OPERATORS: | |
| return _SAFE_OPERATORS[op_type](_safe_eval(node.operand)) | |
| raise ValueError(f"Unsupported operator: {op_type}") | |
| raise ValueError(f"Unsupported syntax: {type(node)}") | |
| def safe_calculate(expression: str) -> str: | |
| """Parse and calculate math expressions safely using AST representation.""" | |
| clean_expr = re.sub(r"[^\d+\-*/().\s]", "", expression) | |
| if not clean_expr.strip(): | |
| return "Error: Empty expression or invalid characters." | |
| try: | |
| node = ast.parse(clean_expr, mode="eval").body | |
| res = _safe_eval(node) | |
| return str(res) | |
| except Exception as e: | |
| return f"Error evaluating expression '{expression}': {e}" | |
| # ββ Tool Registry βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class ToolRouter: | |
| """ | |
| Modular execution router for AI assistant tools. | |
| Integrates calculator, datetime, web search, and retrieval QA capabilities. | |
| """ | |
| def __init__(self) -> None: | |
| pass | |
| def tool_calculator(self, expression: str) -> str: | |
| """Safe math calculation tool.""" | |
| logger.info(f"[TOOL] Executing Calculator: {expression}") | |
| return f"[Calculator Result] {safe_calculate(expression)}" | |
| def tool_datetime(self) -> str: | |
| """Returns the current date and time.""" | |
| logger.info("[TOOL] Executing Datetime") | |
| now = datetime.now() | |
| return f"[Datetime Result] Current date and time is {now.strftime('%Y-%m-%d %H:%M:%S')}." | |
| def tool_web_retrieval(self, query: str) -> str: | |
| """Mocked web retrieval interface returning contextual details.""" | |
| logger.info(f"[TOOL] Executing Web Retrieval: {query}") | |
| query_lower = query.lower() | |
| # Simple simulated search summaries | |
| if "weather" in query_lower: | |
| return "[Web Result] Weather forecast is currently sunny, 22Β°C with light wind." | |
| elif "groq" in query_lower: | |
| return "[Web Result] Groq is an AI infrastructure company that builds LPU (Language Processing Unit) chips for high-speed inference." | |
| elif "qwen" in query_lower: | |
| return "[Web Result] Qwen is a series of open-source large language models developed by Alibaba Group, optimized for chat and reasoning." | |
| return f"[Web Result] Web search matches for '{query}': No highly relevant resources found." | |
| def tool_retrieval_qa(self, query: str, context: str) -> str: | |
| """Extract matching sentence or answer from a local text context.""" | |
| logger.info(f"[TOOL] Executing Retrieval QA on query: {query}") | |
| sentences = re.split(r"(?<=[.!?])\s+", context) | |
| matches = [] | |
| for word in query.lower().split(): | |
| if len(word) > 3: # focus on key terms | |
| for sentence in sentences: | |
| if word in sentence.lower() and sentence not in matches: | |
| matches.append(sentence) | |
| if matches: | |
| return f"[QA Result] Found matching context: " + " ".join(matches[:2]) | |
| return "[QA Result] No direct matches found in current text context." | |
| def route_and_execute(self, user_input: str, qa_context: str = "") -> Tuple[str, bool]: | |
| """ | |
| Scan input text for specific tool triggers and execute matched tool. | |
| Returns: | |
| -------- | |
| (output_text, executed) | |
| """ | |
| input_lower = user_input.lower() | |
| # 1. Calculator Trigger | |
| calc_match = re.search(r"\b(?:calculate|math|calc)\s+([\d+\-*/().\s]+)", input_lower) | |
| if calc_match: | |
| expr = calc_match.group(1).strip() | |
| return self.tool_calculator(expr), True | |
| # 2. Datetime Trigger | |
| if any(term in input_lower for term in ["current time", "what time is it", "today's date", "what is the date"]): | |
| return self.tool_datetime(), True | |
| # 3. Web Retrieval Trigger | |
| search_match = re.search(r"\b(?:search\s+for|web\s+search|lookup|find\s+info\s+on)\s+(.+)", input_lower) | |
| if search_match: | |
| q = search_match.group(1).strip() | |
| return self.tool_web_retrieval(q), True | |
| # 4. Retrieval QA Trigger (if context is present and question is asked) | |
| if qa_context and any(term in input_lower for term in ["who", "what", "where", "explain", "find"]): | |
| return self.tool_retrieval_qa(user_input, qa_context), True | |
| return "", False | |