import sqlite3 import datetime import json import os import random # <--- Thêm thư viện này để random dữ liệu # --- CẤU HÌNH ĐƯỜNG DẪN TUYỆT ĐỐI --- # Lấy thư mục chứa file database.py hiện tại BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Tạo đường dẫn file DB nằm ngay tại thư mục này DB_PATH = os.path.join(BASE_DIR, "vnpt_call_center.db") print(f"[DB SYSTEM] Database file path: {DB_PATH}") # --- HÀM SINH DỮ LIỆU MẪU THÔNG MINH (DYNAMIC DATE) --- def generate_seed_data(): data = [] now = datetime.datetime.now() # Tạo 20 cuộc gọi mẫu for i in range(20): # 12 cuộc gọi cho ngày HÔM NAY (Để Dashboard nhảy số ngay) if i < 12: minutes_ago = random.randint(5, 700) # Cách đây vài phút đến vài tiếng call_time = now - datetime.timedelta(minutes=minutes_ago) else: # 8 cuộc gọi còn lại cho TUẦN NÀY (Cách đây 1-6 ngày) days_ago = random.randint(1, 6) call_time = now - datetime.timedelta(days=days_ago) timestamp_str = call_time.isoformat() # Random chỉ số để biểu đồ đẹp intent = random.choice(["network_issue", "cancel_package", "competitor", "low_data"]) # Logic giả lập cảm xúc theo intent if intent == "cancel_package": sentiment = "negative" csat = random.randint(1, 3) elif intent == "competitor": sentiment = "neutral" csat = random.randint(3, 4) else: sentiment = "positive" csat = 5 item = { "customer_id": f"CUS_{i+1:03d}", "call_id": f"SEED_{i+1}", "call_timestamp": timestamp_str, "call_duration_seconds": random.randint(60, 300), "intent": intent, "sentiment": sentiment, "ai_resolved": random.choice([True, True, False]), # Tỉ lệ True cao hơn "upsell_success": random.choice([True, False, False]), "csat": csat, "cost_per_call_vnd": random.randint(1500, 5000) } data.append(item) return data class Database: def __init__(self): self.conn = None self._init_db() def _get_conn(self): # SỬA LỖI: Dùng DB_PATH tuyệt đối return sqlite3.connect(DB_PATH, check_same_thread=False) def _init_db(self): conn = self._get_conn() cursor = conn.cursor() # Tạo bảng nếu chưa có cursor.execute(''' CREATE TABLE IF NOT EXISTS calls ( id INTEGER PRIMARY KEY AUTOINCREMENT, customer_id TEXT, call_id TEXT, call_timestamp DATETIME, duration INTEGER, intent TEXT, sentiment TEXT, ai_resolved BOOLEAN, upsell BOOLEAN, csat INTEGER, cost INTEGER ) ''') # Kiểm tra dữ liệu cursor.execute("SELECT count(*) FROM calls") count = cursor.fetchone()[0] if count == 0: print(" [DB] Database trống. Đang nạp 20 bản ghi mẫu cho HÔM NAY...") # Gọi hàm sinh dữ liệu động thay vì dùng list tĩnh seed_data = generate_seed_data() self._seed_data(cursor, seed_data) conn.commit() conn.close() def _seed_data(self, cursor, data): for item in data: cursor.execute(''' INSERT INTO calls (customer_id, call_id, call_timestamp, duration, intent, sentiment, ai_resolved, upsell, csat, cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( item['customer_id'], item['call_id'], item['call_timestamp'], item['call_duration_seconds'], item['intent'], item['sentiment'], item['ai_resolved'], item['upsell_success'], item['csat'], item['cost_per_call_vnd'] )) # --- HÀM THÊM MỚI (Logic giữ nguyên) --- def add_call(self, customer_id, duration, intent, sentiment, ai_resolved, upsell, cost): conn = self._get_conn() cursor = conn.cursor() call_id = f"LIVE_{int(datetime.datetime.now().timestamp())}" timestamp = datetime.datetime.now().isoformat() # Xử lý cost dictionary cost_val = cost['value'] if isinstance(cost, dict) else cost csat_val = cost['csat'] if isinstance(cost, dict) else 4 cursor.execute(''' INSERT INTO calls (customer_id, call_id, call_timestamp, duration, intent, sentiment, ai_resolved, upsell, csat, cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', (customer_id, call_id, timestamp, duration, intent, sentiment, ai_resolved, upsell, csat_val, cost_val)) conn.commit() conn.close() # --- HÀM CẬP NHẬT ĐÁNH GIÁ SAO (Logic giữ nguyên) --- def update_call_rating(self, customer_id, stars, note): conn = self._get_conn() cursor = conn.cursor() try: cursor.execute(''' SELECT id FROM calls WHERE customer_id = ? ORDER BY id DESC LIMIT 1 ''', (str(customer_id),)) row = cursor.fetchone() if row: call_id_db = row[0] cursor.execute('UPDATE calls SET csat = ? WHERE id = ?', (int(stars), call_id_db)) conn.commit() print(f" [DB] Đã cập nhật CSAT={stars} cho khách {customer_id}") else: print(f" [DB] Không tìm thấy cuộc gọi nào của khách {customer_id} để update.") except Exception as e: print(f" [DB Error] Update Rating: {e}") finally: conn.close() # --- HÀM LẤY DỮ LIỆU CHO DASHBOARD (Sửa key trả về cho khớp Frontend) --- def get_all_calls(self): conn = self._get_conn() cursor = conn.cursor() cursor.execute("SELECT * FROM calls ORDER BY call_timestamp DESC") rows = cursor.fetchall() result = [] for r in rows: result.append({ "id": r[1], # customer_id "time": r[3], # call_timestamp "dur": r[4], # duration "intent": r[5], "sent": r[6], "ai": bool(r[7]), "upsell": bool(r[8]), "csat": r[9], "cost": r[10] }) conn.close() return result # Khởi tạo singleton db = Database()