-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode_parser.py
More file actions
160 lines (135 loc) · 6.81 KB
/
Copy pathcode_parser.py
File metadata and controls
160 lines (135 loc) · 6.81 KB
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
import ast
import sqlite3
from sentence_transformers import SentenceTransformer
# Khởi tạo mô hình nhúng vector (Sử dụng mô hình nhỏ gọn, nhẹ cho máy)
model = SentenceTransformer('all-MiniLM-L6-v2')
def extract_functions_from_code(code_content):
"""Bóc tách các hàm từ file code .py sử dụng thư viện AST"""
chunks = []
try:
tree = ast.parse(code_content)
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
# Lấy toàn bộ đoạn code của hàm đó
func_code = ast.get_source_segment(code_content, node)
chunks.append({
"name": node.name,
"line": node.lineno,
"code": func_code
})
except Exception as e:
print(f"Lỗi parse code: {e}")
return chunks
def process_and_store_file(file_content, file_name, user_id):
"""Xử lý file code, kiểm tra trùng lặp từng hàm, trả về kết quả chi tiết dưới dạng dict"""
chunks = extract_functions_from_code(file_content)
if not chunks:
return {"status": "error", "message": "❌ Không tìm thấy hàm Python nào hợp lệ trong file này!"}
conn = sqlite3.connect("code_rag_repository.db")
cursor = conn.cursor()
# [TỐI ƯU HIỆU NĂNG]: Lấy toàn bộ vector hiện tại của user ra bộ nhớ trước để đối chiếu, tránh quét DB trong vòng lặp
cursor.execute("SELECT file_name, class_name, line_number, vector_data FROM code_vectors WHERE user_id = ?", (user_id,))
all_rows = cursor.fetchall()
saved_count = 0
duplicated_functions = []
SIMILARITY_THRESHOLD = 0.38 # Ngưỡng phát hiện trùng
for chunk in chunks:
# 1. Biến đổi đoạn code hiện tại thành vector để chuẩn bị đối chiếu
current_vector = model.encode(chunk['code']).tolist()
is_duplicated = False
duplicate_info = ""
# 2. Đối chiếu trực tiếp trên mảng dữ liệu đã lưu ở RAM
for db_file, db_class, db_line, db_vector_str in all_rows:
try:
db_vector = [float(x) for x in db_vector_str.split(",")]
except:
continue
# Tính độ tương đồng Cosine
dot_product = sum(a * b for a, b in zip(current_vector, db_vector))
norm_a = sum(a * a for a in current_vector) ** 0.5
norm_b = sum(b * b for b in db_vector) ** 0.5
score = dot_product / (norm_a * norm_b) if (norm_a * norm_b) > 0 else 0
# Nếu phát hiện độ tương đồng vượt ngưỡng, đánh dấu là trùng lặp
if score >= SIMILARITY_THRESHOLD:
is_duplicated = True
duplicate_info = f"Hàm '{chunk['name']}' (dòng {chunk['line']}) giống {score:.1%} với hàm '{db_class}' trong file '{db_file}' (dòng {db_line})"
break
# 3. Quyết định lưu hay chặn
if is_duplicated:
duplicated_functions.append(duplicate_info)
else:
# Nếu code mới hoàn toàn thì lưu vào DB
vector_str = ",".join(map(str, current_vector))
cursor.execute('''
INSERT INTO code_vectors (user_id, file_name, class_name, line_number, embedding_text, vector_data)
VALUES (?, ?, ?, ?, ?, ?)
''', (user_id, file_name, chunk['name'], chunk['line'], chunk['code'], vector_str))
saved_count += 1
# Đồng thời cập nhật luôn vào bộ nhớ tạm all_rows để các hàm phía sau trong cùng file đối chiếu chéo được luôn
all_rows.append((file_name, chunk['name'], chunk['line'], vector_str))
conn.commit()
conn.close()
# 4. Trả về kết quả cấu trúc tường minh để app.py bắt lỗi chính xác
if saved_count == 0 and duplicated_functions:
return {
"status": "duplicated",
"message": "Toàn bộ hàm trong file đều bị trùng lặp!",
"duplicate_info": "\n".join(duplicated_functions)
}
return {
"status": "success",
"saved_count": saved_count,
"duplicated_count": len(duplicated_functions),
"duplicate_info": "\n".join(duplicated_functions) if duplicated_functions else ""
}
def retrieve_context_from_sqlite(user_query, user_id, top_k=1):
"""Tìm kiếm đoạn code trùng khớp nhất dựa trên độ tương đồng Cosine"""
conn = sqlite3.connect("code_rag_repository.db")
cursor = conn.cursor()
cursor.execute("SELECT file_name, class_name, line_number, embedding_text, vector_data FROM code_vectors WHERE user_id=?", (user_id,))
rows = cursor.fetchall()
conn.close()
if not rows:
return []
query_vector = model.encode(user_query).tolist()
matched_results = []
for file_name, class_name, line_number, embedding_text, vector_data_str in rows:
try:
db_vector = [float(x) for x in vector_data_str.split(",")]
except:
continue
dot_product = sum(a * b for a, b in zip(query_vector, db_vector))
norm_a = sum(a * a for a in query_vector) ** 0.5
norm_b = sum(b * b for b in db_vector) ** 0.5
score = dot_product / (norm_a * norm_b) if (norm_a * norm_b) > 0 else 0
matched_results.append({
"file_name": file_name,
"class_name": class_name,
"line_number": line_number,
"embedding_text": embedding_text,
"score": score
})
matched_results.sort(key=lambda x: x['score'], reverse=True)
return matched_results[:top_k]
def delete_file_from_sqlite(file_name, user_id):
"""Xóa toàn bộ các hàm đã lưu của một file cụ thể khỏi SQLite"""
try:
conn = sqlite3.connect("code_rag_repository.db")
cursor = conn.cursor()
cursor.execute("DELETE FROM code_vectors WHERE file_name = ? AND user_id = ?", (file_name, user_id))
conn.commit()
conn.close()
return f"🗑️ Đã xóa sạch dữ liệu của file '{file_name}' khỏi hệ thống!"
except Exception as e:
return f"❌ Lỗi khi xóa file: {e}"
def get_uploaded_files(user_id):
"""Lấy danh sách tên các file độc nhất đã được lưu trong SQLite của user"""
try:
conn = sqlite3.connect("code_rag_repository.db")
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT file_name FROM code_vectors WHERE user_id = ?", (user_id,))
rows = cursor.fetchall()
conn.close()
return [row[0] for row in rows]
except Exception as e:
return []