Spaces:
Sleeping
Sleeping
Update backend/ai/database.py
Browse files- backend/ai/database.py +64 -40
backend/ai/database.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
-
# database.py
|
| 2 |
import sqlite3
|
| 3 |
import datetime
|
| 4 |
import json
|
| 5 |
import os
|
|
|
|
| 6 |
|
| 7 |
-
# --- CẤU HÌNH ĐƯỜNG DẪN TUYỆT ĐỐI
|
| 8 |
# Lấy thư mục chứa file database.py hiện tại
|
| 9 |
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 10 |
# Tạo đường dẫn file DB nằm ngay tại thư mục này
|
|
@@ -12,29 +12,52 @@ DB_PATH = os.path.join(BASE_DIR, "vnpt_call_center.db")
|
|
| 12 |
|
| 13 |
print(f"[DB SYSTEM] Database file path: {DB_PATH}")
|
| 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 |
class Database:
|
| 40 |
def __init__(self):
|
|
@@ -42,7 +65,7 @@ class Database:
|
|
| 42 |
self._init_db()
|
| 43 |
|
| 44 |
def _get_conn(self):
|
| 45 |
-
# SỬA LỖI
|
| 46 |
return sqlite3.connect(DB_PATH, check_same_thread=False)
|
| 47 |
|
| 48 |
def _init_db(self):
|
|
@@ -66,19 +89,21 @@ class Database:
|
|
| 66 |
)
|
| 67 |
''')
|
| 68 |
|
| 69 |
-
# Kiểm tra
|
| 70 |
cursor.execute("SELECT count(*) FROM calls")
|
| 71 |
count = cursor.fetchone()[0]
|
| 72 |
|
| 73 |
if count == 0:
|
| 74 |
-
print(" [DB] Database trống. Đang nạp 20 bản ghi mẫu...")
|
| 75 |
-
|
|
|
|
|
|
|
| 76 |
conn.commit()
|
| 77 |
|
| 78 |
conn.close()
|
| 79 |
|
| 80 |
-
def _seed_data(self, cursor):
|
| 81 |
-
for item in
|
| 82 |
cursor.execute('''
|
| 83 |
INSERT INTO calls (customer_id, call_id, call_timestamp, duration, intent, sentiment, ai_resolved, upsell, csat, cost)
|
| 84 |
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
@@ -95,30 +120,31 @@ class Database:
|
|
| 95 |
item['cost_per_call_vnd']
|
| 96 |
))
|
| 97 |
|
| 98 |
-
# --- HÀM THÊM MỚI (
|
| 99 |
def add_call(self, customer_id, duration, intent, sentiment, ai_resolved, upsell, cost):
|
| 100 |
conn = self._get_conn()
|
| 101 |
cursor = conn.cursor()
|
| 102 |
|
| 103 |
-
# Tạo call_id tự động (LIVE_timestamp)
|
| 104 |
call_id = f"LIVE_{int(datetime.datetime.now().timestamp())}"
|
| 105 |
timestamp = datetime.datetime.now().isoformat()
|
| 106 |
|
| 107 |
-
#
|
|
|
|
|
|
|
|
|
|
| 108 |
cursor.execute('''
|
| 109 |
INSERT INTO calls (customer_id, call_id, call_timestamp, duration, intent, sentiment, ai_resolved, upsell, csat, cost)
|
| 110 |
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
| 111 |
-
''', (customer_id, call_id, timestamp, duration, intent, sentiment, ai_resolved, upsell,
|
| 112 |
|
| 113 |
conn.commit()
|
| 114 |
conn.close()
|
| 115 |
|
| 116 |
-
# --- HÀM CẬP NHẬT ĐÁNH GIÁ SAO ---
|
| 117 |
def update_call_rating(self, customer_id, stars, note):
|
| 118 |
conn = self._get_conn()
|
| 119 |
cursor = conn.cursor()
|
| 120 |
try:
|
| 121 |
-
# Tìm cuộc gọi mới nhất của khách hàng này
|
| 122 |
cursor.execute('''
|
| 123 |
SELECT id FROM calls
|
| 124 |
WHERE customer_id = ?
|
|
@@ -139,16 +165,14 @@ class Database:
|
|
| 139 |
finally:
|
| 140 |
conn.close()
|
| 141 |
|
| 142 |
-
# --- HÀM LẤY DỮ LIỆU CHO DASHBOARD ---
|
| 143 |
def get_all_calls(self):
|
| 144 |
conn = self._get_conn()
|
| 145 |
cursor = conn.cursor()
|
| 146 |
|
| 147 |
-
# Lấy tất cả, sắp xếp mới nhất lên đầu
|
| 148 |
cursor.execute("SELECT * FROM calls ORDER BY call_timestamp DESC")
|
| 149 |
rows = cursor.fetchall()
|
| 150 |
|
| 151 |
-
# Convert tuple sang list of dict để trả về JSON
|
| 152 |
result = []
|
| 153 |
for r in rows:
|
| 154 |
result.append({
|
|
|
|
|
|
|
| 1 |
import sqlite3
|
| 2 |
import datetime
|
| 3 |
import json
|
| 4 |
import os
|
| 5 |
+
import random # <--- Thêm thư viện này để random dữ liệu
|
| 6 |
|
| 7 |
+
# --- CẤU HÌNH ĐƯỜNG DẪN TUYỆT ĐỐI ---
|
| 8 |
# Lấy thư mục chứa file database.py hiện tại
|
| 9 |
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 10 |
# Tạo đường dẫn file DB nằm ngay tại thư mục này
|
|
|
|
| 12 |
|
| 13 |
print(f"[DB SYSTEM] Database file path: {DB_PATH}")
|
| 14 |
|
| 15 |
+
# --- HÀM SINH DỮ LIỆU MẪU THÔNG MINH (DYNAMIC DATE) ---
|
| 16 |
+
def generate_seed_data():
|
| 17 |
+
data = []
|
| 18 |
+
now = datetime.datetime.now()
|
| 19 |
+
|
| 20 |
+
# Tạo 20 cuộc gọi mẫu
|
| 21 |
+
for i in range(20):
|
| 22 |
+
# 12 cuộc gọi cho ngày HÔM NAY (Để Dashboard nhảy số ngay)
|
| 23 |
+
if i < 12:
|
| 24 |
+
minutes_ago = random.randint(5, 700) # Cách đây vài phút đến vài tiếng
|
| 25 |
+
call_time = now - datetime.timedelta(minutes=minutes_ago)
|
| 26 |
+
else:
|
| 27 |
+
# 8 cuộc gọi còn lại cho TUẦN NÀY (Cách đây 1-6 ngày)
|
| 28 |
+
days_ago = random.randint(1, 6)
|
| 29 |
+
call_time = now - datetime.timedelta(days=days_ago)
|
| 30 |
+
|
| 31 |
+
timestamp_str = call_time.isoformat()
|
| 32 |
+
|
| 33 |
+
# Random chỉ số để biểu đồ đẹp
|
| 34 |
+
intent = random.choice(["network_issue", "cancel_package", "competitor", "low_data"])
|
| 35 |
+
|
| 36 |
+
# Logic giả lập cảm xúc theo intent
|
| 37 |
+
if intent == "cancel_package":
|
| 38 |
+
sentiment = "negative"
|
| 39 |
+
csat = random.randint(1, 3)
|
| 40 |
+
elif intent == "competitor":
|
| 41 |
+
sentiment = "neutral"
|
| 42 |
+
csat = random.randint(3, 4)
|
| 43 |
+
else:
|
| 44 |
+
sentiment = "positive"
|
| 45 |
+
csat = 5
|
| 46 |
+
|
| 47 |
+
item = {
|
| 48 |
+
"customer_id": f"CUS_{i+1:03d}",
|
| 49 |
+
"call_id": f"SEED_{i+1}",
|
| 50 |
+
"call_timestamp": timestamp_str,
|
| 51 |
+
"call_duration_seconds": random.randint(60, 300),
|
| 52 |
+
"intent": intent,
|
| 53 |
+
"sentiment": sentiment,
|
| 54 |
+
"ai_resolved": random.choice([True, True, False]), # Tỉ lệ True cao hơn
|
| 55 |
+
"upsell_success": random.choice([True, False, False]),
|
| 56 |
+
"csat": csat,
|
| 57 |
+
"cost_per_call_vnd": random.randint(1500, 5000)
|
| 58 |
+
}
|
| 59 |
+
data.append(item)
|
| 60 |
+
return data
|
| 61 |
|
| 62 |
class Database:
|
| 63 |
def __init__(self):
|
|
|
|
| 65 |
self._init_db()
|
| 66 |
|
| 67 |
def _get_conn(self):
|
| 68 |
+
# SỬA LỖI: Dùng DB_PATH tuyệt đối
|
| 69 |
return sqlite3.connect(DB_PATH, check_same_thread=False)
|
| 70 |
|
| 71 |
def _init_db(self):
|
|
|
|
| 89 |
)
|
| 90 |
''')
|
| 91 |
|
| 92 |
+
# Kiểm tra dữ liệu
|
| 93 |
cursor.execute("SELECT count(*) FROM calls")
|
| 94 |
count = cursor.fetchone()[0]
|
| 95 |
|
| 96 |
if count == 0:
|
| 97 |
+
print(" [DB] Database trống. Đang nạp 20 bản ghi mẫu cho HÔM NAY...")
|
| 98 |
+
# Gọi hàm sinh dữ liệu động thay vì dùng list tĩnh
|
| 99 |
+
seed_data = generate_seed_data()
|
| 100 |
+
self._seed_data(cursor, seed_data)
|
| 101 |
conn.commit()
|
| 102 |
|
| 103 |
conn.close()
|
| 104 |
|
| 105 |
+
def _seed_data(self, cursor, data):
|
| 106 |
+
for item in data:
|
| 107 |
cursor.execute('''
|
| 108 |
INSERT INTO calls (customer_id, call_id, call_timestamp, duration, intent, sentiment, ai_resolved, upsell, csat, cost)
|
| 109 |
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
|
| 120 |
item['cost_per_call_vnd']
|
| 121 |
))
|
| 122 |
|
| 123 |
+
# --- HÀM THÊM MỚI (Logic giữ nguyên) ---
|
| 124 |
def add_call(self, customer_id, duration, intent, sentiment, ai_resolved, upsell, cost):
|
| 125 |
conn = self._get_conn()
|
| 126 |
cursor = conn.cursor()
|
| 127 |
|
|
|
|
| 128 |
call_id = f"LIVE_{int(datetime.datetime.now().timestamp())}"
|
| 129 |
timestamp = datetime.datetime.now().isoformat()
|
| 130 |
|
| 131 |
+
# Xử lý cost dictionary
|
| 132 |
+
cost_val = cost['value'] if isinstance(cost, dict) else cost
|
| 133 |
+
csat_val = cost['csat'] if isinstance(cost, dict) else 4
|
| 134 |
+
|
| 135 |
cursor.execute('''
|
| 136 |
INSERT INTO calls (customer_id, call_id, call_timestamp, duration, intent, sentiment, ai_resolved, upsell, csat, cost)
|
| 137 |
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
| 138 |
+
''', (customer_id, call_id, timestamp, duration, intent, sentiment, ai_resolved, upsell, csat_val, cost_val))
|
| 139 |
|
| 140 |
conn.commit()
|
| 141 |
conn.close()
|
| 142 |
|
| 143 |
+
# --- HÀM CẬP NHẬT ĐÁNH GIÁ SAO (Logic giữ nguyên) ---
|
| 144 |
def update_call_rating(self, customer_id, stars, note):
|
| 145 |
conn = self._get_conn()
|
| 146 |
cursor = conn.cursor()
|
| 147 |
try:
|
|
|
|
| 148 |
cursor.execute('''
|
| 149 |
SELECT id FROM calls
|
| 150 |
WHERE customer_id = ?
|
|
|
|
| 165 |
finally:
|
| 166 |
conn.close()
|
| 167 |
|
| 168 |
+
# --- HÀM LẤY DỮ LIỆU CHO DASHBOARD (Logic giữ nguyên) ---
|
| 169 |
def get_all_calls(self):
|
| 170 |
conn = self._get_conn()
|
| 171 |
cursor = conn.cursor()
|
| 172 |
|
|
|
|
| 173 |
cursor.execute("SELECT * FROM calls ORDER BY call_timestamp DESC")
|
| 174 |
rows = cursor.fetchall()
|
| 175 |
|
|
|
|
| 176 |
result = []
|
| 177 |
for r in rows:
|
| 178 |
result.append({
|