Update app.py
Browse files
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 |
-
|
| 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']
|
| 61 |
-
|
| 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 |
-
|
| 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 |
-
|
| 83 |
-
self.graph.entities = {
|
| 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
|
| 91 |
-
entity = self.graph.entities.get(
|
| 92 |
if entity:
|
| 93 |
-
obs_to_delete = set(
|
| 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 |
-
|
| 98 |
-
|
| 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 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 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 |
-
|
| 143 |
-
|
| 144 |
-
|
| 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.
|
| 163 |
-
#
|
| 164 |
def create_entities(entities: List[Dict]) -> str:
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
def create_relations(relations: List[Dict]) -> str:
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
def add_observations(observations: List[Dict]) -> str:
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
def delete_entities(entityNames: List[str]) -> str:
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
def delete_observations(deletions: List[Dict]) -> str:
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
def delete_relations(relations: List[Dict]) -> str:
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
with gr.Row():
|
| 220 |
-
open_names = gr.Textbox(label="打开节点", placeholder="输入实体名称,用逗号分隔...")
|
| 221 |
-
open_btn = gr.Button("打开指定节点")
|
| 222 |
-
|
| 223 |
-
# ... 其他Tab (创建/添加, 删除) 保持不变 ...
|
| 224 |
with gr.TabItem("创建与添加"):
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 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 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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__":
|