mirror of
https://gitcode.com/JianFeeeee/TrulyMEM-TrueHumanMEM.git
synced 2026-10-15 12:15:32 +00:00
feat: 添加数据库迁移、清空聊天记录按钮 - 复用SAVE_HISTORY接口
This commit is contained in:
@ -74,5 +74,13 @@ class BackendClient:
|
|||||||
)
|
)
|
||||||
return self._server.send(packet).body.get("history", [])
|
return self._server.send(packet).body.get("history", [])
|
||||||
|
|
||||||
|
def clear_history(self) -> Dict:
|
||||||
|
packet = Packet(
|
||||||
|
id=self._next_id(),
|
||||||
|
type=PacketType.SAVE_HISTORY,
|
||||||
|
body={"messages": [{"action": "clear"}]}
|
||||||
|
)
|
||||||
|
return self._server.send(packet).body
|
||||||
|
|
||||||
def shutdown(self) -> None:
|
def shutdown(self) -> None:
|
||||||
self._server.shutdown()
|
self._server.shutdown()
|
||||||
|
|||||||
@ -71,18 +71,20 @@ class EmbeddedGraphDB:
|
|||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_relation_type ON relations(relation_type)")
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_relation_type ON relations(relation_type)")
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_relation_status ON relations(status)")
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_relation_status ON relations(status)")
|
||||||
|
|
||||||
# 创建聊天记录表
|
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS chat_records (
|
SELECT name FROM sqlite_master
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
WHERE type='table' AND name='chat_records'
|
||||||
role TEXT NOT NULL,
|
|
||||||
content TEXT NOT NULL,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)
|
|
||||||
""")
|
""")
|
||||||
|
if not cursor.fetchone():
|
||||||
# 创建聊天记录索引
|
cursor.execute("""
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_chat_created ON chat_records(created_at)")
|
CREATE TABLE chat_records (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
role TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
cursor.execute("CREATE INDEX idx_chat_created ON chat_records(created_at)")
|
||||||
|
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
@ -445,6 +447,13 @@ class EmbeddedGraphDB:
|
|||||||
""", (limit,))
|
""", (limit,))
|
||||||
return [{"role": row[0], "content": row[1]} for row in cursor.fetchall()]
|
return [{"role": row[0], "content": row[1]} for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
def clear_chat_records(self) -> Dict:
|
||||||
|
"""清空聊天记录(保留图数据库)"""
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute("DELETE FROM chat_records")
|
||||||
|
self.conn.commit()
|
||||||
|
return {"cleared": True}
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""关闭数据库连接"""
|
"""关闭数据库连接"""
|
||||||
if self.conn:
|
if self.conn:
|
||||||
|
|||||||
@ -345,6 +345,9 @@ class BackendServer:
|
|||||||
|
|
||||||
def _handle_save_history(self, body: Dict) -> Dict:
|
def _handle_save_history(self, body: Dict) -> Dict:
|
||||||
messages = body.get("messages", [])
|
messages = body.get("messages", [])
|
||||||
|
if messages and messages[0].get("action") == "clear":
|
||||||
|
self._graph.clear_chat_records()
|
||||||
|
return {"status": "history_cleared"}
|
||||||
result = self._graph.save_chat_records(messages)
|
result = self._graph.save_chat_records(messages)
|
||||||
return {"status": "history_saved"}
|
return {"status": "history_saved"}
|
||||||
|
|
||||||
|
|||||||
@ -198,3 +198,21 @@ def test_get_chat_records_default_limit(db):
|
|||||||
|
|
||||||
history_default = db.get_chat_records()
|
history_default = db.get_chat_records()
|
||||||
assert len(history_default) == 100
|
assert len(history_default) == 100
|
||||||
|
|
||||||
|
|
||||||
|
def test_clear_chat_records(db):
|
||||||
|
"""测试清空聊天记录"""
|
||||||
|
db.save_chat_records([
|
||||||
|
{"role": "user", "content": "测试1"},
|
||||||
|
{"role": "assistant", "content": "回复1"},
|
||||||
|
{"role": "user", "content": "测试2"},
|
||||||
|
])
|
||||||
|
|
||||||
|
history = db.get_chat_records()
|
||||||
|
assert len(history) == 3
|
||||||
|
|
||||||
|
result = db.clear_chat_records()
|
||||||
|
assert result["cleared"] is True
|
||||||
|
|
||||||
|
history_after = db.get_chat_records()
|
||||||
|
assert len(history_after) == 0
|
||||||
|
|||||||
14
ui/app.py
14
ui/app.py
@ -144,6 +144,20 @@ class GraphMemoryApp(App):
|
|||||||
|
|
||||||
asyncio.create_task(self._process(user_input))
|
asyncio.create_task(self._process(user_input))
|
||||||
|
|
||||||
|
def on_input_box_clear_history(self, event) -> None:
|
||||||
|
"""处理清空聊天记录事件"""
|
||||||
|
if not self._backend_client:
|
||||||
|
self.notify("后端未初始化", title="错误", severity="error")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._backend_client.clear_history()
|
||||||
|
|
||||||
|
from .widgets.message_history import MessageHistory
|
||||||
|
history = self.query_one(MessageHistory)
|
||||||
|
history.clear_messages()
|
||||||
|
|
||||||
|
self.notify("聊天记录已清空,AI记忆保持不变", title="提示", severity="information")
|
||||||
|
|
||||||
async def _process(self, user_input: str) -> None:
|
async def _process(self, user_input: str) -> None:
|
||||||
from .widgets.message_history import MessageHistory
|
from .widgets.message_history import MessageHistory
|
||||||
from .widgets.status_bar import StatusBar
|
from .widgets.status_bar import StatusBar
|
||||||
|
|||||||
@ -14,6 +14,11 @@ class InputBox(Container):
|
|||||||
self.content = content
|
self.content = content
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
class ClearHistory(Message):
|
||||||
|
"""清空聊天记录事件"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self._history: list[str] = []
|
self._history: list[str] = []
|
||||||
@ -26,6 +31,7 @@ class InputBox(Container):
|
|||||||
id="input-textarea"
|
id="input-textarea"
|
||||||
)
|
)
|
||||||
with Horizontal(classes="input-buttons"):
|
with Horizontal(classes="input-buttons"):
|
||||||
|
yield Button("清空", id="clear-button", variant="default")
|
||||||
yield Button("发送", id="send-button", variant="primary")
|
yield Button("发送", id="send-button", variant="primary")
|
||||||
|
|
||||||
def on_mount(self) -> None:
|
def on_mount(self) -> None:
|
||||||
@ -38,6 +44,8 @@ class InputBox(Container):
|
|||||||
"""处理按钮点击"""
|
"""处理按钮点击"""
|
||||||
if event.button.id == "send-button":
|
if event.button.id == "send-button":
|
||||||
self._send_message()
|
self._send_message()
|
||||||
|
elif event.button.id == "clear-button":
|
||||||
|
self.post_message(self.ClearHistory())
|
||||||
|
|
||||||
def on_key(self, event) -> None:
|
def on_key(self, event) -> None:
|
||||||
"""处理按键事件"""
|
"""处理按键事件"""
|
||||||
|
|||||||
Reference in New Issue
Block a user