Add deletion
This commit is contained in:
parent
b84872f507
commit
56751ebc1c
18
app/api.py
18
app/api.py
|
|
@ -64,6 +64,22 @@ def delete_graph(graph_id):
|
||||||
return jsonify({"error": f"Не удалось удалить граф {graph_id}."}, 500)
|
return jsonify({"error": f"Не удалось удалить граф {graph_id}."}, 500)
|
||||||
|
|
||||||
|
|
||||||
|
@api.route('/api/graphs/<graph_id>/nodes/<node_id>', methods=['DELETE'])
|
||||||
|
def delete_graph_node(graph_id, node_id):
|
||||||
|
"""API endpoint для удаления узла графа."""
|
||||||
|
if not graph_id or not node_id:
|
||||||
|
return jsonify({"error": "Не указаны ID графа или узла для удаления."}, 400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if graph_history_manager.delete_node(graph_id, node_id):
|
||||||
|
return jsonify({"message": f"Узел {node_id} успешно удален из графа {graph_id}."})
|
||||||
|
else:
|
||||||
|
return jsonify({"error": f"Не удалось удалить узел {node_id} из графа {graph_id}."}, 500)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при удалении узла {node_id} из графа {graph_id}: {e}")
|
||||||
|
return jsonify({"error": f"Ошибка сервера при удалении узла: {str(e)}"}, 500)
|
||||||
|
|
||||||
|
|
||||||
@api.route('/api/messages/<graph_id>/<node_id>', methods=['GET'])
|
@api.route('/api/messages/<graph_id>/<node_id>', methods=['GET'])
|
||||||
def get_messages_from_root_to_node(graph_id, node_id):
|
def get_messages_from_root_to_node(graph_id, node_id):
|
||||||
"""API endpoint для получения сообщений от корня до выбранной ноды."""
|
"""API endpoint для получения сообщений от корня до выбранной ноды."""
|
||||||
|
|
@ -78,7 +94,7 @@ def get_messages_from_root_to_node(graph_id, node_id):
|
||||||
return jsonify({"error": "В графе нет активного узла, до которого можно было бы получить сообщения."}, 404)
|
return jsonify({"error": "В графе нет активного узла, до которого можно было бы получить сообщения."}, 404)
|
||||||
|
|
||||||
messages = graph_history_manager.get_messages_from_root_to_node(
|
messages = graph_history_manager.get_messages_from_root_to_node(
|
||||||
graph_data, target_node_id)
|
graph_id, graph_data, target_node_id)
|
||||||
return jsonify(messages)
|
return jsonify(messages)
|
||||||
|
|
||||||
@api.route('/api/models', methods=['GET'])
|
@api.route('/api/models', methods=['GET'])
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ class GraphHistoryManager:
|
||||||
resolved_current_node_id = target_node_id if target_node_id else db_current_node_id
|
resolved_current_node_id = target_node_id if target_node_id else db_current_node_id
|
||||||
|
|
||||||
messages = self.get_messages_from_root_to_node(
|
messages = self.get_messages_from_root_to_node(
|
||||||
|
graph_id,
|
||||||
{
|
{
|
||||||
"graph_nodes": graph_nodes,
|
"graph_nodes": graph_nodes,
|
||||||
"graph_edges": graph_edges
|
"graph_edges": graph_edges
|
||||||
|
|
@ -269,6 +270,7 @@ class GraphHistoryManager:
|
||||||
|
|
||||||
# Получаем все сообщения до current_node_id
|
# Получаем все сообщения до current_node_id
|
||||||
full_messages = self.get_messages_from_root_to_node(
|
full_messages = self.get_messages_from_root_to_node(
|
||||||
|
gid,
|
||||||
{
|
{
|
||||||
"graph_nodes": graph_nodes,
|
"graph_nodes": graph_nodes,
|
||||||
"graph_edges": graph_edges
|
"graph_edges": graph_edges
|
||||||
|
|
@ -297,7 +299,9 @@ class GraphHistoryManager:
|
||||||
return summaries
|
return summaries
|
||||||
|
|
||||||
def get_messages_from_root_to_node(
|
def get_messages_from_root_to_node(
|
||||||
self, graph_data: Dict[str, Any],
|
self,
|
||||||
|
graph_id: str, # НОВЫЙ АРГУМЕНТ
|
||||||
|
graph_data: Dict[str, Any],
|
||||||
target_node_id: str) -> List[Dict[str, str]]:
|
target_node_id: str) -> List[Dict[str, str]]:
|
||||||
"""
|
"""
|
||||||
Получает список сообщений от корневого узла до указанного узла.
|
Получает список сообщений от корневого узла до указанного узла.
|
||||||
|
|
@ -316,8 +320,12 @@ class GraphHistoryManager:
|
||||||
current = node_id
|
current = node_id
|
||||||
while current in parent_map:
|
while current in parent_map:
|
||||||
current = parent_map[current]
|
current = parent_map[current]
|
||||||
|
# Проверяем, чтобы не зациклиться (хотя в древовидном графе это не должно быть проблемой)
|
||||||
|
if current in path:
|
||||||
|
print(f"Обнаружен цикл при построении пути к узлу {node_id}. Путь: {path}")
|
||||||
|
break
|
||||||
path.append(current)
|
path.append(current)
|
||||||
return path[::-1]
|
return path[::-1] # Разворачиваем путь от корня до целевого узла
|
||||||
|
|
||||||
path_to_target = get_path_to_root(target_node_id)
|
path_to_target = get_path_to_root(target_node_id)
|
||||||
# Собираем сообщения, соответствующие узлам в пути.
|
# Собираем сообщения, соответствующие узлам в пути.
|
||||||
|
|
@ -332,11 +340,12 @@ class GraphHistoryManager:
|
||||||
"role":
|
"role":
|
||||||
original_message.get("role", "unknown"),
|
original_message.get("role", "unknown"),
|
||||||
"type":
|
"type":
|
||||||
node.get("type", "unknown"), # Используем 'type' узла
|
node.get("type", "unknown"),
|
||||||
"content":
|
"content":
|
||||||
original_message.get("content", ""),
|
original_message.get("content", ""),
|
||||||
"node_id":
|
"node_id":
|
||||||
original_message.get("node_id", node_id)
|
original_message.get("node_id", node_id),
|
||||||
|
"graph_id": graph_id
|
||||||
})
|
})
|
||||||
|
|
||||||
return messages_for_path
|
return messages_for_path
|
||||||
|
|
@ -357,6 +366,69 @@ class GraphHistoryManager:
|
||||||
print(f"Ошибка при удалении графа: {e}")
|
print(f"Ошибка при удалении графа: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def delete_node(self, graph_id: str, node_id: str) -> bool:
|
||||||
|
"""
|
||||||
|
Удаляет узел из графа и переподключает его родителей к его детям.
|
||||||
|
Обновляет current_node_id, если удаляемый узел был текущим.
|
||||||
|
"""
|
||||||
|
with self._get_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
try:
|
||||||
|
# 1. Получаем информацию о текущем узле графа
|
||||||
|
cursor.execute("SELECT current_node_id FROM graphs WHERE id = ?", (graph_id,))
|
||||||
|
current_graph_node_id = cursor.fetchone()[0] if cursor.rowcount > 0 else None
|
||||||
|
|
||||||
|
# 2. Находим родителей и детей удаляемого узла
|
||||||
|
# Родители
|
||||||
|
cursor.execute("SELECT source_node_id FROM graph_edges_data WHERE graph_id = ? AND target_node_id = ?",
|
||||||
|
(graph_id, node_id))
|
||||||
|
parents = [row[0] for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
# Дети
|
||||||
|
cursor.execute("SELECT target_node_id FROM graph_edges_data WHERE graph_id = ? AND source_node_id = ?",
|
||||||
|
(graph_id, node_id))
|
||||||
|
children = [row[0] for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
# 3. Переподключаем родителей к детям
|
||||||
|
for parent_id in parents:
|
||||||
|
for child_id in children:
|
||||||
|
# Создаем новое ребро между родителем и ребенком
|
||||||
|
new_edge_id = str(uuid.uuid4())
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT OR IGNORE INTO graph_edges_data (graph_id, edge_id, source_node_id, target_node_id) VALUES (?, ?, ?, ?)",
|
||||||
|
(graph_id, new_edge_id, parent_id, child_id))
|
||||||
|
|
||||||
|
# 4. Удаляем все ребра, связанные с удаляемым узлом (входящие и исходящие)
|
||||||
|
cursor.execute("DELETE FROM graph_edges_data WHERE graph_id = ? AND (source_node_id = ? OR target_node_id = ?)",
|
||||||
|
(graph_id, node_id, node_id))
|
||||||
|
|
||||||
|
# 5. Удаляем сам узел
|
||||||
|
cursor.execute("DELETE FROM graph_nodes_data WHERE graph_id = ? AND node_id = ?",
|
||||||
|
(graph_id, node_id))
|
||||||
|
node_deleted = cursor.rowcount > 0
|
||||||
|
|
||||||
|
# TODO: Здесь не полная логика, т.к. если родителей нет, то current_node_id=None останется
|
||||||
|
# 6. Обновляем current_node_id, если удаленный узел был текущим
|
||||||
|
if node_id == current_graph_node_id:
|
||||||
|
new_current_node_id = None
|
||||||
|
if parents:
|
||||||
|
# Если есть родители, делаем текущим узлом одного из родителей
|
||||||
|
# Для простоты, берем первого родителя. Можно добавить более сложную логику,
|
||||||
|
# например, последнего добавленного родителя, если timestamp доступен.
|
||||||
|
new_current_node_id = parents[0]
|
||||||
|
# Если детей нет и родителей тоже, current_node_id останется None.
|
||||||
|
|
||||||
|
cursor.execute("UPDATE graphs SET current_node_id = ? WHERE id = ?",
|
||||||
|
(new_current_node_id, graph_id))
|
||||||
|
print(f"current_node_id для графа {graph_id} обновлен на {new_current_node_id}")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
return node_deleted
|
||||||
|
except Exception as e:
|
||||||
|
conn.rollback()
|
||||||
|
print(f"Ошибка при удалении узла {node_id} из графа {graph_id}: {e}")
|
||||||
|
raise # Пробрасываем исключение, чтобы API мог вернуть 500
|
||||||
|
|
||||||
# ----------------------------------------------- Title Update Methods ------------------------------------------------------------
|
# ----------------------------------------------- Title Update Methods ------------------------------------------------------------
|
||||||
|
|
||||||
def update_graph_title(self, graph_id: str, title: str):
|
def update_graph_title(self, graph_id: str, title: str):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user