Перейти к содержимому

Скачивание весов модели завершилось или упало

Веса современных моделей — это десятки, а то и сотни гигабайт. Скачивание 70B-модели по обычному каналу идёт часами, и всё это время терминал занят прогресс-баром, на который бессмысленно смотреть. Хуже — качалка может тихо отвалиться на 90% (обрыв сети, кончилось место на диске, rate-limit хаба), и вы обнаружите это, только вернувшись. Push на завершение/ошибку освобождает вас.

Паттерн — как «завершение долгой задачи»: оборачиваем команду и шлём результат по её коду возврата.

Замеряем время и итоговый размер, различаем успех и падение по exit-коду:

#!/usr/bin/env bash
# dl_model.sh REPO [DEST]
REPO="$1"
DEST="${2:-./models/$(basename "$REPO")}"
start=$(date +%s)
huggingface-cli download "$REPO" --local-dir "$DEST" --local-dir-use-symlinks False
code=$?
dur=$(( $(date +%s) - start ))
if [[ $code -eq 0 ]]; then
size=$(du -sh "$DEST" | cut -f1)
title="✅ Скачано: $(basename "$REPO")"
msg="Размер: $size, время: $((dur/60)) мин $((dur%60)) с"
prio=5
else
title="❌ Скачивание упало: $(basename "$REPO")"
msg="Exit $code после $((dur/60)) мин. Проверьте сеть/место на диске."
prio=8
fi
curl -fsS "$NOTIFLY_URL/message?token=$NOTIFLY_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg t "$title" --arg m "$msg" --argjson p "$prio" \
'{title:$t, message:$m, priority:$p}')"
exit $code

Успех — priority=5 (нормальный push, «можно продолжать работу»), падение — priority=8 (нужно вмешаться, качать заново). Запуск: ./dl_model.sh meta-llama/Llama-3.1-70B ./weights.

ollama pull тоже возвращает ненулевой код при сбое:

#!/usr/bin/env bash
MODEL="$1"
start=$(date +%s)
ollama pull "$MODEL"
code=$?
dur=$(( $(date +%s) - start ))
if [[ $code -eq 0 ]]; then
size=$(ollama list | awk -v m="$MODEL" '$1==m {print $3, $4}')
msg="Модель $MODEL готова (${size:-размер см. ollama list}) за $((dur/60)) мин"
prio=5; title="✅ ollama pull готово"
else
msg="ollama pull $MODEL упал (exit $code) за $((dur/60)) мин"
prio=8; title="❌ ollama pull упал"
fi
curl -fsS "$NOTIFLY_URL/message?token=$NOTIFLY_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg t "$title" --arg m "$msg" --argjson p "$prio" '{title:$t,message:$m,priority:$p}')"

Вариант 3: Python с прогрессом и ETA в промежуточном пуше

Заголовок раздела «Вариант 3: Python с прогрессом и ETA в промежуточном пуше»

Если качаете из Python (huggingface_hub.snapshot_download с колбэком) — можно слать один тихий промежуточный push на середине пути, чтобы понимать, что процесс жив:

import os, time, requests
from huggingface_hub import snapshot_download
def notify(title, msg, prio):
requests.post(f"{os.environ['NOTIFLY_URL']}/message",
params={"token": os.environ["NOTIFLY_TOKEN"]},
json={"title": title, "message": msg, "priority": prio}, timeout=5)
t0 = time.time()
try:
path = snapshot_download(repo_id="meta-llama/Llama-3.1-8B")
size_gb = sum(os.path.getsize(os.path.join(dp, f))
for dp, _, fs in os.walk(path) for f in fs) / 1e9
notify("✅ Веса скачаны",
f"{size_gb:.1f} ГБ за {int(time.time()-t0)//60} мин\n{path}", prio=5)
except Exception as e:
notify("❌ Скачивание упало", f"{type(e).__name__}: {e}", prio=8)
raise

Для очень долгих закачек добавьте heartbeat в колбэк прогресса — тогда зависшая на 60% качалка (не упавшая, а именно замершая) тоже даст о себе знать по таймауту.

  • repo/имя модели и путь назначения;
  • итоговый размер и общее время (для успеха);
  • exit-код и причину, если известна: сеть / диск / rate-limit (для падения);
  • сколько места осталось на диске — частая причина падения на 90%.