File size: 6,391 Bytes
91fe002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"""

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://www.festavenue.site"):
        self.base_url = base_url
        self.client = httpx.AsyncClient(timeout=10.0)
    
    def get_tools_prompt(self) -> str:
        """

        Return prompt instruction for HuggingFace LLM về available tools

        """
        return """

AVAILABLE TOOLS:

Bạn có thể sử dụng các công cụ sau để lấy thông tin chi tiết:



1. get_event_details(event_code: str)

   - Mô tả: Lấy thông tin đầy đủ về một sự kiện từ hệ thống

   - Khi nào dùng: Khi user hỏi về ngày giờ chính xác, địa điểm cụ thể, thông tin liên hệ, hoặc chi tiết khác về một sự kiện

   - Tham số: event_code (mã sự kiện, ví dụ: "Y-CONCERT", "EVT001")

   - Ví dụ: User hỏi "Ngày tổ chức Y-CONCERT là khi nào?" → Dùng get_event_details("Y-CONCERT")



CÚ PHÁP GỌI TOOL:

Khi bạn cần gọi tool, hãy trả lời CHÍNH XÁC theo format JSON này:

```json

{

  "tool_call": true,

  "function_name": "get_event_details",

  "arguments": {

    "event_code": "Y-CONCERT"

  },

  "reason": "Cần lấy thông tin chính xác về ngày giờ tổ chức"

}

```



QUAN TRỌNG:

- CHỈ trả JSON khi BẮT BUỘC cần gọi tool

- Nếu có thể trả lời từ context sẵn có, đừng gọi tool

- Sau khi nhận kết quả từ tool, hãy trả lời user bằng ngôn ngữ tự nhiên

"""
    
    async def parse_and_execute(self, llm_response: str) -> Optional[Dict[str, Any]]:
        """

        Parse LLM response và execute tool nếu có

        

        Returns:

            None nếu không có tool call

            Dict với tool result nếu có tool call

        """
        # Try to extract JSON from response
        try:
            # Tìm JSON block trong response
            if "```json" in llm_response:
                json_start = llm_response.find("```json") + 7
                json_end = llm_response.find("```", json_start)
                json_str = llm_response[json_start:json_end].strip()
            elif "{" in llm_response and "}" in llm_response:
                # Fallback: tìm JSON object đầu tiên
                json_start = llm_response.find("{")
                json_end = llm_response.rfind("}") + 1
                json_str = llm_response[json_start:json_end]
            else:
                return None
            
            tool_call = json.loads(json_str)
            
            # Validate tool call structure
            if not tool_call.get("tool_call"):
                return None
            
            function_name = tool_call.get("function_name")
            arguments = tool_call.get("arguments", {})
            
            # Execute tool
            if function_name == "get_event_details":
                result = await self._get_event_details(arguments.get("event_code"))
                return {
                    "function": function_name,
                    "arguments": arguments,
                    "result": result
                }
            else:
                return {
                    "function": function_name,
                    "arguments": arguments,
                    "result": {"success": False, "error": f"Unknown function: {function_name}"}
                }
                
        except (json.JSONDecodeError, KeyError, ValueError) as e:
            # Không phải tool call, response bình thường
            return None
    
    async def _get_event_details(self, event_code: str) -> Dict[str, Any]:
        """

        Call getEventByEventCode API

        """
        try:
            response = await self.client.get(
                f"{self.base_url}/event/get-event-by-event-code",
                params={"eventCode": event_code}
            )
            response.raise_for_status()
            data = response.json()
            
            # Extract relevant fields
            event = data.get("data", {})
            
            if not event:
                return {
                    "success": False,
                    "error": "Event not found",
                    "message": f"Không tìm thấy sự kiện với mã {event_code}"
                }
            
            return {
                "success": True,
                "event_code": event.get("eventCode"),
                "event_name": event.get("eventName"),
                "description": event.get("description"),
                "short_description": event.get("shortDescription"),
                "start_time": event.get("startTimeEventTime"),
                "end_time": event.get("endTimeEventTime"),
                "start_sale": event.get("startTicketSaleTime"),
                "end_sale": event.get("endTicketSaleTime"),
                "location": {
                    "address": event.get("location", {}).get("address"),
                    "city": event.get("location", {}).get("city"),
                },
                "contact": {
                    "email": event.get("publicContactEmail"),
                    "phone": event.get("publicContactPhone"),
                    "website": event.get("website")
                },
                "capacity": event.get("capacity"),
                "hashtags": event.get("hashtags", [])
            }
            
        except httpx.HTTPStatusError as e:
            return {
                "success": False,
                "error": f"HTTP {e.response.status_code}",
                "message": f"API trả về lỗi khi truy vấn sự kiện {event_code}"
            }
        except Exception as e:
            return {
                "success": False,
                "error": str(e),
                "message": "Không thể kết nối đến API để lấy thông tin sự kiện"
            }
    
    async def close(self):
        """Close HTTP client"""
        await self.client.aclose()