File size: 10,642 Bytes
3ba1470 437ef8f 3ba1470 437ef8f d74c57a 3ba1470 d74c57a 3ba1470 d74c57a 3ba1470 d74c57a 3ba1470 d74c57a 3ba1470 d74c57a 437ef8f 3ba1470 32fd9a9 3ba1470 32fd9a9 3ba1470 32fd9a9 3ba1470 32fd9a9 3ba1470 32fd9a9 3ba1470 32fd9a9 3ba1470 32fd9a9 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f d74c57a 3ba1470 d74c57a 437ef8f 3ba1470 d74c57a 437ef8f 3ba1470 437ef8f d74c57a 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 d74c57a 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 d74c57a 3ba1470 437ef8f d74c57a 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 d74c57a 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f d74c57a 3ba1470 d74c57a 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f d74c57a 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 437ef8f 3ba1470 d74c57a 3ba1470 437ef8f d74c57a |
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 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
#!/bin/sh
# 添加更详细的日志
log_info() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1"
}
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1"
}
# 检查环境变量
if [ -z "$HF_TOKEN" ] || [ -z "$DATASET_ID" ]; then
log_error "未启用备份功能 - 缺少HF_TOKEN或DATASET_ID环境变量"
log_info "HF_TOKEN=${HF_TOKEN:0:3}... DATASET_ID=${DATASET_ID}"
exit 0
fi
# 创建临时目录
TEMP_DIR="/tmp/sillytavern_backup"
DATA_DIR="/home/node/app/data"
# 确保目录存在并有正确权限
mkdir -p $TEMP_DIR
chmod -R 777 $TEMP_DIR
mkdir -p $DATA_DIR
chmod -R 777 $DATA_DIR
log_info "临时目录: $TEMP_DIR"
log_info "数据目录: $DATA_DIR"
log_info "HF_TOKEN: ${HF_TOKEN:0:5}..."
log_info "DATASET_ID: $DATASET_ID"
# 安装python和huggingface_hub
if ! command -v python3 > /dev/null 2>&1; then
log_info "正在安装Python..."
apk add --no-cache python3 py3-pip
else
log_info "Python3已安装: $(python3 --version)"
fi
# 确保pip已安装
if ! command -v pip3 > /dev/null 2>&1; then
log_info "正在安装pip..."
apk add --no-cache py3-pip
else
log_info "Pip3已安装: $(pip3 --version)"
fi
# 安装或更新huggingface_hub
log_info "正在安装/更新huggingface_hub..."
pip3 install --no-cache-dir --upgrade huggingface_hub
log_info "huggingface_hub安装完成"
# 测试huggingface_hub是否正常工作
if ! python3 -c "import huggingface_hub; print('huggingface_hub版本:', huggingface_hub.__version__)" > /dev/null 2>&1; then
log_error "huggingface_hub导入失败,正在重试安装..."
pip3 install --no-cache-dir huggingface_hub
fi
# 测试权限是否正常
touch "${TEMP_DIR}/test_file" && rm "${TEMP_DIR}/test_file"
if [ $? -ne 0 ]; then
log_error "临时目录权限测试失败,正在修复权限..."
chmod -R 777 $TEMP_DIR
fi
# 测试与HuggingFace API的连接
log_info "正在测试与HuggingFace API的连接..."
python3 -c "
from huggingface_hub import HfApi
try:
api = HfApi(token='$HF_TOKEN')
user_info = api.whoami()
print(f'成功连接到HuggingFace API,用户: {user_info}')
except Exception as e:
print(f'连接HuggingFace API失败: {str(e)}')
exit(1)
"
if [ $? -ne 0 ]; then
log_error "HuggingFace API连接测试失败,请检查令牌是否有效"
else
log_info "HuggingFace API连接测试成功"
fi
# 生成唯一的测试文件名
TEST_FILE_NAME="test_file_$(date +%s)"
# 测试数据集权限
log_info "正在测试Dataset权限..."
python3 -c "
from huggingface_hub import HfApi
try:
api = HfApi(token='$HF_TOKEN')
# 创建本地测试文件
with open('$TEMP_DIR/test_file', 'w') as f:
f.write('test')
# 上传测试文件
test_file_name = '$TEST_FILE_NAME'
print(f'正在上传测试文件: {test_file_name}')
api.upload_file(
path_or_fileobj='$TEMP_DIR/test_file',
path_in_repo=test_file_name,
repo_id='$DATASET_ID',
repo_type='dataset'
)
print('成功上传测试文件到Dataset')
# 删除已上传的测试文件
print('正在删除测试文件...')
api.delete_file(
path_in_repo=test_file_name,
repo_id='$DATASET_ID',
repo_type='dataset'
)
print('已成功删除测试文件')
except Exception as e:
print(f'Dataset权限测试失败: {str(e)}')
exit(1)
"
if [ $? -ne 0 ]; then
log_error "Dataset权限测试失败,请检查DATASET_ID是否正确且有写入权限"
else
log_info "Dataset权限测试成功,测试文件已清理"
fi
# 确保本地测试文件被删除
rm -f "$TEMP_DIR/test_file"
# 上传备份
upload_backup() {
file_path="$1"
file_name="$2"
if [ ! -f "$file_path" ]; then
log_error "备份文件不存在: $file_path"
return 1
fi
log_info "开始上传备份: $file_name ($(du -h $file_path | cut -f1))"
python3 -c "
from huggingface_hub import HfApi
import sys
import os
import time
def manage_backups(api, repo_id, max_files=10):
try:
files = api.list_repo_files(repo_id=repo_id, repo_type='dataset')
backup_files = [f for f in files if f.startswith('sillytavern_backup_') and f.endswith('.tar.gz')]
backup_files.sort()
if len(backup_files) >= max_files:
files_to_delete = backup_files[:(len(backup_files) - max_files + 1)]
for file_to_delete in files_to_delete:
try:
api.delete_file(path_in_repo=file_to_delete, repo_id=repo_id, repo_type='dataset')
print(f'已删除旧备份: {file_to_delete}')
except Exception as e:
print(f'删除 {file_to_delete} 时出错: {str(e)}')
except Exception as e:
print(f'管理备份文件时出错: {str(e)}')
token='$HF_TOKEN'
repo_id='$DATASET_ID'
try:
api = HfApi(token=token)
# 检查文件大小
file_size = os.path.getsize('$file_path')
print(f'备份文件大小: {file_size / (1024*1024):.2f} MB')
# 确认Dataset存在
try:
dataset_info = api.dataset_info(repo_id=repo_id)
print(f'Dataset信息: {dataset_info.id}')
except Exception as e:
print(f'获取Dataset信息失败: {str(e)}')
start_time = time.time()
print(f'开始上传: {start_time}')
# 上传文件
api.upload_file(
path_or_fileobj='$file_path',
path_in_repo='$file_name',
repo_id=repo_id,
repo_type='dataset'
)
end_time = time.time()
print(f'上传完成,耗时: {end_time - start_time:.2f} 秒')
print(f'成功上传 $file_name')
# 管理备份
manage_backups(api, repo_id)
except Exception as e:
print(f'上传文件时出错: {str(e)}')
sys.exit(1)
"
if [ $? -ne 0 ]; then
log_error "备份上传失败"
return 1
else
log_info "备份上传成功"
return 0
fi
}
# 下载最新备份
download_latest_backup() {
log_info "开始下载最新备份..."
python3 -c "
from huggingface_hub import HfApi
import sys
import os
import tarfile
import tempfile
import time
try:
api = HfApi(token='$HF_TOKEN')
print('已创建API实例')
# 列出仓库文件
try:
files = api.list_repo_files(repo_id='$DATASET_ID', repo_type='dataset')
print(f'仓库文件数量: {len(files)}')
except Exception as e:
print(f'列出仓库文件失败: {str(e)}')
sys.exit(1)
backup_files = [f for f in files if f.startswith('sillytavern_backup_') and f.endswith('.tar.gz')]
print(f'找到备份文件数量: {len(backup_files)}')
if not backup_files:
print('未找到备份文件')
sys.exit(0)
# 按名称排序(实际上是按时间戳排序)
latest_backup = sorted(backup_files)[-1]
print(f'最新备份文件: {latest_backup}')
with tempfile.TemporaryDirectory() as temp_dir:
print(f'创建临时目录: {temp_dir}')
start_time = time.time()
print(f'开始下载: {start_time}')
# 下载文件
try:
filepath = api.hf_hub_download(
repo_id='$DATASET_ID',
filename=latest_backup,
repo_type='dataset',
local_dir=temp_dir
)
print(f'文件下载到: {filepath}')
except Exception as e:
print(f'下载文件失败: {str(e)}')
sys.exit(1)
end_time = time.time()
print(f'下载完成,耗时: {end_time - start_time:.2f} 秒')
if filepath and os.path.exists(filepath):
# 确保目标目录存在
os.makedirs('$DATA_DIR', exist_ok=True)
# 检查文件权限
print(f'文件权限: {oct(os.stat(filepath).st_mode)[-3:]}')
# 解压文件
try:
with tarfile.open(filepath, 'r:gz') as tar:
print('开始解压文件...')
tar.extractall('$DATA_DIR')
print('文件解压完成')
except Exception as e:
print(f'解压文件失败: {str(e)}')
sys.exit(1)
print(f'成功从 {latest_backup} 恢复备份')
else:
print('下载的文件路径无效')
sys.exit(1)
except Exception as e:
print(f'下载备份过程中出错: {str(e)}')
sys.exit(1)
"
if [ $? -ne 0 ]; then
log_error "备份下载失败"
return 1
else
log_info "备份下载成功"
return 0
fi
}
# 首次启动时下载最新备份
log_info "正在从HuggingFace下载最新备份..."
download_latest_backup
# 同步函数
sync_data() {
log_info "数据同步服务已启动"
while true; do
log_info "开始同步进程,时间: $(date)"
if [ -d "$DATA_DIR" ]; then
timestamp=$(date +%Y%m%d_%H%M%S)
backup_file="sillytavern_backup_${timestamp}.tar.gz"
backup_path="${TEMP_DIR}/${backup_file}"
log_info "创建备份文件: $backup_path"
# 检查数据目录内容
file_count=$(find "$DATA_DIR" -type f | wc -l)
log_info "数据目录文件数量: $file_count"
if [ "$file_count" -eq 0 ]; then
log_info "数据目录为空,跳过备份"
else
# 压缩数据目录
tar -czf "$backup_path" -C "$DATA_DIR" .
if [ $? -ne 0 ]; then
log_error "创建压缩文件失败"
else
log_info "压缩文件创建成功: $(du -h $backup_path | cut -f1)"
# 上传备份
log_info "正在上传备份到HuggingFace..."
upload_backup "$backup_path" "$backup_file"
# 删除临时备份文件
rm -f "$backup_path"
log_info "已删除临时备份文件"
fi
fi
else
log_error "数据目录不存在: $DATA_DIR"
mkdir -p "$DATA_DIR"
chmod -R 777 "$DATA_DIR"
fi
# 设置同步间隔
SYNC_INTERVAL=${SYNC_INTERVAL:-3600}
log_info "下次同步将在 ${SYNC_INTERVAL} 秒后进行..."
sleep $SYNC_INTERVAL
done
}
# 启动同步进程
sync_data |