ChatbotRAG / tools_service.py
minhvtt's picture
Update tools_service.py
6597779 verified
raw
history blame
6.82 kB
"""
Tools Service for LLM Function Calling
HuggingFace-compatible với prompt engineering
"""
import httpx
from typing import List, Dict, Any, Optional
import json
import asyncio
class ToolsService:
"""
Manages external API tools that LLM can call via prompt engineering
"""
def __init__(self, base_url: str = "https://hoalacrent.io.vn/api/v0"):
self.base_url = base_url
self.client = httpx.AsyncClient(timeout=10.0)
def get_tools_definition(self) -> List[Dict]:
"""
Return list of tool definitions (OpenAI format style)
Used for constructing system prompt
"""
return [
{
"name": "search_events",
"description": "Tìm kiếm sự kiện phù hợp theo từ khóa, vibe, hoặc thời gian.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Từ khóa tìm kiếm (VD: 'nhạc rock', 'hài kịch')"},
"vibe": {"type": "string", "description": "Vibe/Mood (VD: 'chill', 'sôi động', 'hẹn hò')"},
"time": {"type": "string", "description": "Thời gian (VD: 'cuối tuần này', 'tối nay')"}
}
}
},
{
"name": "get_event_details",
"description": "Lấy thông tin chi tiết (giá, địa điểm, thời gian) của sự kiện.",
"parameters": {
"type": "object",
"properties": {
"event_id": {"type": "string", "description": "ID của sự kiện (MongoDB ID)"}
},
"required": ["event_id"]
}
},
{
"name": "get_purchased_events",
"description": "Kiểm tra lịch sử các sự kiện user đã mua vé hoặc tham gia.",
"parameters": {
"type": "object",
"properties": {
"user_id": {"type": "string", "description": "ID của user"}
},
"required": ["user_id"]
}
},
{
"name": "save_feedback",
"description": "Lưu đánh giá/feedback của user về sự kiện.",
"parameters": {
"type": "object",
"properties": {
"event_id": {"type": "string", "description": "ID sự kiện"},
"rating": {"type": "integer", "description": "Số sao đánh giá (1-5)"},
"comment": {"type": "string", "description": "Nội dung nhận xét"}
},
"required": ["event_id", "rating"]
}
},
{
"name": "save_lead",
"description": "Lưu thông tin khách hàng quan tâm (Lead).",
"parameters": {
"type": "object",
"properties": {
"email": {"type": "string"},
"phone": {"type": "string"},
"interest": {"type": "string"}
}
}
}
]
async def execute_tool(self, tool_name: str, arguments: Dict) -> Any:
"""
Execute a tool by name with arguments
"""
print(f"🔧 Executing Tool: {tool_name} with args: {arguments}")
try:
if tool_name == "get_event_details":
return await self._get_event_details(arguments.get("event_id") or arguments.get("event_code"))
elif tool_name == "get_purchased_events":
return await self._get_purchased_events(arguments.get("user_id"))
elif tool_name == "save_feedback":
return await self._save_feedback(
arguments.get("event_id"),
arguments.get("rating"),
arguments.get("comment")
)
elif tool_name == "search_events":
# Note: This usually requires RAG service, so we return a special signal
# The Agent Service will handle RAG search
return {"action": "run_rag_search", "query": arguments}
elif tool_name == "save_lead":
# Placeholder for lead saving
return {"success": True, "message": "Lead saved successfully"}
else:
return {"error": f"Unknown tool: {tool_name}"}
except Exception as e:
print(f"⚠️ Tool Execution Error: {e}")
return {"error": str(e)}
async def _get_event_details(self, event_id: str) -> Dict:
"""Call API to get event details"""
if not event_id:
return {"error": "Missing event_id"}
try:
url = f"{self.base_url}/event/get-event-by-id"
response = await self.client.get(url, params={"id": event_id})
if response.status_code == 200:
data = response.json()
if data.get("success"):
return data.get("data")
return {"error": "Event not found", "details": response.text}
except Exception as e:
return {"error": str(e)}
async def _get_purchased_events(self, user_id: str) -> List[Dict]:
"""Call API to get purchased events for user"""
if not user_id:
return []
try:
url = f"{self.base_url}/event/get-purchase-event-by-user-id/{user_id}"
print(f"🔍 Calling API: {url}")
response = await self.client.get(url)
if response.status_code == 200:
data = response.json()
# API returns {data: [...]}
return data.get("data", [])
print(f"⚠️ API Error: {response.status_code} - {response.text}")
return []
except Exception as e:
print(f"⚠️ API Exception: {e}")
return []
async def _save_feedback(self, event_id: str, rating: int, comment: str) -> Dict:
"""Save feedback (Mock or Real API)"""
# TODO: Implement real API call when available
print(f"📝 Saving Feedback: Event={event_id}, Rating={rating}, Comment={comment}")
return {"success": True, "message": "Feedback recorded"}
async def close(self):
"""Close HTTP client"""
await self.client.aclose()