dammmmmmmmm commited on
Commit
fd3f251
·
verified ·
1 Parent(s): a2e44f6

Update backend/ai/database.py

Browse files
Files changed (1) hide show
  1. 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 (BẮT BUỘC) ---
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
- # --- 20 DATA MẪU (SOURCE OF TRUTH) ---
16
- INITIAL_DATA = [
17
- {"customer_id": "CUS_001", "call_id": "CALL_0001", "call_timestamp": "2025-01-20T08:15:00+07:00", "call_duration_seconds": 78, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2350},
18
- {"customer_id": "CUS_002", "call_id": "CALL_0002", "call_timestamp": "2025-01-20T08:35:00+07:00", "call_duration_seconds": 92, "intent": "cancel_package", "sentiment": "neutral", "ai_resolved": True, "upsell_success": True, "csat": 4, "cost_per_call_vnd": 2480},
19
- {"customer_id": "CUS_003", "call_id": "CALL_0003", "call_timestamp": "2025-01-20T09:05:00+07:00", "call_duration_seconds": 110, "intent": "competitor", "sentiment": "negative", "ai_resolved": False, "upsell_success": False, "csat": 3, "cost_per_call_vnd": 2650},
20
- {"customer_id": "CUS_004", "call_id": "CALL_0004", "call_timestamp": "2025-01-20T09:40:00+07:00", "call_duration_seconds": 70, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2300},
21
- {"customer_id": "CUS_005", "call_id": "CALL_0005", "call_timestamp": "2025-01-20T10:10:00+07:00", "call_duration_seconds": 88, "intent": "cancel_package", "sentiment": "neutral", "ai_resolved": True, "upsell_success": True, "csat": 4, "cost_per_call_vnd": 2450},
22
- {"customer_id": "CUS_006", "call_id": "CALL_0006", "call_timestamp": "2025-01-20T10:45:00+07:00", "call_duration_seconds": 80, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2380},
23
- {"customer_id": "CUS_007", "call_id": "CALL_0007", "call_timestamp": "2025-01-18T14:20:00+07:00", "call_duration_seconds": 95, "intent": "cancel_package", "sentiment": "neutral", "ai_resolved": True, "upsell_success": True, "csat": 4, "cost_per_call_vnd": 2500},
24
- {"customer_id": "CUS_008", "call_id": "CALL_0008", "call_timestamp": "2025-01-18T16:05:00+07:00", "call_duration_seconds": 72, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2320},
25
- {"customer_id": "CUS_009", "call_id": "CALL_0009", "call_timestamp": "2025-01-17T10:30:00+07:00", "call_duration_seconds": 105, "intent": "competitor", "sentiment": "negative", "ai_resolved": False, "upsell_success": False, "csat": 3, "cost_per_call_vnd": 2680},
26
- {"customer_id": "CUS_010", "call_id": "CALL_0010", "call_timestamp": "2025-01-17T15:10:00+07:00", "call_duration_seconds": 85, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2400},
27
- {"customer_id": "CUS_011", "call_id": "CALL_0011", "call_timestamp": "2025-01-16T09:45:00+07:00", "call_duration_seconds": 90, "intent": "cancel_package", "sentiment": "neutral", "ai_resolved": True, "upsell_success": True, "csat": 4, "cost_per_call_vnd": 2480},
28
- {"customer_id": "CUS_012", "call_id": "CALL_0012", "call_timestamp": "2025-01-16T11:20:00+07:00", "call_duration_seconds": 76, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2350},
29
- {"customer_id": "CUS_013", "call_id": "CALL_0013", "call_timestamp": "2025-01-15T14:55:00+07:00", "call_duration_seconds": 108, "intent": "competitor", "sentiment": "negative", "ai_resolved": False, "upsell_success": False, "csat": 3, "cost_per_call_vnd": 2620},
30
- {"customer_id": "CUS_014", "call_id": "CALL_0014", "call_timestamp": "2025-01-15T16:40:00+07:00", "call_duration_seconds": 82, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2380},
31
- {"customer_id": "CUS_015", "call_id": "CALL_0015", "call_timestamp": "2025-01-10T10:15:00+07:00", "call_duration_seconds": 88, "intent": "cancel_package", "sentiment": "neutral", "ai_resolved": True, "upsell_success": True, "csat": 4, "cost_per_call_vnd": 2450},
32
- {"customer_id": "CUS_016", "call_id": "CALL_0016", "call_timestamp": "2025-01-08T14:30:00+07:00", "call_duration_seconds": 74, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2350},
33
- {"customer_id": "CUS_017", "call_id": "CALL_0017", "call_timestamp": "2025-01-05T09:50:00+07:00", "call_duration_seconds": 112, "intent": "competitor", "sentiment": "negative", "ai_resolved": False, "upsell_success": False, "csat": 3, "cost_per_call_vnd": 2700},
34
- {"customer_id": "CUS_018", "call_id": "CALL_0018", "call_timestamp": "2025-01-04T15:05:00+07:00", "call_duration_seconds": 80, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2380},
35
- {"customer_id": "CUS_019", "call_id": "CALL_0019", "call_timestamp": "2025-01-03T11:40:00+07:00", "call_duration_seconds": 96, "intent": "cancel_package", "sentiment": "neutral", "ai_resolved": True, "upsell_success": True, "csat": 4, "cost_per_call_vnd": 2500},
36
- {"customer_id": "CUS_020", "call_id": "CALL_0020", "call_timestamp": "2024-12-28T16:10:00+07:00", "call_duration_seconds": 85, "intent": "network_issue", "sentiment": "positive", "ai_resolved": True, "upsell_success": False, "csat": 5, "cost_per_call_vnd": 2400}
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 Ở ĐÂY: Dùng DB_PATH thay vì DB_NAME
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 xem có dữ liệu chưa
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
- self._seed_data(cursor)
 
 
76
  conn.commit()
77
 
78
  conn.close()
79
 
80
- def _seed_data(self, cursor):
81
- for item in INITIAL_DATA:
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 (Dùng cho Live Call) ---
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
- # cost['value'] cost['csat'] từ logic_flow truyền vào
 
 
 
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, cost['csat'], cost['value']))
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ử 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({