File size: 7,588 Bytes
376ee15 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | # agents/storage.py
import sqlite3
from datetime import datetime
DEFAULT_DB_PATH = "agent_storage.db"
class Storage:
def __init__(self, config=None):
self.config = config or {}
db_path = self.config.get("db_path", DEFAULT_DB_PATH)
self.conn = sqlite3.connect(db_path)
self._init_db()
def _init_db(self):
c = self.conn.cursor()
# 🧠 Таблица дневника
c.execute('''
CREATE TABLE IF NOT EXISTS diary_entries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
tags TEXT,
timestamp TEXT NOT NULL
)
''')
# 📚 Таблица концептов
c.execute('''
CREATE TABLE IF NOT EXISTS concepts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT
)
''')
# 🔗 Таблица связей
c.execute('''
CREATE TABLE IF NOT EXISTS links (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source_id INTEGER,
target_id INTEGER,
relation TEXT,
FOREIGN KEY(source_id) REFERENCES concepts(id),
FOREIGN KEY(target_id) REFERENCES concepts(id)
)
''')
self.conn.commit()
# --- 🧠 Diary API ---
def write_entry(self, text, tags=None):
timestamp = datetime.utcnow().isoformat()
tag_str = ",".join(tags) if tags else ""
self.conn.execute(
'INSERT INTO diary_entries (text, tags, timestamp) VALUES (?, ?, ?)',
(text, tag_str, timestamp)
)
self.conn.commit()
def read_entries(self, limit=10, tag_filter=None):
cursor = self.conn.cursor()
if tag_filter:
# Простейшая фильтрация по включению строки
if isinstance(tag_filter, list):
tag_filter = ",".join(tag_filter)
like_expr = f"%{tag_filter}%"
cursor.execute(
'SELECT * FROM diary_entries WHERE tags LIKE ? ORDER BY id DESC LIMIT ?',
(like_expr, limit)
)
else:
cursor.execute(
'SELECT * FROM diary_entries ORDER BY id DESC LIMIT ?',
(limit,)
)
return cursor.fetchall()
def search_entries_by_time(self, from_ts, to_ts):
cursor = self.conn.cursor()
cursor.execute(
'SELECT * FROM diary_entries WHERE timestamp BETWEEN ? AND ? ORDER BY timestamp DESC',
(from_ts, to_ts)
)
return cursor.fetchall()
# --- 🧠 Semantic Graph API ---
def add_concept(self, name, description=None):
cursor = self.conn.cursor()
cursor.execute(
'INSERT INTO concepts (name, description) VALUES (?, ?)',
(name, description)
)
self.conn.commit()
return cursor.lastrowid
def query_concept(self, name_substr):
cursor = self.conn.execute(
'SELECT id, name, description FROM concepts WHERE name LIKE ?',
(f"%{name_substr}%",)
)
return cursor.fetchall()
def add_link(self, source_id, target_id, relation):
cursor = self.conn.cursor()
cursor.execute(
'INSERT INTO links (source_id, target_id, relation) VALUES (?, ?, ?)',
(source_id, target_id, relation)
)
self.conn.commit()
return cursor.lastrowid
def list_concepts(self):
return self.conn.execute('SELECT * FROM concepts').fetchall()
def list_links(self):
return self.conn.execute('SELECT * FROM links').fetchall()
def expand_graph(self, start_id, depth):
visited = set()
results = []
def dfs(node_id, level):
if level > depth or node_id in visited:
return
visited.add(node_id)
cursor = self.conn.execute(
'SELECT source_id, target_id, relation FROM links WHERE source_id=?',
(node_id,)
)
for row in cursor.fetchall():
results.append(row)
dfs(row[1], level + 1)
dfs(start_id, 0)
return results
def delete_concept(self, concept_id):
self.conn.execute('DELETE FROM concepts WHERE id = ?', (concept_id,))
self.conn.execute('DELETE FROM links WHERE source_id = ? OR target_id = ?', (concept_id, concept_id))
self.conn.commit()
def delete_link(self, link_id):
self.conn.execute('DELETE FROM links WHERE id = ?', (link_id,))
self.conn.commit()
def delete_entry(self, entry_id):
self.conn.execute('DELETE FROM diary_entries WHERE id = ?', (entry_id,))
self.conn.commit()
def export_diary(self):
cursor = self.conn.cursor()
cursor.execute('SELECT id, text, tags, timestamp FROM diary_entries ORDER BY id ASC')
return cursor.fetchall()
def export_graph(self):
cursor = self.conn.cursor()
cursor.execute('SELECT id, name, description FROM concepts ORDER BY id ASC')
concepts = cursor.fetchall()
cursor.execute('SELECT id, source_id, target_id, relation FROM links ORDER BY id ASC')
links = cursor.fetchall()
return {"concepts": concepts, "links": links}
def update_concept(self, concept_id, name=None, description=None):
cursor = self.conn.cursor()
if name is not None:
cursor.execute('UPDATE concepts SET name = ? WHERE id = ?', (name, concept_id))
if description is not None:
cursor.execute('UPDATE concepts SET description = ? WHERE id = ?', (description, concept_id))
self.conn.commit()
def get_tag_stats(self):
cursor = self.conn.cursor()
cursor.execute('SELECT tags FROM diary_entries')
tag_counts = {}
for row in cursor.fetchall():
tags = row[0].split(",") if row[0] else []
for tag in tags:
tag = tag.strip()
if tag:
tag_counts[tag] = tag_counts.get(tag, 0) + 1
return tag_counts
def search_links_by_relation(self, relation):
cursor = self.conn.cursor()
cursor.execute(
'SELECT id, source_id, target_id, relation FROM links WHERE relation LIKE ?',
(f"%{relation}%",)
)
return cursor.fetchall()
def search_concepts(self, query):
cursor = self.conn.execute(
'''SELECT id, name, description FROM concepts
WHERE name LIKE ? OR description LIKE ?''',
(f"%{query}%", f"%{query}%")
)
return cursor.fetchall()
def merge_concepts(self, source_id, target_id):
cursor = self.conn.cursor()
# Перенос всех связей source_id -> target_id
cursor.execute('UPDATE links SET source_id = ? WHERE source_id = ?', (target_id, source_id))
cursor.execute('UPDATE links SET target_id = ? WHERE target_id = ?', (target_id, source_id))
# Удаление исходного концепта
self.delete_concept(source_id)
self.conn.commit()
def find_concept_id_by_name(self, name):
cursor = self.conn.execute('SELECT id FROM concepts WHERE name = ?', (name,))
row = cursor.fetchone()
return row[0] if row else None
def close(self):
self.conn.close()
|