File size: 12,004 Bytes
6f8d9d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
from langchain_community.utilities.sql_database import SQLDatabase
from langchain_experimental.sql import SQLDatabaseChain
import os, sys
import os
from dotenv import load_dotenv

# Load biến môi trường từ file .env
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))  # hoặc ".." tùy vị trí
dotenv_path = os.path.join(BASE_DIR, ".env")
import os
from dotenv import load_dotenv

# # Gán đường dẫn tuyệt đối đến file .env
# dotenv_path = r"d:\HmDrinks_Chat\V2\chatbot -  19_5\.env"

from dotenv import load_dotenv, find_dotenv

# Tự động tìm file .env gần nhất trong cây thư mục cha
load_dotenv(find_dotenv(), override=True)

# Debug kiểm tra
# print(">> DEBUG: dotenv_path =", dotenv_path)
# print(">> DEBUG: DB_HOST =", os.getenv("DB_HOST"))
# print(">> DEBUG: DB_USER =", os.getenv("DB_USER"))
# print(">> DEBUG: DB_PASSWORD =", os.getenv("DB_PASSWORD"))
# print(">> DEBUG: DB_NAME =", os.getenv("DB_NAME"))
# print(">> DEBUG: DB_PORT =", os.getenv("DB_PORT"))




DB_HOST = os.getenv("DB_HOST")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_NAME =  os.getenv("DB_NAME")
DB_PORT =  os.getenv("DB_PORT")
import os
from urllib.parse import quote

password = os.getenv("DB_PASSWORD")
DB_PASSWORD = quote(password)
# Tạo connection string
connection_uri = (
    f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
    "?ssl_verify_cert=false&ssl_verify_identity=false"
)
print(">> DEBUG connection_uri:", connection_uri)
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(current_dir, '..', '..'))  # Lên 2 cấp
sys.path.append(project_root)



from support import get_key

api_key = get_key.get_random_api_key()
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

os.environ["GOOGLE_API_KEY"] = "AIzaSyCO-RlqYewC4e9BEPoC8m-AxHUY7J3_o2E"
import prompt.prompt_main as prompt
from langchain_google_genai import GoogleGenerativeAIEmbeddings, ChatGoogleGenerativeAI
llm1 = ChatGoogleGenerativeAI(model='gemini-2.0-flash-thinking-exp-01-21',temperature=0.6,api_key=api_key)



db = SQLDatabase.from_uri(connection_uri)
db.get_table_info_no_throw()
import re
db_chain = SQLDatabaseChain.from_llm(llm=llm1,db=db,prompt= prompt.PROMPT)
import prompt.prompt_table as prompt_table
import prompt.prompt_create_table as prompt_create
import json

# import google.generativeai as genai
# genai.configure(api_key=api_key)

# async def response_general(input:str)->list:
#  api_key = get_key.get_random_api_key()
#  genai.configure(api_key=api_key)
#  generation_config = {
#   "temperature": 1,
#   "top_p": 0.95,
#   "top_k": 40,
#   "max_output_tokens": 8192,
#   "response_mime_type": "text/plain",
# }
 
 
#  model = genai.GenerativeModel(
#   model_name="gemini-2.5-flash-preview-04-17",
#   generation_config=generation_config,
# )

#  chat_session = model.start_chat(
#   history=[  
#     {
#       "role": "user",
#       "parts": [
#         f"""Hãy vui lòng đọc kỹ các bảng sau đây gồm có các thuộc tÍNH, khóa ngoại của các bảng sau khi tạo bảng trong MySQL. {prompt_create.PROMPT_TABLE}.
#         Mình có định nghĩa các thuộc tính tham số, mối quan hệ các bảng sau đây: {prompt_table}. Luôn đọc kĩ càng các thông tin mô tả này. Hãy xác định kĩ càng các bước, mô tả của mình để lấy các bảng cần dùng chính xác nhất.
#         Hãy cân nhắc cho câu hỏi sau đây: {input}. Phân tích câu hỏi và chọn các bảng cần thiết để có thể trả lời câu hỏi.
#         Hãy phân biệt rõ giữa đơn hàng bình thường(orders) và đơn hàng nhóm(group_orders).
#         ** Cách trả lời:  
#         - Bạn vui lòng trả lại danh sách các table liên quan. Vui lòng ghép chúng vào trong list và nối với nhau bằng , ví dụ ["cart","user"].
#         - Luôn bao gồm bảng user trong mọi trường hợp câu hỏi.
#         - Chỉ lấy tên các bảng mà mình đã cung cấp, không được tự ý sinh thêm bảng. Điều này là cấm.
#         - Không được phép dùng bảng "Token, user_chat, notification"
#         - Nếu trong list có bảng cart thì phải kèm theo cart_item
#         - Nếu trong list có bảng cart_group thì phải kèm theo cart_item_group
#         - Nếu trong bảng có chứa các bảng như cart_item, cart_item_group thì vui lòng kèm theo các bảng liên quan về sản phẩm như product_translation và product_variants, product
#         - Nếu trong list có bảng category thì phải kèm theo category_translation, product phải kèm theo product_translation và product_variant
#         - Nếu trong list có bảng group_orders thì phải kèm theo group_order_members.
#         - Nếu trong list có bảng group_order_members thì phải kèm theo cart_group.
#         - Nếu trong list trả về có các bảng như product, post, hay category phải kèm theo bảng translation liên kết với nó.
#         - Khi trong list có liên quan product hãy luôn cung cấp product_variants để có thể cung cấp thêm giá tùy trương hợp.
#         - Không yêu cầu giải thích gì thêm chỉ cần trả về list theo mình mô tả ví dụ.
#         - Luôn đảm bảo Xác định chính xác bảng cần dùng cho câu hỏi, không dư thừa bảng, không bỏ sót bảng cần thiết.
#         - Luôn luôn trả về đúng list []. Cấm trả sai định dạng mà mình đã cung cấp""",
#       ],
#     }
#   ]
# )

#  response = chat_session.send_message("Hãy luôn đảm bảo rằng bạn tuân thủ những gì mình đưa ra, không được phép làm khác đi.")
#  data = response.text
#  if data.strip():  # Kiểm tra dữ liệu không rỗng
#     try:
#         # Cố gắng parse JSON
#         data_list = json.loads(data)
#         return data_list
#     except json.JSONDecodeError:
#         # Nếu không phải JSON, thử tìm danh sách bảng trong chuỗi văn bản
#         match = re.search(r'\[(.*?)\]', data)
#         if match:
#             # Lấy phần trong dấu [ ], tách thành list
#             items_str = match.group(1)
#             items = [item.strip().strip('"').strip("'") for item in items_str.split(',')]
#             print("Danh sách bảng đã trích xuất:", items)
#             return items
#         else:
#             print("Không tìm thấy danh sách bảng trong dữ liệu văn bản!")
#  else:
#     print("Dữ liệu đầu vào rỗng!")
    

import asyncio
import json
import re
from support import get_key
import google.generativeai as genai

async def response_general(input: str) -> list:
    async def call_model_once() -> list:
        # Lấy API key và cấu hình
        api_key = get_key.get_random_api_key()
        genai.configure(api_key=api_key)

        generation_config = {
            "temperature": 1,
            "top_p": 0.95,
            "top_k": 40,
            "max_output_tokens": 8192,
            "response_mime_type": "text/plain",
        }

        model = genai.GenerativeModel(
            model_name="gemini-2.5-flash-preview-04-17",
            generation_config=generation_config,
        )

        chat_session = model.start_chat(
            history=[
                {
                    "role": "user",
                    "parts": [
                        f"""Hãy vui lòng đọc kỹ các bảng sau đây gồm có các thuộc tÍNH, khóa ngoại của các bảng sau khi tạo bảng trong MySQL. {prompt_create.PROMPT_TABLE}.
                        Mình có định nghĩa các thuộc tính tham số, mối quan hệ các bảng sau đây: {prompt_table}. Luôn đọc kĩ càng các thông tin mô tả này. Hãy xác định kĩ càng các bước, mô tả của mình để lấy các bảng cần dùng chính xác nhất.
                        Hãy cân nhắc cho câu hỏi sau đây: {input}. Phân tích câu hỏi và chọn các bảng cần thiết để có thể trả lời câu hỏi.
                        Hãy phân biệt rõ giữa đơn hàng bình thường(orders) và đơn hàng nhóm(group_orders).
                        ** Cách trả lời:  
                        - Bạn vui lòng trả lại danh sách các table liên quan. Vui lòng ghép chúng vào trong list và nối với nhau bằng , ví dụ ["cart","user"].
                        - Luôn bao gồm bảng user trong mọi trường hợp câu hỏi.
                        - Chỉ lấy tên các bảng mà mình đã cung cấp, không được tự ý sinh thêm bảng. Điều này là cấm.
                        - Không được phép dùng bảng "Token, user_chat, notification"
                        - Nếu trong list có bảng cart thì phải kèm theo cart_item
                        - Nếu trong list có bảng cart_group thì phải kèm theo cart_item_group
                        - Nếu trong bảng có chứa các bảng như cart_item, cart_item_group thì vui lòng kèm theo các bảng liên quan về sản phẩm như product_translation và product_variants, product
                        - Nếu trong list có bảng category thì phải kèm theo category_translation, product phải kèm theo product_translation và product_variant
                        - Nếu trong list có bảng group_orders thì phải kèm theo group_order_members.
                        - Nếu trong list có bảng group_order_members thì phải kèm theo cart_group.
                        - Nếu trong list trả về có các bảng như product, post, hay category phải kèm theo bảng translation liên kết với nó.
                        - Khi trong list có liên quan product hãy luôn cung cấp product_variants để có thể cung cấp thêm giá tùy trương hợp.
                        - Không yêu cầu giải thích gì thêm chỉ cần trả về list theo mình mô tả ví dụ.
                        - Luôn đảm bảo Xác định chính xác bảng cần dùng cho câu hỏi, không dư thừa bảng, không bỏ sót bảng cần thiết.
                        - Luôn luôn trả về đúng list []. Cấm trả sai định dạng mà mình đã cung cấp""",
                    ],
                }
            ]
        )

        response = await chat_session.send_message_async("Hãy luôn đảm bảo rằng bạn tuân thủ những gì mình đưa ra, không được phép làm khác đi.")
        data = response.text

        if data.strip():
            try:
                return json.loads(data)
            except json.JSONDecodeError:
                match = re.search(r'\[(.*?)\]', data)
                if match:
                    items_str = match.group(1)
                    items = [item.strip().strip('"').strip("'") for item in items_str.split(',')]
                    print("✅ Danh sách bảng đã trích xuất:", items)
                    return items
                else:
                    raise ValueError("Không tìm thấy danh sách bảng hợp lệ trong phản hồi văn bản.")
        else:
            raise ValueError("Dữ liệu phản hồi trống.")

    # Gọi lần đầu
    try:
        return await call_model_once()
    except Exception as e:
        print(f"⚠️ Lỗi lần đầu: {e} — thử lại sau 2 giây...")
        await asyncio.sleep(2)

        try:
            return await call_model_once()
        except Exception as retry_error:
            print(f"❌ Lỗi lần 2: {retry_error}")
            raise Exception("Gọi mô hình thất bại sau khi thử lại.")

    
# if __name__ == "__main__":
#  import asyncio
#  asyncio.run(response_general("Danh sách bài đăng mới nhất"))