diff --git a/core/client.py b/core/client.py index ef45af0..9eebed7 100644 --- a/core/client.py +++ b/core/client.py @@ -73,6 +73,14 @@ class BackendClient: body={} ) 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: self._server.shutdown() diff --git a/core/embedded_db.py b/core/embedded_db.py index ba76cdc..411d090 100644 --- a/core/embedded_db.py +++ b/core/embedded_db.py @@ -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_status ON relations(status)") - # 创建聊天记录表 cursor.execute(""" - CREATE TABLE IF NOT EXISTS chat_records ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - role TEXT NOT NULL, - content TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) + SELECT name FROM sqlite_master + WHERE type='table' AND name='chat_records' """) - - # 创建聊天记录索引 - cursor.execute("CREATE INDEX IF NOT EXISTS idx_chat_created ON chat_records(created_at)") + if not cursor.fetchone(): + cursor.execute(""" + 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() @@ -445,6 +447,13 @@ class EmbeddedGraphDB: """, (limit,)) 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): """关闭数据库连接""" if self.conn: diff --git a/core/server.py b/core/server.py index e5bd446..2583ed6 100644 --- a/core/server.py +++ b/core/server.py @@ -345,9 +345,12 @@ class BackendServer: def _handle_save_history(self, body: Dict) -> Dict: 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) return {"status": "history_saved"} - + def _send_response(self, request_id: str, response: PacketResponse) -> None: with self._lock: q = self._response_queues.pop(request_id, None) diff --git a/tests/test_core/test_embedded_db.py b/tests/test_core/test_embedded_db.py index 511a1c8..c6f7e48 100644 --- a/tests/test_core/test_embedded_db.py +++ b/tests/test_core/test_embedded_db.py @@ -198,3 +198,21 @@ def test_get_chat_records_default_limit(db): history_default = db.get_chat_records() 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 diff --git a/ui/app.py b/ui/app.py index 5b27cf4..99ec2b0 100644 --- a/ui/app.py +++ b/ui/app.py @@ -143,7 +143,21 @@ class GraphMemoryApp(App): status_bar.set_processing(True) 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: from .widgets.message_history import MessageHistory from .widgets.status_bar import StatusBar diff --git a/ui/widgets/input_box.py b/ui/widgets/input_box.py index 47b2a7a..03335be 100644 --- a/ui/widgets/input_box.py +++ b/ui/widgets/input_box.py @@ -13,6 +13,11 @@ class InputBox(Container): def __init__(self, content: str) -> None: self.content = content super().__init__() + + class ClearHistory(Message): + """清空聊天记录事件""" + def __init__(self) -> None: + super().__init__() def __init__(self, **kwargs): super().__init__(**kwargs) @@ -26,6 +31,7 @@ class InputBox(Container): id="input-textarea" ) with Horizontal(classes="input-buttons"): + yield Button("清空", id="clear-button", variant="default") yield Button("发送", id="send-button", variant="primary") def on_mount(self) -> None: @@ -38,6 +44,8 @@ class InputBox(Container): """处理按钮点击""" if event.button.id == "send-button": self._send_message() + elif event.button.id == "clear-button": + self.post_message(self.ClearHistory()) def on_key(self, event) -> None: """处理按键事件"""