File size: 11,053 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
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
236
237
238
239
240
# import re
# from collections import defaultdict, deque

# def parse_step_data_blocks(text):
#     blocks = re.findall(r"<step_data>(.*?)</step_data>", text, re.DOTALL)
#     parsed_steps = []

#     for block in blocks:
#         match = re.search(r"Yêu cầu\s+(\d+):", block.strip())
#         if match:
#             step_id = int(match.group(1))
#             parsed_steps.append({
#                 "id": step_id,
#                 "content": block.strip(),
#                 "dependencies": set(),
#             })
#         else:
#             pass
#     return parsed_steps


# # ==== Phân tích phụ thuộc ====
# def extract_dependencies(steps):
#     for step in steps:
#         deps = re.findall(r"Yêu cầu\s+(\d+)", step["content"])
#         step["dependencies"] = {int(d) for d in deps if int(d) != step["id"]}

# # ==== Xây đồ thị phụ thuộc ====
# def build_dependency_graph(steps):
#     graph = defaultdict(list)
#     for step in steps:
#         for dep in step["dependencies"]:
#             graph[dep].append(step["id"])
#     return graph

# # ==== Sắp xếp topo ====
# def topological_sort(steps, graph):
#     indegree = {step["id"]: 0 for step in steps}
#     for step in steps:
#         for dep in step["dependencies"]:
#             indegree[step["id"]] += 1

#     queue = deque([sid for sid, deg in indegree.items() if deg == 0])
#     sorted_order = []

#     while queue:
#         current = queue.popleft()
#         sorted_order.append(current)
#         for neighbor in graph[current]:
#             indegree[neighbor] -= 1
#             if indegree[neighbor] == 0:
#                 queue.append(neighbor)

#     return sorted_order

# async def execute_steps(steps, execution_order, query_func,user_id, role,languages):
#     results = {}
#     step_map = {s["id"]: s for s in steps}
#     for step_id in execution_order:
#         step = step_map[step_id]

#         merged_prompt = ""
#         for dep in step["dependencies"]:
#             merged_prompt += f"[Yêu cầu {dep}]\n{step_map[dep]['content']}\n"
#             merged_prompt += f"[Kết quả {dep}]\n{results[dep]}\n"
#         sql_warning = (
#             "\n\n⚠️ **Lưu ý khi viết SQL**:\n"
#             "- Tránh lỗi như `(1054, \"Unknown column 'oi.pro_id','oi.size' in 'field list'\")`\n"
#             "- Vui lòng **kiểm tra kỹ tên cột** trong bảng thực tế.\n"
#             "\n\n⚠️ **Lưu ý khi viết SQL** :\n"
#     "- Tránh các lỗi như :\n"
#     "  Tuyệt đối cấm dùng các kí hiệu %, %%s để tránh bị báo lỗi"
#     "  (1054, \"Unknown column 'oi.pro_id' in 'field list'\")\n . Luôn đảm bảo bạn không bao giờ bị lỗi này"
#     "  (1054, \"Unknown column 'oi.note' in 'field list'\") . Luôn đảm bảo bạn không bao giờ bị lỗi này\n"
#     "  (1054, \"Unknown column 'oi.size' in 'field list'\") . Luôn đảm bảo bạn không bao giờ bị lỗi này \n"
#     "  (1054, \"Unknown column 'c.is_deleted' in 'on clause'\").  Luôn đảm bảo bạn không bao giờ bị lỗi này\n"
#     "- 🔍 Quan trọng(Luôn luôn ghi nhớ): Bảng `order_item` **không có** cột `pro_id`, chỉ gồm các cột: `order_item_id`, `order_id`, `quantity`, `total_price`, `cart_id`,. để lấy chi tiết các item hãy nối qua cart tù cart nối cart_item\n"
#     """- Tránh lỗi:(1054, "Unknown column 'c.is_deleted' in 'where clause'") vì cart không có thuộc tính is_deleted, cart_item không có thuộc tính user_id"""
#     "- Quan trọng:  Không cần thêm các điều kiện `is_deleted = 0` như:\n"
#     "    AND oi.is_deleted = 0\n"
#     "    AND ci.is_deleted = 0\n"
    
#     "    AND pv.is_deleted = 0\n"
#     "    AND p.is_deleted = 0\n"
#     "    AND cat.is_deleted = 0\n"
#     "    AND c.is_deleted = 0\n"
#     "- ✅ Các câu SQL đã được kiểm tra và chạy thành công trên hệ thống – vui lòng không tự động thêm các điều kiện lọc `is_deleted`.\n"
#     "Khi lấy chi tiết tiết các item thì cần lấy pro_name, size và, price"
#     "Vui lòng  luu ý rang order_item không có cột pro_id,size chỉ có các cột order_item_id, order_id, quantity, total_pric \n"
#             "- Không cần thêm điều kiện `is_deleted = 0` trong các bảng như `oi`, `ci`, `pv`, `p`, `cat`, `c`.\n"
#         )

#         # Ghép prompt chính để gửi đi
#         question_prompt = merged_prompt + f"[ Vui long thục hiện Yêu cầu {step_id}]\n{step['content']}" + sql_warning

#         print(f"\n=== 🧩 Thực thi Yêu cầu {step_id} ===")

#         # Gọi hàm async thực thi câu hỏi
#         result = await query_func(question_prompt, user_id, languages, role)

#         results[step_id] = result
#         print(f"\n✅ 📤 Kết quả Yêu cầu {step_id}: {result}")

#     return results

# async def run_pipeline(text, query_func,user_id,role,languages):
#     steps = parse_step_data_blocks(text)
#     extract_dependencies(steps)
#     graph = build_dependency_graph(steps)
#     order = topological_sort(steps, graph)
#     print("\n🔗 Thứ tự thực thi hợp lệ theo phụ thuộc:", order)
#     data =  await execute_steps(steps, order, query_func,user_id,role,languages)
#     return data

import re
from collections import defaultdict, deque
import asyncio

def parse_step_data_blocks(text):
    blocks = re.findall(r"<step_data>(.*?)</step_data>", text, re.DOTALL)
    parsed_steps = []

    for block in blocks:
        match = re.search(r"Yêu cầu\s+(\d+):", block.strip())
        if match:
            step_id = int(match.group(1))
            parsed_steps.append({
                "id": step_id,
                "content": block.strip(),
                "dependencies": set(),
            })
    return parsed_steps


def extract_dependencies(steps):
    for step in steps:
        deps = re.findall(r"Yêu cầu\s+(\d+)", step["content"])
        step["dependencies"] = {int(d) for d in deps if int(d) != step["id"]}


def build_dependency_graph(steps):
    graph = defaultdict(list)
    for step in steps:
        for dep in step["dependencies"]:
            graph[dep].append(step["id"])
    return graph


def topological_sort(steps, graph):
    indegree = {step["id"]: 0 for step in steps}
    for step in steps:
        for dep in step["dependencies"]:
            indegree[step["id"]] += 1

    queue = deque([sid for sid, deg in indegree.items() if deg == 0])
    sorted_order = []

    while queue:
        current = queue.popleft()
        sorted_order.append(current)
        for neighbor in graph[current]:
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                queue.append(neighbor)

    return sorted_order

async def execute_steps_parallel(steps, graph, query_func, user_id, role, languages):
    results = {}
    step_map = {s["id"]: s for s in steps}
    indegree = {s["id"]: 0 for s in steps}

    for step in steps:
        for dep in step["dependencies"]:
            indegree[step["id"]] += 1

    queue = deque([sid for sid, deg in indegree.items() if deg == 0])

    async def run_step(step_id):
        step = step_map[step_id]

        merged_prompt = ""
        for dep in step["dependencies"]:
            merged_prompt += f"[Yêu cầu {dep}]\n{step_map[dep]['content']}\n"
            merged_prompt += f"[Kết quả {dep}]\n{results[dep]}\n"

        sql_warning = (
            "\n\n⚠️ **Lưu ý khi viết SQL**:\n"
            "- Tránh lỗi như `(1054, \"Unknown column 'oi.pro_id','oi.size' in 'field list'\")`\n"
            "- Vui lòng **kiểm tra kỹ tên cột** trong bảng thực tế.\n"
            "\n\n⚠️ **Lưu ý khi viết SQL** :\n"
    "- Tránh các lỗi như :\n"
    "  ###Tuyệt đối cấm dùng các kí hiệu %, %%s để tránh bị báo lỗi"
    "  (1054, \"Unknown column 'oi.pro_id' in 'field list'\")\n . Luôn đảm bảo bạn không bao giờ bị lỗi này"
    "  (1054, \"Unknown column 'oi.note' in 'field list'\") . Luôn đảm bảo bạn không bao giờ bị lỗi này\n"
    "  (1054, \"Unknown column 'oi.size' in 'field list'\") . Luôn đảm bảo bạn không bao giờ bị lỗi này \n"
    "  (1054, \"Unknown column 'c.is_deleted' in 'on clause'\").  Luôn đảm bảo bạn không bao giờ bị lỗi này\n"
    "- 🔍 Quan trọng(Luôn luôn ghi nhớ): Bảng `order_item` **không có** cột `pro_id`, chỉ gồm các cột: `order_item_id`, `order_id`, `quantity`, `total_price`, `cart_id`,. để lấy chi tiết các item hãy nối qua cart tù cart nối cart_item\n"
    """- Tránh lỗi:(1054, "Unknown column 'c.is_deleted' in 'where clause'") vì cart không có thuộc tính is_deleted, cart_item không có thuộc tính user_id"""
    "- Quan trọng:  Không cần thêm các điều kiện `is_deleted = 0` như:\n"
    "    AND oi.is_deleted = 0\n"
    "    AND ci.is_deleted = 0\n"
    
    "    AND pv.is_deleted = 0\n"
    "    AND p.is_deleted = 0\n"
    "    AND cat.is_deleted = 0\n"
    "    AND c.is_deleted = 0\n"
    "- ✅ Các câu SQL đã được kiểm tra và chạy thành công trên hệ thống – vui lòng không tự động thêm các điều kiện lọc `is_deleted`.\n"
    "Khi lấy chi tiết tiết các item thì cần lấy pro_name, size và, price"
    "Vui lòng  luu ý rang order_item không có cột pro_id,size chỉ có các cột order_item_id, order_id, quantity, total_pric \n"
            "- Không cần thêm điều kiện `is_deleted = 0` trong các bảng như `oi`, `ci`, `pv`, `p`, `cat`, `c`.\n"
        )
        question_prompt = merged_prompt + f"[ Vui lòng thực hiện Yêu cầu {step_id}]\n{step['content']}" + sql_warning

        print(f"\n=== 🧩 Thực thi Yêu cầu {step_id} ===")
        result = await query_func(question_prompt, user_id, languages, role)
        results[step_id] = result
        print(f"\n✅ 📤 Kết quả Yêu cầu {step_id}: {result}")

        for neighbor in graph[step_id]:
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                queue.append(neighbor)

    while queue:
        current_batch = list(queue)
        queue.clear()
        await asyncio.gather(*(run_step(sid) for sid in current_batch))

    return results

async def run_pipeline(text, query_func, user_id, role, languages):
    steps = parse_step_data_blocks(text)
    extract_dependencies(steps)
    graph = build_dependency_graph(steps)
    order = topological_sort(steps, graph)
    print("\n🔗 Thứ tự thực thi hợp lệ theo phụ thuộc:", order)
    data = await execute_steps_parallel(steps, graph, query_func, user_id, role, languages)
    return data