Yash030 Claude Opus 4.7 commited on
Commit
e24267e
·
1 Parent(s): c23ccf2

fix: use upload_folder for backup (prevents 429 rate limits) and auto-create second-brain dir

Browse files
Files changed (2) hide show
  1. src/app.py +1 -2
  2. sync.py +46 -39
src/app.py CHANGED
@@ -1312,8 +1312,7 @@ def api_get_second_brain():
1312
  return auth_err
1313
 
1314
  brain_dir = os.getenv("SECOND_BRAIN_DIR", os.path.join(os.path.expanduser("~"), ".agentmemory", "second-brain"))
1315
- if not os.path.exists(brain_dir):
1316
- return jsonify({"error": "Second brain directory not found", "path": brain_dir}), 404
1317
 
1318
  file_param = request.args.get("file")
1319
  if file_param:
 
1312
  return auth_err
1313
 
1314
  brain_dir = os.getenv("SECOND_BRAIN_DIR", os.path.join(os.path.expanduser("~"), ".agentmemory", "second-brain"))
1315
+ os.makedirs(brain_dir, exist_ok=True)
 
1316
 
1317
  file_param = request.args.get("file")
1318
  if file_param:
sync.py CHANGED
@@ -7,8 +7,8 @@ Usage:
7
  """
8
  import os
9
  import sys
10
- import glob
11
  import shutil
 
12
 
13
  try:
14
  from huggingface_hub import HfApi, hf_hub_download, list_repo_files
@@ -17,11 +17,12 @@ except ImportError:
17
  print("[sync] huggingface_hub not installed, skipping sync")
18
  sys.exit(0)
19
 
20
- HF_TOKEN = os.environ.get("HF_TOKEN", "")
21
- REPO_ID = os.environ.get("AGENTMEMORY_DATASET_REPO", "Yash030/agentmemory-python-data")
22
- DATA_DIR = os.path.expanduser("~/.agentmemory")
23
- SKIP_FILES = {".env"} # never upload secrets
24
- ALLOW_HIDDEN = {".hmac"} # hidden files that ARE safe to backup
 
25
 
26
  def get_api():
27
  return HfApi(token=HF_TOKEN)
@@ -49,7 +50,7 @@ def restore():
49
  try:
50
  local_path = os.path.join(DATA_DIR, fname)
51
  os.makedirs(os.path.dirname(local_path), exist_ok=True)
52
- downloaded = hf_hub_download(
53
  repo_id=REPO_ID,
54
  filename=fname,
55
  repo_type="dataset",
@@ -77,40 +78,46 @@ def backup():
77
  print(f"[sync] repo_info error: {e}")
78
  return
79
 
80
- # Collect files to upload
81
- all_files = []
82
- for root, dirs, files in os.walk(DATA_DIR):
83
- # Skip hidden directories, EXCEPT if they are inside the '.dolt' folder
84
- is_inside_dolt = '.dolt' in root.replace('\\', '/').split('/')
85
- if not is_inside_dolt:
86
- dirs[:] = [d for d in dirs if not d.startswith('.') or d == '.dolt']
87
- for f in files:
88
- if f in SKIP_FILES:
89
- continue
90
- if f.startswith('.') and f not in ALLOW_HIDDEN:
91
- continue
92
- full = os.path.join(root, f)
93
- rel = os.path.relpath(full, DATA_DIR)
94
- all_files.append((full, rel))
95
-
96
- if not all_files:
97
- print("[sync] nothing to backup")
98
- return
 
 
 
99
 
100
- for full_path, rel_path in all_files:
101
- try:
102
- api.upload_file(
103
- path_or_fileobj=full_path,
104
- path_in_repo=rel_path.replace('\\', '/'),
105
- repo_id=REPO_ID,
106
- repo_type="dataset",
107
- token=HF_TOKEN,
108
- )
109
- print(f"[sync] backed up {rel_path}")
110
- except Exception as e:
111
- print(f"[sync] backup {rel_path} error: {e}")
112
 
113
- print("[sync] backup complete")
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  if __name__ == "__main__":
116
  cmd = sys.argv[1] if len(sys.argv) > 1 else "backup"
 
7
  """
8
  import os
9
  import sys
 
10
  import shutil
11
+ import tempfile
12
 
13
  try:
14
  from huggingface_hub import HfApi, hf_hub_download, list_repo_files
 
17
  print("[sync] huggingface_hub not installed, skipping sync")
18
  sys.exit(0)
19
 
20
+ HF_TOKEN = os.environ.get("HF_TOKEN", "")
21
+ REPO_ID = os.environ.get("AGENTMEMORY_DATASET_REPO", "Yash030/agentmemory-python-data")
22
+ DATA_DIR = os.path.expanduser("~/.agentmemory")
23
+ SKIP_FILES = {".env"}
24
+ ALLOW_HIDDEN = {".hmac"}
25
+ SKIP_NAMES = {"LOCK"} # held open by Dolt — always skip
26
 
27
  def get_api():
28
  return HfApi(token=HF_TOKEN)
 
50
  try:
51
  local_path = os.path.join(DATA_DIR, fname)
52
  os.makedirs(os.path.dirname(local_path), exist_ok=True)
53
+ hf_hub_download(
54
  repo_id=REPO_ID,
55
  filename=fname,
56
  repo_type="dataset",
 
78
  print(f"[sync] repo_info error: {e}")
79
  return
80
 
81
+ # Stage files into a temp dir then upload in one commit
82
+ staging = tempfile.mkdtemp(prefix="agentmemory_sync_")
83
+ try:
84
+ copied = 0
85
+ for root, dirs, files in os.walk(DATA_DIR):
86
+ is_inside_dolt = ".dolt" in root.replace("\\", "/").split("/")
87
+ if not is_inside_dolt:
88
+ dirs[:] = [d for d in dirs if not d.startswith(".") or d == ".dolt"]
89
+ for f in files:
90
+ if f in SKIP_FILES or f in SKIP_NAMES:
91
+ continue
92
+ if f.startswith(".") and f not in ALLOW_HIDDEN:
93
+ continue
94
+ full = os.path.join(root, f)
95
+ rel = os.path.relpath(full, DATA_DIR).replace("\\", "/")
96
+ dest = os.path.join(staging, rel.replace("/", os.sep))
97
+ os.makedirs(os.path.dirname(dest), exist_ok=True)
98
+ try:
99
+ shutil.copy2(full, dest)
100
+ copied += 1
101
+ except Exception as e:
102
+ print(f"[sync] stage {rel} error: {e}")
103
 
104
+ if copied == 0:
105
+ print("[sync] nothing to backup")
106
+ return
 
 
 
 
 
 
 
 
 
107
 
108
+ print(f"[sync] uploading {copied} files to {REPO_ID}...")
109
+ api.upload_folder(
110
+ folder_path=staging,
111
+ repo_id=REPO_ID,
112
+ repo_type="dataset",
113
+ token=HF_TOKEN,
114
+ commit_message="sync: periodic backup",
115
+ )
116
+ print("[sync] backup complete")
117
+ except Exception as e:
118
+ print(f"[sync] backup error: {e}")
119
+ finally:
120
+ shutil.rmtree(staging, ignore_errors=True)
121
 
122
  if __name__ == "__main__":
123
  cmd = sys.argv[1] if len(sys.argv) > 1 else "backup"