play7284 commited on
Commit
78e9173
·
verified ·
1 Parent(s): 9bd9a5d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +201 -193
app.py CHANGED
@@ -1,265 +1,273 @@
1
  import gradio as gr
2
- import os
3
  import json
4
  from dataclasses import dataclass, field, asdict
5
  from typing import List, Dict, Any, Tuple
6
 
7
- # --- 1. 数据结构定义 (与之前相同) ---
8
-
9
  @dataclass
10
  class Entity:
11
  name: str
12
  entityType: str
13
  observations: List[str] = field(default_factory=list)
14
-
15
  @dataclass
16
  class Relation:
17
  from_entity: str
18
  to_entity: str
19
  relationType: str
20
-
21
  @dataclass
22
  class KnowledgeGraph:
23
  entities: Dict[str, Entity] = field(default_factory=dict)
24
  relations: List[Relation] = field(default_factory=list)
25
 
26
-
27
- # --- 2. 核心逻辑: KnowledgeGraphManager (修改为纯内存) ---
28
-
29
  class KnowledgeGraphManager:
30
- """
31
- 这个版本的 Manager 将知识图谱完全保存在内存中。
32
- 服务器重启后,所有数据都会丢失。
33
- """
34
  def __init__(self):
35
- # 服务器启动时,在内存中初始化一个空的知识图谱
36
  self.graph = KnowledgeGraph()
37
  print("Initialized a new, empty in-memory knowledge graph.")
38
-
39
  def _reset_graph(self):
40
- """提供一个方法来手动重置图谱,主要用于UI。"""
41
  self.graph = KnowledgeGraph()
42
  return "In-memory knowledge graph has been reset to an empty state."
43
-
44
  def create_entities(self, entities_data: List[Dict]) -> List[Entity]:
45
  new_entities = []
46
  for e_data in entities_data:
47
  if e_data['name'] not in self.graph.entities:
48
- new_entity = Entity(**e_data)
49
- self.graph.entities[e_data['name']] = new_entity
50
- new_entities.append(new_entity)
51
  return new_entities
52
-
53
  def create_relations(self, relations_data: List[Dict]) -> List[Relation]:
54
  new_relations = []
55
- existing_relations_set = {
56
- (r.from_entity, r.to_entity, r.relationType) for r in self.graph.relations
57
- }
58
  for r_data in relations_data:
59
- r_data['from_entity'] = r_data.pop('from')
60
- r_data['to_entity'] = r_data.pop('to')
61
- if (r_data['from_entity'], r_data['to_entity'], r_data['relationType']) not in existing_relations_set:
62
- new_relation = Relation(**r_data)
63
- self.graph.relations.append(new_relation)
64
- new_relations.append(new_relation)
65
  return new_relations
66
-
67
  def add_observations(self, observations_data: List[Dict]) -> List[Dict]:
68
  results = []
69
  for o_data in observations_data:
70
  entity = self.graph.entities.get(o_data['entityName'])
71
- if not entity:
72
- raise ValueError(f"Entity with name {o_data['entityName']} not found")
73
-
74
- new_observations = [
75
- obs for obs in o_data['contents'] if obs not in entity.observations
76
- ]
77
- entity.observations.extend(new_observations)
78
- results.append({"entityName": entity.name, "addedObservations": new_observations})
79
  return results
80
-
81
  def delete_entities(self, entity_names: List[str]) -> None:
82
- names_to_delete = set(entity_names)
83
- self.graph.entities = {name: entity for name, entity in self.graph.entities.items() if name not in names_to_delete}
84
- self.graph.relations = [
85
- r for r in self.graph.relations
86
- if r.from_entity not in names_to_delete and r.to_entity not in names_to_delete
87
- ]
88
-
89
  def delete_observations(self, deletions_data: List[Dict]) -> None:
90
- for d_data in deletions_data:
91
- entity = self.graph.entities.get(d_data['entityName'])
92
  if entity:
93
- obs_to_delete = set(d_data['observations'])
94
- entity.observations = [obs for obs in entity.observations if obs not in obs_to_delete]
95
-
96
  def delete_relations(self, relations_data: List[Dict]) -> None:
97
- relations_to_delete = {
98
- (r.get('from'), r.get('to'), r.get('relationType')) for r in relations_data
99
- }
100
- self.graph.relations = [
101
- r for r in self.graph.relations
102
- if (r.from_entity, r.to_entity, r.relationType) not in relations_to_delete
103
- ]
104
-
105
  def read_graph(self) -> Dict:
106
- return {
107
- "entities": [asdict(e) for e in self.graph.entities.values()],
108
- "relations": [
109
- {"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType}
110
- for r in self.graph.relations
111
- ]
112
- }
113
-
114
  def search_nodes(self, query: str) -> Dict:
115
- query_lower = query.lower()
116
-
117
- filtered_entities = [
118
- e for e in self.graph.entities.values() if
119
- query_lower in e.name.lower() or
120
- query_lower in e.entityType.lower() or
121
- any(query_lower in obs.lower() for obs in e.observations)
122
- ]
123
-
124
- filtered_entity_names = {e.name for e in filtered_entities}
125
-
126
- filtered_relations = [
127
- r for r in self.graph.relations if
128
- r.from_entity in filtered_entity_names and r.to_entity in filtered_entity_names
129
- ]
130
-
131
- return {
132
- "entities": [asdict(e) for e in filtered_entities],
133
- "relations": [
134
- {"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType}
135
- for r in filtered_relations
136
- ]
137
- }
138
-
139
  def open_nodes(self, names: List[str]) -> Dict:
140
  names_set = set(names)
141
-
142
- filtered_entities = [e for name, e in self.graph.entities.items() if name in names_set]
143
- filtered_entity_names = {e.name for e in filtered_entities}
144
- filtered_relations = [
145
- r for r in self.graph.relations if
146
- r.from_entity in filtered_entity_names and r.to_entity in filtered_entity_names
147
- ]
148
-
149
- return {
150
- "entities": [asdict(e) for e in filtered_entities],
151
- "relations": [
152
- {"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType}
153
- for r in filtered_relations
154
- ]
155
- }
156
-
157
- # 初始化一个全局的、单例的 Manager 实例
158
- # 所有API调用都将共享这一个实例
159
- kg_manager = KnowledgeGraphManager()
160
 
 
161
 
162
- # --- 3. Gradio MCP 工具函数定义 (与之前相同, 只调用 manager) ---
163
- # ... (所有工具函数如 create_entities, read_graph 等保持不变) ...
164
  def create_entities(entities: List[Dict]) -> str:
165
- try:
166
- new_entities = kg_manager.create_entities(entities)
167
- return json.dumps([asdict(e) for e in new_entities], indent=2)
168
- except Exception as e: return f"Error: {e}"
 
 
 
 
 
 
 
169
  def create_relations(relations: List[Dict]) -> str:
170
- try:
171
- new_relations = kg_manager.create_relations(relations)
172
- return json.dumps([{"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType} for r in new_relations], indent=2)
173
- except Exception as e: return f"Error: {e}"
 
 
 
 
 
 
 
174
  def add_observations(observations: List[Dict]) -> str:
175
- try:
176
- results = kg_manager.add_observations(observations)
177
- return json.dumps(results, indent=2)
178
- except Exception as e: return f"Error: {e}"
 
 
 
 
 
 
 
179
  def delete_entities(entityNames: List[str]) -> str:
180
- try:
181
- kg_manager.delete_entities(entityNames)
182
- return "Entities and their relations deleted successfully."
183
- except Exception as e: return f"Error: {e}"
 
 
 
 
 
 
 
184
  def delete_observations(deletions: List[Dict]) -> str:
185
- try:
186
- kg_manager.delete_observations(deletions)
187
- return "Observations deleted successfully."
188
- except Exception as e: return f"Error: {e}"
 
 
 
 
 
 
 
189
  def delete_relations(relations: List[Dict]) -> str:
190
- try:
191
- kg_manager.delete_relations(relations)
192
- return "Relations deleted successfully."
193
- except Exception as e: return f"Error: {e}"
194
- def read_graph() -> Dict: return kg_manager.read_graph()
195
- def search_nodes(query: str) -> Dict: return kg_manager.search_nodes(query)
196
- def open_nodes(names: List[str]) -> Dict: return kg_manager.open_nodes(names)
197
- def reset_graph_ui() -> Tuple[str, Dict]:
198
- message = kg_manager._reset_graph()
199
- empty_graph = kg_manager.read_graph()
200
- return message, empty_graph
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
- # --- 4. Gradio 界面构建 (略作调整) ---
204
 
 
205
  with gr.Blocks(theme=gr.themes.Soft()) as app:
206
  gr.Markdown("# 知识图谱记忆工具 (纯内存模式)")
207
  gr.Markdown("所有数据都保存在服务器内存中。**关闭或重启服务器将清空所有数据。**")
208
 
 
209
  with gr.Tabs():
210
- # --- 查看/搜索 Tab ---
211
  with gr.TabItem("查看与搜索"):
212
  graph_output = gr.JSON(label="知识图谱内容")
213
- with gr.Row():
214
- read_btn = gr.Button("读取/刷新图谱")
215
- reset_btn = gr.Button("清空并重置图谱", variant="stop")
216
- with gr.Row():
217
- search_query = gr.Textbox(label="搜索查询", placeholder="输入实体名称、类型或观察内容中的关键词...")
218
- search_btn = gr.Button("搜索节点")
219
- with gr.Row():
220
- open_names = gr.Textbox(label="打开节点", placeholder="输入实体名称,用逗号分隔...")
221
- open_btn = gr.Button("打开指定节点")
222
-
223
- # ... 其他Tab (创建/添加, 删除) 保持不变 ...
224
  with gr.TabItem("创建与添加"):
225
- status_output_create = gr.Textbox(label="操作结果", interactive=False)
226
- with gr.Accordion("创建实体", open=True):
227
- create_entities_input = gr.Code(label="实体 (JSON格式)", language="json", value='[\n {\n "name": "Claude 3",\n "entityType": "AI Model",\n "observations": ["Developed by Anthropic", "Is a large language model"]\n }\n]')
228
- create_entities_btn = gr.Button("创建实体")
229
- with gr.Accordion("创建关系", open=False):
230
- create_relations_input = gr.Code(label="关系 (JSON格式)", language="json", value='[\n {\n "from": "Claude 3",\n "to": "Anthropic",\n "relationType": "developed by"\n }\n]')
231
- create_relations_btn = gr.Button("创建关系")
232
- with gr.Accordion("添加观察记录", open=False):
233
- add_obs_input = gr.Code(label="观察记录 (JSON格式)", language="json", value='[\n {\n "entityName": "Claude 3",\n "contents": ["Released in 2024"]\n }\n]')
234
- add_obs_btn = gr.Button("添加观察记录")
235
  with gr.TabItem("删除"):
236
- status_output_delete = gr.Textbox(label="操作结果", interactive=False)
237
- with gr.Accordion("删除实体", open=True):
238
- delete_entities_input = gr.Textbox(label="实体名称 (逗号分隔)", placeholder="Claude 3,Anthropic")
239
- delete_entities_btn = gr.Button("删除实体")
240
- with gr.Accordion("删除关系", open=False):
241
- delete_relations_input = gr.Code(label="关系 (JSON格式)", language="json", value='[\n {\n "from": "Claude 3",\n "to": "Anthropic",\n "relationType": "developed by"\n }\n]')
242
- delete_relations_btn = gr.Button("删除关系")
243
- with gr.Accordion("删除观察记录", open=False):
244
- delete_obs_input = gr.Code(label="要删除的观察记录 (JSON格式)", language="json", value='[\n {\n "entityName": "Claude 3",\n "observations": ["Released in 2024"]\n }\n]')
245
- delete_obs_btn = gr.Button("删除观察记录")
246
-
247
-
248
- # --- 5. 事件与API绑定 (与之前相同) ---
249
- # ... (所有 .click 事件绑定保持不变, 添加 reset_btn 的绑定) ...
250
- read_btn.click(fn=read_graph, outputs=graph_output, api_name="read_graph")
251
- search_btn.click(fn=search_nodes, inputs=search_query, outputs=graph_output, api_name="search_nodes")
252
- open_btn.click(fn=lambda names_str: open_nodes(names=[name.strip() for name in names_str.split(',')]), inputs=open_names, outputs=graph_output, api_name="open_nodes")
253
- create_entities_btn.click(fn=lambda entities_json: create_entities(json.loads(entities_json)), inputs=create_entities_input, outputs=status_output_create, api_name="create_entities")
254
- create_relations_btn.click(fn=lambda relations_json: create_relations(json.loads(relations_json)), inputs=create_relations_input, outputs=status_output_create, api_name="create_relations")
255
- add_obs_btn.click(fn=lambda obs_json: add_observations(json.loads(obs_json)), inputs=add_obs_input, outputs=status_output_create, api_name="add_observations")
256
- delete_entities_btn.click(fn=lambda names_str: delete_entities(entityNames=[name.strip() for name in names_str.split(',')]), inputs=delete_entities_input, outputs=status_output_delete, api_name="delete_entities")
257
- delete_relations_btn.click(fn=lambda relations_json: delete_relations(json.loads(relations_json)), inputs=delete_relations_input, outputs=status_output_delete, api_name="delete_relations")
258
- delete_obs_btn.click(fn=lambda obs_json: delete_observations(json.loads(obs_json)), inputs=delete_obs_input, outputs=status_output_delete, api_name="delete_observations")
259
-
260
- # UI-only reset button
261
- # We need a status output for the reset button, let's reuse one.
262
- reset_btn.click(fn=reset_graph_ui, outputs=[status_output_create, graph_output])
 
 
 
 
 
263
 
264
 
265
  if __name__ == "__main__":
 
1
  import gradio as gr
 
2
  import json
3
  from dataclasses import dataclass, field, asdict
4
  from typing import List, Dict, Any, Tuple
5
 
6
+ # --- 1. 数据结构定义 ---
 
7
  @dataclass
8
  class Entity:
9
  name: str
10
  entityType: str
11
  observations: List[str] = field(default_factory=list)
 
12
  @dataclass
13
  class Relation:
14
  from_entity: str
15
  to_entity: str
16
  relationType: str
 
17
  @dataclass
18
  class KnowledgeGraph:
19
  entities: Dict[str, Entity] = field(default_factory=dict)
20
  relations: List[Relation] = field(default_factory=list)
21
 
22
+ # --- 2. 核心逻辑: KnowledgeGraphManager (纯内存) ---
 
 
23
  class KnowledgeGraphManager:
 
 
 
 
24
  def __init__(self):
 
25
  self.graph = KnowledgeGraph()
26
  print("Initialized a new, empty in-memory knowledge graph.")
 
27
  def _reset_graph(self):
 
28
  self.graph = KnowledgeGraph()
29
  return "In-memory knowledge graph has been reset to an empty state."
30
+ # ... (所有 manager 内部逻辑方法保持不变) ...
31
  def create_entities(self, entities_data: List[Dict]) -> List[Entity]:
32
  new_entities = []
33
  for e_data in entities_data:
34
  if e_data['name'] not in self.graph.entities:
35
+ new_entity = Entity(**e_data); self.graph.entities[e_data['name']] = new_entity; new_entities.append(new_entity)
 
 
36
  return new_entities
 
37
  def create_relations(self, relations_data: List[Dict]) -> List[Relation]:
38
  new_relations = []
39
+ existing = {(r.from_entity, r.to_entity, r.relationType) for r in self.graph.relations}
 
 
40
  for r_data in relations_data:
41
+ r_data['from_entity'] = r_data.pop('from'); r_data['to_entity'] = r_data.pop('to')
42
+ if (r_data['from_entity'], r_data['to_entity'], r_data['relationType']) not in existing:
43
+ new_relation = Relation(**r_data); self.graph.relations.append(new_relation); new_relations.append(new_relation)
 
 
 
44
  return new_relations
 
45
  def add_observations(self, observations_data: List[Dict]) -> List[Dict]:
46
  results = []
47
  for o_data in observations_data:
48
  entity = self.graph.entities.get(o_data['entityName'])
49
+ if not entity: raise ValueError(f"Entity with name {o_data['entityName']} not found")
50
+ new_obs = [obs for obs in o_data['contents'] if obs not in entity.observations]
51
+ entity.observations.extend(new_obs); results.append({"entityName": entity.name, "addedObservations": new_obs})
 
 
 
 
 
52
  return results
 
53
  def delete_entities(self, entity_names: List[str]) -> None:
54
+ to_delete = set(entity_names)
55
+ self.graph.entities = {n: e for n, e in self.graph.entities.items() if n not in to_delete}
56
+ self.graph.relations = [r for r in self.graph.relations if r.from_entity not in to_delete and r.to_entity not in to_delete]
 
 
 
 
57
  def delete_observations(self, deletions_data: List[Dict]) -> None:
58
+ for d in deletions_data:
59
+ entity = self.graph.entities.get(d['entityName'])
60
  if entity:
61
+ obs_to_delete = set(d['observations']); entity.observations = [obs for obs in entity.observations if obs not in obs_to_delete]
 
 
62
  def delete_relations(self, relations_data: List[Dict]) -> None:
63
+ to_delete = {(r.get('from'), r.get('to'), r.get('relationType')) for r in relations_data}
64
+ self.graph.relations = [r for r in self.graph.relations if (r.from_entity, r.to_entity, r.relationType) not in to_delete]
 
 
 
 
 
 
65
  def read_graph(self) -> Dict:
66
+ return {"entities": [asdict(e) for e in self.graph.entities.values()], "relations": [{"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType} for r in self.graph.relations]}
 
 
 
 
 
 
 
67
  def search_nodes(self, query: str) -> Dict:
68
+ q_lower = query.lower()
69
+ f_entities = [e for e in self.graph.entities.values() if q_lower in e.name.lower() or q_lower in e.entityType.lower() or any(q_lower in obs.lower() for obs in e.observations)]
70
+ f_names = {e.name for e in f_entities}
71
+ f_relations = [r for r in self.graph.relations if r.from_entity in f_names and r.to_entity in f_names]
72
+ return {"entities": [asdict(e) for e in f_entities], "relations": [{"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType} for r in f_relations]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  def open_nodes(self, names: List[str]) -> Dict:
74
  names_set = set(names)
75
+ f_entities = [e for n, e in self.graph.entities.items() if n in names_set]
76
+ f_names = {e.name for e in f_entities}
77
+ f_relations = [r for r in self.graph.relations if r.from_entity in f_names and r.to_entity in f_names]
78
+ return {"entities": [asdict(e) for e in f_entities], "relations": [{"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType} for r in f_relations]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
+ kg_manager = KnowledgeGraphManager()
81
 
82
+ # --- 3. API 工具函数定义 (带有完整的文档字符串) ---
83
+ # 这些是我们将要精确暴露的 9 个函数
84
  def create_entities(entities: List[Dict]) -> str:
85
+ """在知识图谱中创建多个新实体。
86
+
87
+ Args:
88
+ entities (List[Dict]): 一个实体对象的列表。每个对象应包含 'name', 'entityType', 'observations' 键。
89
+
90
+ Returns:
91
+ str: 表示成功创建的新实体的JSON字符串。
92
+ """
93
+ new_entities = kg_manager.create_entities(entities)
94
+ return json.dumps([asdict(e) for e in new_entities], indent=2)
95
+
96
  def create_relations(relations: List[Dict]) -> str:
97
+ """在知识图谱中的实体之间创建多个新关系。关系应使用主动语态。
98
+
99
+ Args:
100
+ relations (List[Dict]): 一个关系对象的列表。每个对象应包含 'from', 'to', 'relationType' 键。
101
+
102
+ Returns:
103
+ str: 表示成功创建的新关系的JSON字符串。
104
+ """
105
+ new_relations = kg_manager.create_relations(relations)
106
+ return json.dumps([{"from": r.from_entity, "to": r.to_entity, "relationType": r.relationType} for r in new_relations], indent=2)
107
+
108
  def add_observations(observations: List[Dict]) -> str:
109
+ """向知识图谱中已存在的实体添加新的观察记录。
110
+
111
+ Args:
112
+ observations (List[Dict]): 一个观察对象的列表。每个对象应包含 'entityName' 'contents' (字符串列表)。
113
+
114
+ Returns:
115
+ str: 表示成功添加的观察记录的JSON字符串。
116
+ """
117
+ results = kg_manager.add_observations(observations)
118
+ return json.dumps(results, indent=2)
119
+
120
  def delete_entities(entityNames: List[str]) -> str:
121
+ """从知识图谱中删除多个实体及其相关联的关系。
122
+
123
+ Args:
124
+ entityNames (List[str]): 一个要删除的实体名称的列表。
125
+
126
+ Returns:
127
+ str: 表示操作成功的消息。
128
+ """
129
+ kg_manager.delete_entities(entityNames)
130
+ return "Entities and their relations deleted successfully."
131
+
132
  def delete_observations(deletions: List[Dict]) -> str:
133
+ """从知识图谱中的实体删除特定的观察记录。
134
+
135
+ Args:
136
+ deletions (List[Dict]): 一个删除指令的列表。每个对象应包含 'entityName' 'observations' (字符串列表)。
137
+
138
+ Returns:
139
+ str: 表示操作成功的消息。
140
+ """
141
+ kg_manager.delete_observations(deletions)
142
+ return "Observations deleted successfully."
143
+
144
  def delete_relations(relations: List[Dict]) -> str:
145
+ """从知识图谱中删除多个关系。
146
+
147
+ Args:
148
+ relations (List[Dict]): 一个要删除的关系对象的列表。每个对象应包含 'from', 'to', 'relationType'。
149
+
150
+ Returns:
151
+ str: 表示操作成功的消息。
152
+ """
153
+ kg_manager.delete_relations(relations)
154
+ return "Relations deleted successfully."
155
+
156
+ def read_graph() -> Dict:
157
+ """读取并返回整个知识图谱。
158
+
159
+ Returns:
160
+ Dict: 包含 'entities' 和 'relations' 列表的整个知识图谱。
161
+ """
162
+ return kg_manager.read_graph()
163
+
164
+ def search_nodes(query: str) -> Dict:
165
+ """根据查询词在知识图谱中搜索节点。
166
+
167
+ Args:
168
+ query (str): 用于匹配实体名称、类型和观察内容的搜索词。
169
+
170
+ Returns:
171
+ Dict: 包含匹配的实体和它们之间关系的过滤后的知识图谱。
172
+ """
173
+ return kg_manager.search_nodes(query)
174
+
175
+ def open_nodes(names: List[str]) -> Dict:
176
+ """通过名称打开知识图谱中的特定节点。
177
+
178
+ Args:
179
+ names (List[str]): 一个要检索的实体名称的列表。
180
 
181
+ Returns:
182
+ Dict: 包含指定的实体和它们之间关系的过滤后的知识图谱。
183
+ """
184
+ return kg_manager.open_nodes(names)
185
+
186
+
187
+ # --- 4. UI 辅助函数 ---
188
+ # 这些函数仅用于处理UI输入,不会被暴露为工具。
189
+ def ui_create_entities(json_str: str) -> str:
190
+ try: return create_entities(json.loads(json_str))
191
+ except Exception as e: return f"JSON解析错误或API调用失败: {e}"
192
+ def ui_create_relations(json_str: str) -> str:
193
+ try: return create_relations(json.loads(json_str))
194
+ except Exception as e: return f"JSON解析错误或API调用失败: {e}"
195
+ def ui_add_observations(json_str: str) -> str:
196
+ try: return add_observations(json.loads(json_str))
197
+ except Exception as e: return f"JSON解析错误或API调用失败: {e}"
198
+ def ui_delete_entities(names_str: str) -> str:
199
+ try: return delete_entities([name.strip() for name in names_str.split(',') if name.strip()])
200
+ except Exception as e: return f"API调用失败: {e}"
201
+ def ui_delete_observations(json_str: str) -> str:
202
+ try: return delete_observations(json.loads(json_str))
203
+ except Exception as e: return f"JSON解析错误或API调用失败: {e}"
204
+ def ui_delete_relations(json_str: str) -> str:
205
+ try: return delete_relations(json.loads(json_str))
206
+ except Exception as e: return f"JSON解析错误或API调用失败: {e}"
207
+ def ui_open_nodes(names_str: str) -> Dict:
208
+ try: return open_nodes([name.strip() for name in names_str.split(',') if name.strip()])
209
+ except Exception as e: return {"error": f"API调用失败: {e}"}
210
+ def ui_reset_graph() -> Tuple[str, Dict]:
211
+ message = kg_manager._reset_graph()
212
+ return message, kg_manager.read_graph()
213
 
 
214
 
215
+ # --- 5. Gradio 界面构建 ---
216
  with gr.Blocks(theme=gr.themes.Soft()) as app:
217
  gr.Markdown("# 知识图谱记忆工具 (纯内存模式)")
218
  gr.Markdown("所有数据都保存在服务器内存中。**关闭或重启服务器将清空所有数据。**")
219
 
220
+ # 定义所有UI组件
221
  with gr.Tabs():
 
222
  with gr.TabItem("查看与搜索"):
223
  graph_output = gr.JSON(label="知识图谱内容")
224
+ read_btn = gr.Button("读取/刷新图谱")
225
+ reset_btn = gr.Button("清空并重置图谱", variant="stop")
226
+ search_query = gr.Textbox(label="搜索查询")
227
+ search_btn = gr.Button("搜索节点")
228
+ open_names_str = gr.Textbox(label="打开节点 (逗号分隔)")
229
+ open_btn = gr.Button("打开指定节点")
 
 
 
 
 
230
  with gr.TabItem("创建与添加"):
231
+ status_create = gr.Textbox(label="操作结果", interactive=False)
232
+ create_entities_json = gr.Code(label="实体 (JSON)", language="json", value='[\n {\n "name": "Claude 3", "entityType": "AI Model", "observations": ["Developed by Anthropic"]\n }\n]')
233
+ create_entities_btn = gr.Button("创建实体")
234
+ create_relations_json = gr.Code(label="关系 (JSON)", language="json", value='[\n {\n "from": "Claude 3", "to": "Anthropic", "relationType": "developed by"\n }\n]')
235
+ create_relations_btn = gr.Button("创建关系")
236
+ add_obs_json = gr.Code(label="观察记录 (JSON)", language="json", value='[\n {\n "entityName": "Claude 3", "contents": ["Released in 2024"]\n }\n]')
237
+ add_obs_btn = gr.Button("添加观察记录")
 
 
 
238
  with gr.TabItem("删除"):
239
+ status_delete = gr.Textbox(label="操作结果", interactive=False)
240
+ delete_entities_str = gr.Textbox(label="实体名称 (逗号分隔)")
241
+ delete_entities_btn = gr.Button("删除实体")
242
+ delete_relations_json = gr.Code(label="关系 (JSON)", language="json", value='[\n {\n "from": "Claude 3", "to": "Anthropic", "relationType": "developed by"\n }\n]')
243
+ delete_relations_btn = gr.Button("删除关系")
244
+ delete_obs_json = gr.Code(label="要删除的观察记录 (JSON)", language="json", value='[\n {\n "entityName": "Claude 3", "observations": ["Released in 2024"]\n }\n]')
245
+ delete_obs_btn = gr.Button("删除观察记录")
246
+
247
+ # --- 6. 绑定 UI 事件到辅助函数 (注意:这里没有 api_name) ---
248
+ read_btn.click(fn=read_graph, outputs=graph_output)
249
+ reset_btn.click(fn=ui_reset_graph, outputs=[status_create, graph_output])
250
+ search_btn.click(fn=search_nodes, inputs=search_query, outputs=graph_output)
251
+ open_btn.click(fn=ui_open_nodes, inputs=open_names_str, outputs=graph_output)
252
+ create_entities_btn.click(fn=ui_create_entities, inputs=create_entities_json, outputs=status_create)
253
+ create_relations_btn.click(fn=ui_create_relations, inputs=create_relations_json, outputs=status_create)
254
+ add_obs_btn.click(fn=ui_add_observations, inputs=add_obs_json, outputs=status_create)
255
+ delete_entities_btn.click(fn=ui_delete_entities, inputs=delete_entities_str, outputs=status_delete)
256
+ delete_relations_btn.click(fn=ui_delete_relations, inputs=delete_relations_json, outputs=status_delete)
257
+ delete_obs_btn.click(fn=ui_delete_observations, inputs=delete_obs_json, outputs=status_delete)
258
+
259
+ # --- 7. 显式注册 9 API 工具 ---
260
+ # 我们利用 app.load 事件在应用启动时注册所有工具。
261
+ # 这些事件只用于注册,它们的输入输出没有实际意义。
262
+ app.load(fn=create_entities, inputs=create_entities_json, outputs=status_create, api_name="create_entities",_js="() => []")
263
+ app.load(fn=create_relations, inputs=create_relations_json, outputs=status_create, api_name="create_relations",_js="() => []")
264
+ app.load(fn=add_observations, inputs=add_obs_json, outputs=status_create, api_name="add_observations",_js="() => []")
265
+ app.load(fn=delete_entities, inputs=delete_entities_str, outputs=status_delete, api_name="delete_entities",_js="() => []")
266
+ app.load(fn=delete_observations, inputs=delete_obs_json, outputs=status_delete, api_name="delete_observations",_js="() => []")
267
+ app.load(fn=delete_relations, inputs=delete_relations_json, outputs=status_delete, api_name="delete_relations",_js="() => []")
268
+ app.load(fn=read_graph, outputs=graph_output, api_name="read_graph",_js="() => {}")
269
+ app.load(fn=search_nodes, inputs=search_query, outputs=graph_output, api_name="search_nodes",_js="() => ''")
270
+ app.load(fn=open_nodes, inputs=open_names_str, outputs=graph_output, api_name="open_nodes",_js="() => ''")
271
 
272
 
273
  if __name__ == "__main__":