Khi triển khai mô hình Qwen3-4B Instruct, dữ liệu hội thoại thường bị mất sau khi đóng trình duyệt hoặc khởi động lại dịch vụ. Giải pháp này sử dụng SQLite để lưu trữ lịch sử hội thoại một cách bền vững, đảm bảo dữ liệu có thể truy xuất lại sau khi restart.
Trước khi bắt đầu, hãy đảm bảo môi trường đã được cấu hình đúng. Mô hình Qwen3-4B Instruct cần được triển khai và chạy thành công. Các thư viện cần thiết bao gồm Streamlit và SQLite. Trong terminal, chạy lệnh sau để kiểm tra:
pip install streamlit transformers accelerate torchSQLite đã được tích hợp sẵn trong Python, không cần cài đặt thêm.
Phần chính của giải pháp là tạo một lớp quản lý cơ sở dữ liệu. Dưới đây là ví dụ về cấu trúc bảng và phương thức:
import sqlite3
import json
from typing import List, Dict, Optional
class DataPersistence:
def __init__(self, db_path: str = "chat_storage.db"):
self.db_path = db_path
self._setup_tables()
def _setup_tables(self):
connection = sqlite3.connect(self.db_path)
cursor = connection.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS session_records (
record_id INTEGER PRIMARY KEY AUTOINCREMENT,
session_key TEXT NOT NULL,
speaker_role TEXT NOT NULL,
message_content TEXT NOT NULL,
event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
context_data TEXT
)
''')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_session_key ON session_records(session_key)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_event_time ON session_records(event_time)')
connection.commit()
connection.close()
def log_entry(self, session_id: str, role: str, text: str, extra: Optional[Dict] = None):
connection = sqlite3.connect(self.db_path)
cursor = connection.cursor()
context_json = json.dumps(extra) if extra else None
cursor.execute('''
INSERT INTO session_records (session_key, speaker_role, message_content, context_data)
VALUES (?, ?, ?, ?)
''', (session_id, role, text, context_json))
connection.commit()
connection.close()
def retrieve_session(self, session_id: str, max_items: Optional[int] = None) -> List[Dict]:
connection = sqlite3.connect(self.db_path)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
query = '''
SELECT speaker_role, message_content, event_time, context_data
FROM session_records
WHERE session_key = ?
ORDER BY event_time ASC
'''
params = [session_id]
if max_items:
query += ' LIMIT ?'
params.append(max_items)
cursor.execute(query, params)
history = []
for row in cursor.fetchall():
item = {
'role': row['speaker_role'],
'text': row['message_content'],
'timestamp': row['event_time']
}
if row['context_data']:
item['metadata'] = json.loads(row['context_data'])
history.append(item)
connection.close()
return history
def clear_session(self, session_id: str) -> int:
connection = sqlite3.connect(self.db_path)
cursor = connection.cursor()
cursor.execute('DELETE FROM session_records WHERE session_key = ?', (session_id,))
count = cursor.rowcount
connection.commit()
connection.close()
return count
def list_all_sessions(self) -> List[str]:
connection = sqlite3.connect(self.db_path)
cursor = connection.cursor()
cursor.execute('SELECT DISTINCT session_key FROM session_records ORDER BY MIN(event_time) DESC')
sessions = [row[0] for row in cursor.fetchall()]
connection.close()
return sessionsTrong ứng dụng Streamlit chính (app.py), cần tích hợp lớp này:
import streamlit as st
from transformers import AutoModelForCausalLM, AutoTokenizer
from persistence import DataPersistence
storage = DataPersistence()
CURRENT_SESSION = "main_session"
if "chat_history" not in st.session_state:
st.session_state.chat_history = storage.retrieve_session(CURRENT_SESSION) or []
if user_input := st.chat_input("Nhập câu hỏi..."):
st.session_state.chat_history.append({"role": "user", "text": user_input})
storage.log_entry(CURRENT_SESSION, "user", user_input, {"source": "web"})
with st.chat_message("assistant"):
# ... code xử lý AI response ...
ai_response = "Kết quả trả về"
st.session_state.chat_history.append({"role": "assistant", "text": ai_response})
storage.log_entry(CURRENT_SESSION, "assistant", ai_response, {"model": "Qwen3-4B-Instruct-2507"})
with st.sidebar:
if st.button("Xóa dữ liệu hiện tại"):
st.session_state.chat_history = []
deleted = storage.clear_session(CURRENT_SESSION)
st.success(f"Đã xóa {deleted} bản ghi từ cơ sở dữ liệu")
st.rerun()
if st.button("Xem danh sách hội thoại"):
sessions = storage.list_all_sessions()
if sessions:
st.write("Các phiên làm việc hiện có:")
for sid in sessions:
records = storage.retrieve_session(sid)
st.write(f"- `{sid}`: {len(records)} bản ghi")
else:
st.info("Không có dữ liệu nào trong cơ sở dữ liệu")Để kiểm tra, khởi động lại ứng dụng, thực hiện một số cuộc hội thoại, đóng trình duyệt và mở lại. Dữ liệu sẽ được khôi phục từ SQLite. Sử dụng nút "Xóa dữ liệu hiện tại" để xóa dữ liệu khỏi cả bộ nhớ và cơ sở dữ liệu.
| Chức năng | Trước khi tích hợp | Sau khi tích hợp |
|---|---|---|
| Lưu trữ lịch sử | Chỉ tồn tại trong bộ nhớ trình duyệt | Lưu trữ bền vững trong SQLite |
| Khôi phục sau restart | Không thể | Có thể |
| Quản lý dữ liệu | Không hỗ trợ | Hỗ trợ xóa và xem danh sách hội thoại |
Các cải tiến có thể thực hiện bao gồm: hỗ trợ nhiều hội thoại đồng thời, giao diện tìm kiếm lịch sử, xuất dữ liệu sang định dạng khác, hoặc tích hợp với cơ sở dữ liệu lớn hơn như PostgreSQL.