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

Файлы и изображения

Пользовательские файлы хранятся на диске, а не как BLOB: оригиналы живут в data/files/, пересоздаваемые миниатюры — в data/cache/thumbnails/, и каждая запись атомарна.

Оригиналы и кэш

Разделение строгое:

  • Оригиналыdata/files/{avatars,backgrounds,attachments,audio,generated}/. Оригиналы никогда не изменяются и не удаляются обслуживанием кэша.
  • Кэшdata/cache/thumbnails/. Миниатюры пересоздаваемы и адресуются по содержимому.

Очистка кэша никогда не удаляет оригиналы. Отсутствующая миниатюра автоматически пересоздаётся из оригинала.

Конвейер импорта изображений

Импорт изображения следует фиксированному конвейеру:

  1. Проверка размера, MIME-типа и расширения.
  2. Вычисление хэша содержимого (SHA-256).
  3. Сохранение оригинала без потерь, адресуемого по содержимому ({sha256}{ext}), что дедуплицирует по содержимому.
  4. Генерация миниатюр низкого разрешения для галерей, списков и предпросмотров.
  5. Сохранение миниатюр в data/cache/thumbnails/.
  6. Ключ каждой миниатюры — хэш оригинала, целевой размер и версия алгоритма: {hash}-{size}-v{algorithmVersion}.
  7. Не пересоздавать миниатюру, чей ключ не изменился.
  8. Никогда не загружать оригинал там, где достаточно миниатюры.
  9. Автоматическая пересборка кэша при отсутствующей миниатюре.
  10. Очистка кэша никогда не затрагивает оригиналы.

Атомарные записи

Каждая запись файла проходит через временный файл с последующим переименованием. Сбой в середине никогда не оставляет частично записанный файл. Это касается оригиналов, миниатюр и скачанных файлов токенизаторов.

Галерея персонажей

Изображения галереи переиспользуют таблицу attachments с owner_type = character.gallery. Строки метаданных хранят URL оригинала и его миниатюры; байты остаются в адресуемых по содержимому files/avatars/. Удаление изображения из галереи удаляет запись вложения, а не файл оригинала — действие остаётся обратимым, а дедупликация сохраняется.

Фоны чатов

files/backgrounds/ — источник истины: список строится сканированием каталога, поэтому фоны, импортированные из SillyTavern, появляются без какого-либо шага переноса. Загруженные файлы хранятся адресуемыми по содержимому и никогда не изменяются.

Миниатюры фонов живут в cache/thumbnails/ с ключом по SHA-256 имени файла, а не содержимого, что позволяет получать миниатюры и файлам из SillyTavern с произвольными именами и держит загрузку, список и удаление на одном ключе. Файл, который нельзя декодировать или который превышает 64 МиБ, перечисляется без миниатюры; оригинал остаётся доступным. Удаление фона удаляет и оригинал, и его кэшированную миниатюру.

Импорт карточек персонажей

POST /api/v2/characters/import принимает JSON Character Card V1/V2 и PNG с метаданными chara. Ввод ограничен 25 МиБ и определяется по содержимому. SHA-256 всего исходного файла хранится в ext._st2.importHash, и повторный импорт того же файла возвращает существующую запись. PNG проверяются декодером изображений. Оригинал атомарно записывается в files/avatars/, и генерируется WebP-миниатюра; отсутствующая миниатюра пересобирается из оригинала при следующем чтении.

Обслуживание кэша

Экран диагностики вызывает DELETE /api/v2/diagnostics/cache, который удаляет только файлы в cache/thumbnails/ и их строки cache_metadata. Корень cache/ сохраняется, поэтому активные каталоги подготовки миграций никогда не прерываются. Результат сообщает количество и размер удалённых файлов; повторный запуск безопасен и возвращает нули.