KingOfThoughtFleuren commited on
Commit
f165fa8
·
verified ·
1 Parent(s): bc1c311

Update services/secondary_brain.py

Browse files
Files changed (1) hide show
  1. services/secondary_brain.py +38 -12
services/secondary_brain.py CHANGED
@@ -2,8 +2,32 @@
2
  import os
3
  import json
4
  import datetime
 
5
  from pathlib import Path
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  # Tags that indicate procedural/how-to content worth extracting separately
8
  PROCEDURAL_TAGS = {
9
  "algorithm", "method", "formula", "process", "technique",
@@ -148,21 +172,23 @@ class DomainLayer:
148
  condensed = json.loads(cleaned)
149
 
150
  if isinstance(condensed, list) and len(condensed) > 0:
151
- # Overwrite legend with condensed entries
152
- with open(self.legend_path, "w", encoding="utf-8") as f:
153
- for item in condensed:
154
- item["domain"] = self.domain_name
155
- item["timestamp"] = datetime.datetime.now().isoformat()
156
- f.write(json.dumps(item, ensure_ascii=False) + "\n")
 
 
 
157
 
158
  print(f"[SecondaryBrain] '{self.domain_name}' condensed from {count} → {len(condensed)} entries.", flush=True)
159
 
160
- # Also update condensed_ontology.txt with a summary
161
- ontology_lines = [f"Domain: {self.domain_name}", f"Condensed at: {datetime.datetime.now().isoformat()}", ""]
162
  for item in condensed:
163
  ontology_lines.append(f" [{item.get('sqt','')}] {item.get('summary','')}")
164
- with open(self.ontology_path, "w", encoding="utf-8") as f:
165
- f.write("\n".join(ontology_lines))
166
 
167
  return True
168
 
@@ -310,8 +336,8 @@ class SecondaryBrain:
310
  "concept_count": concept_count,
311
  "last_active": last_active
312
  }
313
- with open(self.index_path, "w", encoding="utf-8") as f:
314
- json.dump(index, f, indent=2, ensure_ascii=False)
315
 
316
  def _get_or_create_domain(self, domain_name: str) -> DomainLayer:
317
  """
 
2
  import os
3
  import json
4
  import datetime
5
+ import tempfile
6
  from pathlib import Path
7
 
8
+
9
+ def _safe_write(filepath: str, content: str):
10
+ """
11
+ Bucket-safe atomic write. Writes to a temp file in the SAME directory,
12
+ then renames over the target. Within one directory on a FUSE-mounted
13
+ bucket, rename is atomic. Direct open('w') is NOT safe — a crash
14
+ mid-write silently zeroes the file on object storage.
15
+ """
16
+ dirpath = os.path.dirname(os.path.abspath(filepath))
17
+ os.makedirs(dirpath, exist_ok=True)
18
+ fd, tmp_path = tempfile.mkstemp(prefix=".tmp_sb_", dir=dirpath)
19
+ try:
20
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
21
+ f.write(content)
22
+ f.flush()
23
+ os.replace(tmp_path, filepath)
24
+ except Exception:
25
+ try:
26
+ os.remove(tmp_path)
27
+ except FileNotFoundError:
28
+ pass
29
+ raise
30
+
31
  # Tags that indicate procedural/how-to content worth extracting separately
32
  PROCEDURAL_TAGS = {
33
  "algorithm", "method", "formula", "process", "technique",
 
172
  condensed = json.loads(cleaned)
173
 
174
  if isinstance(condensed, list) and len(condensed) > 0:
175
+ # Build condensed legend content
176
+ now_iso = datetime.datetime.now().isoformat()
177
+ legend_lines = []
178
+ for item in condensed:
179
+ item["domain"] = self.domain_name
180
+ item["timestamp"] = now_iso
181
+ legend_lines.append(json.dumps(item, ensure_ascii=False))
182
+ # Atomic write — safe on bucket/FUSE storage
183
+ _safe_write(self.legend_path, "\n".join(legend_lines) + "\n")
184
 
185
  print(f"[SecondaryBrain] '{self.domain_name}' condensed from {count} → {len(condensed)} entries.", flush=True)
186
 
187
+ # Also update condensed_ontology.txt with a summary (atomic)
188
+ ontology_lines = [f"Domain: {self.domain_name}", f"Condensed at: {now_iso}", ""]
189
  for item in condensed:
190
  ontology_lines.append(f" [{item.get('sqt','')}] {item.get('summary','')}")
191
+ _safe_write(self.ontology_path, "\n".join(ontology_lines))
 
192
 
193
  return True
194
 
 
336
  "concept_count": concept_count,
337
  "last_active": last_active
338
  }
339
+ # Atomic write safe on bucket/FUSE storage
340
+ _safe_write(self.index_path, json.dumps(index, indent=2, ensure_ascii=False))
341
 
342
  def _get_or_create_domain(self, domain_name: str) -> DomainLayer:
343
  """