File size: 8,345 Bytes
325b400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
import os
import os,sys
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
sys.path.insert(0, BASE_DIR)
import function.gemini_response.filter_query_internal as filter_query


#Test OpenAI
os.environ["OPENAI_API_KEY"] = "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"
llm = ChatOpenAI(model="gpt-4.1")

#Test google
os.environ["GOOGLE_API_KEY"] = "AIzaSyB_7ahCuAOZU0UKcON_A00ya5breHTEgQM"
from langchain_google_genai import GoogleGenerativeAIEmbeddings, ChatGoogleGenerativeAI
llm1 = ChatGoogleGenerativeAI(model='gemini-2.5-flash-preview-05-20',temperature=0.6)

from langchain_core.messages import HumanMessage, ToolMessage


@tool
def question_information(query: str) -> str:
    """

    Trả lời các câu hỏi về thông tin liên hệ của cửa hàng, thông tin về sinh viên, tên đề tài các nội dung liên quan mà không phải sql



    Hàm này chỉ phục vụ mục đích cung cấp thông tin liên lạc của cửa hàng, bao gồm:

      - Số điện thoại liên hệ.

      - Địa chỉ cửa hàng.

      - Giờ làm việc.

      - Email hỗ trợ.

      - Các kênh liên hệ khác như Facebook, Zalo, v.v.



    ⚠️ Lưu ý: 

    - Hàm này KHÔNG trả lời các câu hỏi khác như: gợi ý món ăn, tư vấn sản phẩm, giá cả, chương trình khuyến mãi, cách pha chế đồ uống, v.v.

    - Nếu truy vấn không liên quan đến thông tin cửa hàng, hàm sẽ từ chối trả lời.



    Args:

        query (str): Câu hỏi của người dùng liên quan đến thông tin liên hệ của cửa hàng. bao gồm:

      - Số điện thoại liên hệ.

      - Địa chỉ cửa hàng.

      - Giờ làm việc.

      - Email hỗ trợ.

      - Các kênh liên hệ khác như Facebook, Zalo, v.v.



    Returns:

        str: Thông tin liên hệ của cửa hàng hoặc thông báo từ chối nếu câu hỏi không phù hợp. Xác định rõ câu hỏi không viết gọn

    """
    return query
    

@tool(description="Vui lòng giữ đúng truy vấn người dùng không tạo ra câu truy vấn khác ý nghĩa câu hỏi người dùng định hỏi, (**yêu cầu phải bám sát không được tự sinh câu hỏi)")
def question_sql(query: str)->str:
    """

    Hỗ trợ truy xuất schema của database để giúp tạo truy vấn SQL cho các bảng sau:

    

    - **Giỏ hàng (cart, cart_item)**

    - **Danh mục sản phẩm(tên sản phẩm) (category, category_translation)**

    - **Liên hệ và yêu thích (contact, favourite, favourite_item)**

    - **Thông báo (notification)**

    - **Đơn hàng (orders, order_item, shipment)**

    - **Thanh toán (otp, payments)**

    - **Bài viết & tin tức (post, post_translation)**

    - **Lịch sử giá (price_history)**

    - **Sản phẩm (product, product_translation, product_variants)**

    - **Đánh giá sản phẩm (review)**

    - **Người dùng (user, user_coin, token)**

    - **Mã giảm giá & phiếu giảm giá (voucher, user_voucher)**

    - **Xác nhận về mua/xem, xóa  giỏ hàng, đơn hàng**(Hãy lưu ý những câu hỏi về này)

    

    ⚠ **Lưu ý**: 

    - Chỉ hỗ trợ truy vấn liên quan đến các bảng trong database.

    - Không trả lời các câu hỏi về thông tin cửa hàng như số điện thoại, email, giờ làm việc.

    

    Args:

        query (str): Câu hỏi liên quan đến việc truy vấn dữ liệu từ database.

    

    Returns:

        str: Mô tả bảng tương ứng hoặc thông báo từ chối nếu câu hỏi không phù hợp.

    """
    return query


@tool
def question_general(query: str) -> str:
    """

    Xử lý các câu hỏi không liên quan đến các công cụ có sẵn.



    Hàm này nhận vào một câu hỏi dưới dạng chuỗi và trả về câu hỏi đó 

    mà không thực hiện bất kỳ xử lý nào khác. Nó có thể được sử dụng như 

    một phương án dự phòng khi không có tool nào phù hợp để xử lý câu hỏi.



    Args:

        query (str): Câu hỏi đầu vào từ người dùng.



    Returns:

        str: Trả về chính câu hỏi mà không thay đổi.

    """
    return query




@tool(description="""ác định xem truy vấn có phải là câu chào hỏi hay không.  

    Câu chào hỏi bao gồm các từ hoặc cụm từ thể hiện sự chào đón, bắt đầu cuộc trò chuyện, chẳng hạn như:

    - "Xin chào", "Chào bạn", "Hello", "Hi", "Hey", "Good morning", "Good evening", ...  

    - Cụm từ mang ý nghĩa xã giao: "Rất vui được gặp bạn", "Hôm nay bạn thế nào?", "Chúc một ngày tốt lành", ...  



    Lưu ý:

    - Chỉ xử lý các câu hỏi thuộc nhóm chào hỏi.

    - Không liên quan đến **question_sql** hoặc các câu hỏi về dữ liệu.



    Args:

        query (str): Câu hỏi đầu vào của người dùng.



    Returns:

        str: Trả về câu hỏi nếu nó thuộc nhóm chào hỏi, ngược lại có thể xử lý theo yêu cầu cụ thể.""")
def question_hello(query: str)->str:
    """

    Xác định xem truy vấn có phải là câu chào hỏi hay không.  

    Câu chào hỏi bao gồm các từ hoặc cụm từ thể hiện sự chào đón, bắt đầu cuộc trò chuyện, chẳng hạn như:

    - "Xin chào", "Chào bạn", "Hello", "Hi", "Hey", "Good morning", "Good evening", ...  

    - Cụm từ mang ý nghĩa xã giao: "Rất vui được gặp bạn", "Hôm nay bạn thế nào?", "Chúc một ngày tốt lành", ...  



    Lưu ý:

    - Chỉ xử lý các câu hỏi thuộc nhóm chào hỏi.

    - Không liên quan đến **question_sql** hoặc các câu hỏi về dữ liệu.



    Args:

        query (str): Câu hỏi đầu vào của người dùng.



    Returns:

        str: Trả về câu hỏi nếu nó thuộc nhóm chào hỏi, ngược lại có thể xử lý theo yêu cầu cụ thể.

    """
    return query


import asyncio
import importlib
import function.chat as chat_module
async def update_tool_calls(tool_calls, chat_id,user_id,user_input):

    updated_calls = []
    
    for tool in tool_calls:
        query = tool['args']['query']
        list_history = await chat_module.get_chat_details_text(chat_id, user_id)
        new_question = await filter_query.response_rename_question(user_input, list_history, query)
        tool['args']['query'] = new_question
        new_name = await filter_query.response_general(new_question, list_history)
        if new_name is not None and new_name == "question_sql":
         tool['name'] = new_name.strip()
         updated_calls.append(tool)
        if new_name == "question_general":
            tool['name'] = new_name.strip()
            updated_calls.append(tool)
            return updated_calls
        else:
            return tool_calls
    
    return updated_calls


async def process_user_query(user_input, user_id, role, language,chat_id):
    always_call_tool_llm = llm.bind_tools([question_information, question_sql, question_hello], tool_choice=True,strict=True)
    tool_calls = always_call_tool_llm.invoke(f"{user_input}").tool_calls
    
    for tc in tool_calls:
        tc["user_id"] = user_id
        tc["role"] = role
        tc["language"] = language
    print("Tool gốc:",tool_calls)
    data = await update_tool_calls(tool_calls,chat_id,user_id,user_input)
   
    for item in data:
        item['chat_id'] = chat_id
    print("Tool update: ", data)
    return data


# import asyncio

async def main():
    await process_user_query("Tôi muốn thêm trà chanh size L vào giỏ hàng", 4, "CUSTOMER", "VN", "67d2fc6607b51a01e3beb501")

if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main())
    loop.close()