| |
| """ |
| OpenClaw 记忆同步脚本 |
| 将本地记忆文件同步至 Hugging Face Dataset,并从 Dataset 恢复。 |
| """ |
|
|
| import os |
| import sys |
| import time |
| import logging |
| from pathlib import Path |
| from huggingface_hub import HfApi, hf_hub_download, upload_file, list_repo_files |
|
|
| |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
| logger = logging.getLogger(__name__) |
|
|
| class MemorySync: |
| def __init__(self): |
| self.hf_token = os.getenv('HF_TOKEN') |
| |
| self.hf_dataset = os.getenv('HF_MEMORY_DATASET', 'a8926764/openclaw-memory') |
| |
| self.local_memory_dir = Path(os.getenv('OPENCLAW_MEMORY_DIR', '/root/.openclaw/memory')) |
| self.api = HfApi(token=self.hf_token) |
|
|
| def ensure_memory_dir(self): |
| """确保本地记忆目录存在""" |
| self.local_memory_dir.mkdir(parents=True, exist_ok=True) |
| logger.info(f"Memory directory ensured: {self.local_memory_dir}") |
|
|
| def download_memory(self): |
| """从 Dataset 拉取所有记忆文件(.md 文件)""" |
| self.ensure_memory_dir() |
| try: |
| logger.info(f'开始从 Dataset 下载记忆文件: {self.hf_dataset}') |
| files = list_repo_files(repo_id=self.hf_dataset, repo_type="dataset") |
| downloaded_count = 0 |
| for file_name in files: |
| if file_name.endswith('.md'): |
| try: |
| local_path = hf_hub_download( |
| repo_id=self.hf_dataset, |
| filename=file_name, |
| repo_type="dataset", |
| token=self.hf_token, |
| local_dir=self.local_memory_dir |
| ) |
| logger.info(f'已下载记忆文件: {file_name}') |
| downloaded_count += 1 |
| except Exception as e: |
| logger.error(f'下载文件 {file_name} 失败: {e}') |
| continue |
| if downloaded_count == 0: |
| logger.info('Dataset 中未找到记忆文件,将使用新记忆。') |
| else: |
| logger.info(f'记忆文件下载完成,共下载 {downloaded_count} 个文件。') |
| return True |
| except Exception as e: |
| logger.error(f'从 Dataset 拉取记忆失败: {e}') |
| |
| return True |
|
|
| def upload_memory(self): |
| """推送本地所有 .md 记忆文件到 Dataset""" |
| self.ensure_memory_dir() |
| try: |
| logger.info(f'开始推送记忆文件到 Dataset: {self.hf_dataset}') |
| memory_files = list(self.local_memory_dir.glob('*.md')) |
| if not memory_files: |
| logger.warning('本地没有找到 .md 格式的记忆文件,跳过上传。') |
| return False |
|
|
| uploaded_count = 0 |
| for mem_file in memory_files: |
| try: |
| upload_file( |
| path_or_fileobj=str(mem_file), |
| path_in_repo=mem_file.name, |
| repo_id=self.hf_dataset, |
| repo_type="dataset", |
| token=self.hf_token, |
| commit_message=f"自动同步记忆: {mem_file.name} - {time.strftime('%Y-%m-%d %H:%M:%S')}" |
| ) |
| logger.info(f'已上传记忆文件: {mem_file.name}') |
| uploaded_count += 1 |
| except Exception as e: |
| logger.error(f'上传文件 {mem_file.name} 失败: {e}') |
| continue |
|
|
| logger.info(f'记忆文件上传完成,共上传 {uploaded_count} 个文件。') |
| return uploaded_count > 0 |
| except Exception as e: |
| logger.error(f'推送记忆到 Dataset 失败: {e}') |
| return False |
|
|
| def main(): |
| """主函数,处理命令行参数""" |
| if len(sys.argv) != 2 or sys.argv[1] not in ['download', 'upload']: |
| print('用法: python memory_sync.py [download|upload]') |
| sys.exit(1) |
|
|
| sync = MemorySync() |
| mode = sys.argv[1] |
|
|
| if mode == 'download': |
| success = sync.download_memory() |
| sys.exit(0 if success else 1) |
| elif mode == 'upload': |
| success = sync.upload_memory() |
| sys.exit(0 if success else 1) |
|
|
| if __name__ == '__main__': |
| main() |