hxger commited on
Commit
3ba1470
·
verified ·
1 Parent(s): d74c57a

Upload 4 files

Browse files
Files changed (2) hide show
  1. Dockerfile +8 -5
  2. sync_data.sh +260 -53
Dockerfile CHANGED
@@ -4,7 +4,7 @@ FROM node:19.1.0-alpine3.16
4
  ARG APP_HOME=/home/node/app
5
 
6
  # 安装系统依赖
7
- RUN apk add gcompat tini git python3 py3-pip
8
 
9
  # 安装HuggingFace Hub
10
  RUN pip3 install --no-cache-dir huggingface_hub
@@ -31,7 +31,8 @@ RUN echo "*** 安装npm包 ***" && \
31
 
32
  # 添加启动脚本和数据同步脚本
33
  COPY launch.sh sync_data.sh ./
34
- RUN chmod +x launch.sh sync_data.sh
 
35
 
36
  # 安装生产依赖
37
  RUN echo "*** 安装生产npm包 ***" && \
@@ -54,11 +55,13 @@ RUN echo "*** 清理 ***" && \
54
  # 修改入口脚本,添加自定义启动脚本
55
  RUN sed -i 's/# Start the server/.\/launch.sh/g' docker-entrypoint.sh
56
 
57
- # 创建临时备份目录
58
- RUN mkdir -p /tmp/sillytavern_backup
 
59
 
60
  # 设置权限
61
- RUN chmod -R 777 ${APP_HOME}
 
62
 
63
  # 暴露端口
64
  EXPOSE 8000
 
4
  ARG APP_HOME=/home/node/app
5
 
6
  # 安装系统依赖
7
+ RUN apk add --no-cache gcompat tini git python3 py3-pip bash dos2unix findutils tar curl
8
 
9
  # 安装HuggingFace Hub
10
  RUN pip3 install --no-cache-dir huggingface_hub
 
31
 
32
  # 添加启动脚本和数据同步脚本
33
  COPY launch.sh sync_data.sh ./
34
+ RUN chmod +x launch.sh sync_data.sh && \
35
+ dos2unix launch.sh sync_data.sh
36
 
37
  # 安装生产依赖
38
  RUN echo "*** 安装生产npm包 ***" && \
 
55
  # 修改入口脚本,添加自定义启动脚本
56
  RUN sed -i 's/# Start the server/.\/launch.sh/g' docker-entrypoint.sh
57
 
58
+ # 创建临时备份目录和数据目录
59
+ RUN mkdir -p /tmp/sillytavern_backup && \
60
+ mkdir -p ${APP_HOME}/data
61
 
62
  # 设置权限
63
+ RUN chmod -R 777 ${APP_HOME} && \
64
+ chmod -R 777 /tmp/sillytavern_backup
65
 
66
  # 暴露端口
67
  EXPOSE 8000
sync_data.sh CHANGED
@@ -1,128 +1,335 @@
1
- #!/bin/bash
 
 
 
 
 
 
 
 
 
2
 
3
  # 检查环境变量
4
- if [[ -z "$HF_TOKEN" ]] || [[ -z "$DATASET_ID" ]]; then
5
- echo "未启用备份功能 - 缺少HF_TOKEN或DATASET_ID环境变量"
 
6
  exit 0
7
  fi
8
 
9
  # 创建临时目录
10
  TEMP_DIR="/tmp/sillytavern_backup"
 
 
 
11
  mkdir -p $TEMP_DIR
 
 
 
 
 
 
 
 
12
 
13
  # 安装python和huggingface_hub
14
- if ! command -v python3 &> /dev/null; then
15
- echo "正在安装Python..."
16
  apk add --no-cache python3 py3-pip
 
 
 
 
 
 
 
 
 
 
17
  fi
18
 
19
- if ! python3 -c "import huggingface_hub" &> /dev/null; then
20
- echo "正在安装huggingface_hub..."
 
 
 
 
 
 
21
  pip3 install --no-cache-dir huggingface_hub
22
  fi
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  # 上传备份
25
  upload_backup() {
 
 
 
 
 
 
 
 
 
 
 
 
26
  import sys
27
  import os
 
 
28
  def manage_backups(api, repo_id, max_files=10):
29
- files = api.list_repo_files(repo_id=repo_id, repo_type='dataset')
30
- backup_files = [f for f in files if f.startswith('sillytavern_backup_') and f.endswith('.tar.gz')]
31
- backup_files.sort()
32
-
33
- if len(backup_files) >= max_files:
34
- files_to_delete = backup_files[:(len(backup_files) - max_files + 1)]
35
- for file_to_delete in files_to_delete:
36
- try:
37
- api.delete_file(path_in_repo=file_to_delete, repo_id=repo_id, repo_type='dataset')
38
- print(f'已删除旧备份: {file_to_delete}')
39
- except Exception as e:
40
- print(f'删除 {file_to_delete} 时出错: {str(e)}')
41
- api = HfApi(token='$token')
 
 
 
 
 
 
42
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  api.upload_file(
44
  path_or_fileobj='$file_path',
45
  path_in_repo='$file_name',
46
- repo_id='$repo_id',
47
  repo_type='dataset'
48
  )
 
 
 
49
  print(f'成功上传 $file_name')
50
 
51
- manage_backups(api, '$repo_id')
 
52
  except Exception as e:
53
  print(f'上传文件时出错: {str(e)}')
 
54
  "
 
 
 
 
 
 
 
55
  }
56
 
 
57
  download_latest_backup() {
58
- token="$HF_TOKEN"
59
- repo_id="$DATASET_ID"
60
- data_dir="/home/node/app/data"
61
 
62
- # 确保数据目录存在
63
- mkdir -p $data_dir
64
-
65
  python3 -c "
66
  from huggingface_hub import HfApi
 
67
  import os
68
  import tarfile
69
  import tempfile
70
- api = HfApi(token='$token')
 
71
  try:
72
- files = api.list_repo_files(repo_id='$repo_id', repo_type='dataset')
 
 
 
 
 
 
 
 
 
 
73
  backup_files = [f for f in files if f.startswith('sillytavern_backup_') and f.endswith('.tar.gz')]
 
74
 
75
  if not backup_files:
76
  print('未找到备份文件')
77
- sys.exit()
78
-
 
79
  latest_backup = sorted(backup_files)[-1]
 
80
 
81
  with tempfile.TemporaryDirectory() as temp_dir:
82
- filepath = api.hf_hub_download(
83
- repo_id='$repo_id',
84
- filename=latest_backup,
85
- repo_type='dataset',
86
- local_dir=temp_dir
87
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  if filepath and os.path.exists(filepath):
90
- with tarfile.open(filepath, 'r:gz') as tar:
91
- tar.extractall('$data_dir')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  print(f'成功从 {latest_backup} 恢复备份')
93
-
 
 
94
  except Exception as e:
95
- print(f'下载备份时出错: {str(e)}')
 
96
  "
 
 
 
 
 
 
 
97
  }
98
 
99
  # 首次启动时下载最新备份
100
- echo "正在从HuggingFace下载最新备份..."
101
  download_latest_backup
102
 
103
  # 同步函数
104
  sync_data() {
 
 
105
  while true; do
106
- echo "开始同步进程,时间: $(date)"
107
 
108
- data_dir="/home/node/app/data"
109
- if [ -d "$data_dir" ]; then
110
  timestamp=$(date +%Y%m%d_%H%M%S)
111
  backup_file="sillytavern_backup_${timestamp}.tar.gz"
 
112
 
113
- # 压缩数据目录
114
- tar -czf "${TEMP_DIR}/${backup_file}" -C "$data_dir" .
115
 
116
- echo "正在上传备份到HuggingFace..."
117
- upload_backup "${TEMP_DIR}/${backup_file}" "${backup_file}"
 
118
 
119
- rm -f "${TEMP_DIR}/${backup_file}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  else
121
- echo "数据目录尚不存在,等待下次同步..."
 
 
122
  fi
123
 
 
124
  SYNC_INTERVAL=${SYNC_INTERVAL:-3600}
125
- echo "下次同步将在 ${SYNC_INTERVAL} 秒后进行..."
126
  sleep $SYNC_INTERVAL
127
  done
128
  }
 
1
+ #!/bin/sh
2
+
3
+ # 添加更详细的日志
4
+ log_info() {
5
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1"
6
+ }
7
+
8
+ log_error() {
9
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1"
10
+ }
11
 
12
  # 检查环境变量
13
+ if [ -z "$HF_TOKEN" ] || [ -z "$DATASET_ID" ]; then
14
+ log_error "未启用备份功能 - 缺少HF_TOKEN或DATASET_ID环境变量"
15
+ log_info "HF_TOKEN=${HF_TOKEN:0:3}... DATASET_ID=${DATASET_ID}"
16
  exit 0
17
  fi
18
 
19
  # 创建临时目录
20
  TEMP_DIR="/tmp/sillytavern_backup"
21
+ DATA_DIR="/home/node/app/data"
22
+
23
+ # 确保目录存在并有正确权限
24
  mkdir -p $TEMP_DIR
25
+ chmod -R 777 $TEMP_DIR
26
+ mkdir -p $DATA_DIR
27
+ chmod -R 777 $DATA_DIR
28
+
29
+ log_info "临时目录: $TEMP_DIR"
30
+ log_info "数据目录: $DATA_DIR"
31
+ log_info "HF_TOKEN: ${HF_TOKEN:0:5}..."
32
+ log_info "DATASET_ID: $DATASET_ID"
33
 
34
  # 安装python和huggingface_hub
35
+ if ! command -v python3 > /dev/null 2>&1; then
36
+ log_info "正在安装Python..."
37
  apk add --no-cache python3 py3-pip
38
+ else
39
+ log_info "Python3已安装: $(python3 --version)"
40
+ fi
41
+
42
+ # 确保pip已安装
43
+ if ! command -v pip3 > /dev/null 2>&1; then
44
+ log_info "正在安装pip..."
45
+ apk add --no-cache py3-pip
46
+ else
47
+ log_info "Pip3已安装: $(pip3 --version)"
48
  fi
49
 
50
+ # 安装或更新huggingface_hub
51
+ log_info "正在安装/更新huggingface_hub..."
52
+ pip3 install --no-cache-dir --upgrade huggingface_hub
53
+ log_info "huggingface_hub安装完成"
54
+
55
+ # 测试huggingface_hub是否正常工作
56
+ if ! python3 -c "import huggingface_hub; print('huggingface_hub版本:', huggingface_hub.__version__)" > /dev/null 2>&1; then
57
+ log_error "huggingface_hub导入失败,正在重试安装..."
58
  pip3 install --no-cache-dir huggingface_hub
59
  fi
60
 
61
+ # 测试权限是否正常
62
+ touch "${TEMP_DIR}/test_file" && rm "${TEMP_DIR}/test_file"
63
+ if [ $? -ne 0 ]; then
64
+ log_error "临时目录权限测试失败,正在修复权限..."
65
+ chmod -R 777 $TEMP_DIR
66
+ fi
67
+
68
+ # 测试与HuggingFace API的连接
69
+ log_info "正在测试与HuggingFace API的连接..."
70
+ python3 -c "
71
+ from huggingface_hub import HfApi
72
+ try:
73
+ api = HfApi(token='$HF_TOKEN')
74
+ user_info = api.whoami()
75
+ print(f'成功连接到HuggingFace API,用户: {user_info}')
76
+ except Exception as e:
77
+ print(f'连接HuggingFace API失败: {str(e)}')
78
+ exit(1)
79
+ "
80
+ if [ $? -ne 0 ]; then
81
+ log_error "HuggingFace API连接测试失败,请检查令牌是否有效"
82
+ else
83
+ log_info "HuggingFace API连接测试成功"
84
+ fi
85
+
86
+ # 测试数据集权限
87
+ log_info "正在测试Dataset权限..."
88
+ python3 -c "
89
+ from huggingface_hub import HfApi
90
+ try:
91
+ api = HfApi(token='$HF_TOKEN')
92
+ # 尝试创建一个测试文件
93
+ api.upload_file(
94
+ path_or_fileobj='$TEMP_DIR/test_file' if not open('$TEMP_DIR/test_file', 'w').write('test') else '$TEMP_DIR/test_file',
95
+ path_in_repo='test_file_' + '$(date +%s)',
96
+ repo_id='$DATASET_ID',
97
+ repo_type='dataset'
98
+ )
99
+ print('成功上传测试文件到Dataset')
100
+ except Exception as e:
101
+ print(f'上传测试文件到Dataset失败: {str(e)}')
102
+ exit(1)
103
+ "
104
+ if [ $? -ne 0 ]; then
105
+ log_error "Dataset权限测试失败,请检查DATASET_ID是否正确且有写入权限"
106
+ else
107
+ log_info "Dataset权限测试成功"
108
+ fi
109
+
110
  # 上传备份
111
  upload_backup() {
112
+ file_path="$1"
113
+ file_name="$2"
114
+
115
+ if [ ! -f "$file_path" ]; then
116
+ log_error "备份文件不存在: $file_path"
117
+ return 1
118
+ fi
119
+
120
+ log_info "开始上传备份: $file_name ($(du -h $file_path | cut -f1))"
121
+
122
+ python3 -c "
123
+ from huggingface_hub import HfApi
124
  import sys
125
  import os
126
+ import time
127
+
128
  def manage_backups(api, repo_id, max_files=10):
129
+ try:
130
+ files = api.list_repo_files(repo_id=repo_id, repo_type='dataset')
131
+ backup_files = [f for f in files if f.startswith('sillytavern_backup_') and f.endswith('.tar.gz')]
132
+ backup_files.sort()
133
+
134
+ if len(backup_files) >= max_files:
135
+ files_to_delete = backup_files[:(len(backup_files) - max_files + 1)]
136
+ for file_to_delete in files_to_delete:
137
+ try:
138
+ api.delete_file(path_in_repo=file_to_delete, repo_id=repo_id, repo_type='dataset')
139
+ print(f'已删除旧备份: {file_to_delete}')
140
+ except Exception as e:
141
+ print(f'删除 {file_to_delete} 时出错: {str(e)}')
142
+ except Exception as e:
143
+ print(f'管理备份文件时出错: {str(e)}')
144
+
145
+ token='$HF_TOKEN'
146
+ repo_id='$DATASET_ID'
147
+
148
  try:
149
+ api = HfApi(token=token)
150
+
151
+ # 检查文件大小
152
+ file_size = os.path.getsize('$file_path')
153
+ print(f'备份文件大小: {file_size / (1024*1024):.2f} MB')
154
+
155
+ # 确认Dataset存在
156
+ try:
157
+ dataset_info = api.dataset_info(repo_id=repo_id)
158
+ print(f'Dataset信息: {dataset_info.id}')
159
+ except Exception as e:
160
+ print(f'获取Dataset信息失败: {str(e)}')
161
+
162
+ start_time = time.time()
163
+ print(f'开始上传: {start_time}')
164
+
165
+ # 上传文件
166
  api.upload_file(
167
  path_or_fileobj='$file_path',
168
  path_in_repo='$file_name',
169
+ repo_id=repo_id,
170
  repo_type='dataset'
171
  )
172
+
173
+ end_time = time.time()
174
+ print(f'上传完成,耗时: {end_time - start_time:.2f} 秒')
175
  print(f'成功上传 $file_name')
176
 
177
+ # 管理备份
178
+ manage_backups(api, repo_id)
179
  except Exception as e:
180
  print(f'上传文件时出错: {str(e)}')
181
+ sys.exit(1)
182
  "
183
+ if [ $? -ne 0 ]; then
184
+ log_error "备份上传失败"
185
+ return 1
186
+ else
187
+ log_info "备份上传成功"
188
+ return 0
189
+ fi
190
  }
191
 
192
+ # 下载最新备份
193
  download_latest_backup() {
194
+ log_info "开始下载最新备份..."
 
 
195
 
 
 
 
196
  python3 -c "
197
  from huggingface_hub import HfApi
198
+ import sys
199
  import os
200
  import tarfile
201
  import tempfile
202
+ import time
203
+
204
  try:
205
+ api = HfApi(token='$HF_TOKEN')
206
+ print('已创建API实例')
207
+
208
+ # 列出仓库文件
209
+ try:
210
+ files = api.list_repo_files(repo_id='$DATASET_ID', repo_type='dataset')
211
+ print(f'仓库文件数量: {len(files)}')
212
+ except Exception as e:
213
+ print(f'列出仓库文件失败: {str(e)}')
214
+ sys.exit(1)
215
+
216
  backup_files = [f for f in files if f.startswith('sillytavern_backup_') and f.endswith('.tar.gz')]
217
+ print(f'找到备份文件数量: {len(backup_files)}')
218
 
219
  if not backup_files:
220
  print('未找到备份文件')
221
+ sys.exit(0)
222
+
223
+ # 按名称排序(实际上是按时间戳排序)
224
  latest_backup = sorted(backup_files)[-1]
225
+ print(f'最新备份文件: {latest_backup}')
226
 
227
  with tempfile.TemporaryDirectory() as temp_dir:
228
+ print(f'创建临时目录: {temp_dir}')
229
+
230
+ start_time = time.time()
231
+ print(f'开始下载: {start_time}')
232
+
233
+ # 下载文件
234
+ try:
235
+ filepath = api.hf_hub_download(
236
+ repo_id='$DATASET_ID',
237
+ filename=latest_backup,
238
+ repo_type='dataset',
239
+ local_dir=temp_dir
240
+ )
241
+ print(f'文件下载到: {filepath}')
242
+ except Exception as e:
243
+ print(f'下载文件失败: {str(e)}')
244
+ sys.exit(1)
245
+
246
+ end_time = time.time()
247
+ print(f'下载完成,耗时: {end_time - start_time:.2f} 秒')
248
 
249
  if filepath and os.path.exists(filepath):
250
+ # 确保目标目录存在
251
+ os.makedirs('$DATA_DIR', exist_ok=True)
252
+
253
+ # 检查文件权限
254
+ print(f'文件权限: {oct(os.stat(filepath).st_mode)[-3:]}')
255
+
256
+ # 解压文件
257
+ try:
258
+ with tarfile.open(filepath, 'r:gz') as tar:
259
+ print('开始解压文件...')
260
+ tar.extractall('$DATA_DIR')
261
+ print('文件解压完成')
262
+ except Exception as e:
263
+ print(f'解压文件失败: {str(e)}')
264
+ sys.exit(1)
265
+
266
  print(f'成功从 {latest_backup} 恢复备份')
267
+ else:
268
+ print('下载的文件路径无效')
269
+ sys.exit(1)
270
  except Exception as e:
271
+ print(f'下载备份过程中出错: {str(e)}')
272
+ sys.exit(1)
273
  "
274
+ if [ $? -ne 0 ]; then
275
+ log_error "备份下载失败"
276
+ return 1
277
+ else
278
+ log_info "备份下载成功"
279
+ return 0
280
+ fi
281
  }
282
 
283
  # 首次启动时下载最新备份
284
+ log_info "正在从HuggingFace下载最新备份..."
285
  download_latest_backup
286
 
287
  # 同步函数
288
  sync_data() {
289
+ log_info "数据同步服务已启动"
290
+
291
  while true; do
292
+ log_info "开始同步进程,时间: $(date)"
293
 
294
+ if [ -d "$DATA_DIR" ]; then
 
295
  timestamp=$(date +%Y%m%d_%H%M%S)
296
  backup_file="sillytavern_backup_${timestamp}.tar.gz"
297
+ backup_path="${TEMP_DIR}/${backup_file}"
298
 
299
+ log_info "创建备份文件: $backup_path"
 
300
 
301
+ # 检查数据目录内容
302
+ file_count=$(find "$DATA_DIR" -type f | wc -l)
303
+ log_info "数据目录文件数量: $file_count"
304
 
305
+ if [ "$file_count" -eq 0 ]; then
306
+ log_info "数据目录为空,跳过备份"
307
+ else
308
+ # 压缩数据目录
309
+ tar -czf "$backup_path" -C "$DATA_DIR" .
310
+ if [ $? -ne 0 ]; then
311
+ log_error "创建压缩文件失败"
312
+ else
313
+ log_info "压缩文件创建成功: $(du -h $backup_path | cut -f1)"
314
+
315
+ # 上传备份
316
+ log_info "正在上传备份到HuggingFace..."
317
+ upload_backup "$backup_path" "$backup_file"
318
+
319
+ # 删除临时备份文件
320
+ rm -f "$backup_path"
321
+ log_info "已删除临时备份文件"
322
+ fi
323
+ fi
324
  else
325
+ log_error "数据目录不存在: $DATA_DIR"
326
+ mkdir -p "$DATA_DIR"
327
+ chmod -R 777 "$DATA_DIR"
328
  fi
329
 
330
+ # 设置同步间隔
331
  SYNC_INTERVAL=${SYNC_INTERVAL:-3600}
332
+ log_info "下次同步将在 ${SYNC_INTERVAL} 秒后进行..."
333
  sleep $SYNC_INTERVAL
334
  done
335
  }