Файлы и изображения
Пользовательские файлы хранятся на диске, а не как BLOB: оригиналы живут в
data/files/, пересоздаваемые миниатюры — в data/cache/thumbnails/, и
каждая запись атомарна.
Оригиналы и кэш
Разделение строгое:
- Оригиналы —
data/files/{avatars,backgrounds,attachments,audio,generated}/. Оригиналы никогда не изменяются и не удаляются обслуживанием кэша. - Кэш —
data/cache/thumbnails/. Миниатюры пересоздаваемы и адресуются по содержимому.
Очистка кэша никогда не удаляет оригиналы. Отсутствующая миниатюра автоматически пересоздаётся из оригинала.
Конвейер импорта изображений
Импорт изображения следует фиксированному конвейеру:
- Проверка размера, MIME-типа и расширения.
- Вычисление хэша содержимого (SHA-256).
- Сохранение оригинала без потерь, адресуемого по содержимому
(
{sha256}{ext}), что дедуплицирует по содержимому. - Генерация миниатюр низкого разрешения для галерей, списков и предпросмотров.
- Сохранение миниатюр в
data/cache/thumbnails/. - Ключ каждой миниатюры — хэш оригинала, целевой размер и версия
алгоритма:
{hash}-{size}-v{algorithmVersion}. - Не пересоздавать миниатюру, чей ключ не изменился.
- Никогда не загружать оригинал там, где достаточно миниатюры.
- Автоматическая пересборка кэша при отсутствующей миниатюре.
- Очистка кэша никогда не затрагивает оригиналы.
Атомарные записи
Каждая запись файла проходит через временный файл с последующим переименованием. Сбой в середине никогда не оставляет частично записанный файл. Это касается оригиналов, миниатюр и скачанных файлов токенизаторов.
Галерея персонажей
Изображения галереи переиспользуют таблицу 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/ сохраняется, поэтому активные каталоги подготовки миграций
никогда не прерываются. Результат сообщает количество и размер удалённых
файлов; повторный запуск безопасен и возвращает нули.