- BrainTools - https://www.braintools.ru -
Запустить нейросеть у себя дома сегодня несложно, но не с первого раза. Нужно найти и поставить Ollama, понять в терминале, какую из сотни моделей брать под свою видеокарту, не ошибиться с тегом, дождаться скачивания на несколько гигабайт, а потом ещё и добыть интерфейс. Родственникам и знакомым, которые просят «поставь мне такой же ИИ, как у тебя», всё это не объяснишь за пять минут. Поэтому я написал программу Local AI: она смотрит на железо, подбирает модель, ставит Ollama и модель одним кликом и открывает обычный чат. Ниже — как она устроена и какие грабли попались по пути.

Один LocalAI.exe (около 42 МБ), ничего ставить заранее не нужно, Python тоже.
Определяет видеокарту, видеопамять, ОЗУ и свободное место на диске, рекомендует модель из каталога на 34 позиции (Qwen3, Gemma 3/3n, Llama 3.1/3.2, Mistral, Phi-4, DeepSeek-R1, Qwen2.5-Coder и -VL, LLaVA, gpt-oss).
Скачивает и ставит Ollama без прав администратора, скачивает модель с прогрессом.
Чат с потоковым ответом, режим «Рассуждать», вложения (текстовые файлы и картинки для моделей, которые их понимают), панель «О модели» и значки возможностей.
Выбор папок для Ollama и моделей, перенос моделей, обновление Ollama и моделей, удаление всего «без следов».
Интерфейс на русском и английском, две темы. Исходники открыты, MIT.
Диалоги не покидают ПК: чат разговаривает с Ollama на 127.0.0.1. Сеть нужна только для скачивания и проверки обновлений.

Выбор стека простой: нужно маленькое окно с интерфейсом и логика [1], которая лезет в систему (реестр, процессы, установщики). Это Python, а интерфейс — обычный HTML/CSS/JS без сборщиков.
main.py поднимает локальный HTTP-сервер на 127.0.0.1 и открывает окно pywebview [2] (WebView2). Если окно не открылось, запасной путь — Edge или Chrome с ключом --app.
server.py — API для интерфейса: состояние, установка, чат, обновления, пути. Запросы защищены токеном сессии (заголовок X-Token) и проверкой Host, чтобы страница из браузера не могла дёргать локальный сервер.
hw.py — определение железа, catalog.py — каталог моделей и рекомендация, engine.py — всё про Ollama (поиск, установка, запуск, скачивание моделей, обновление, удаление).
ui/ — страница, стили и app.js с мини-Markdown, чатами и модальными окнами. Строки интерфейса лежат в i18n.js на двух языках.
Первым делом хотелось спросить у Windows про видеокарту через WMI. На моём ПК он оказался сломан, а на чужих такое тоже бывает, поэтому железо определяется без него:
NVIDIA — nvidia-smi --query-gpu=name,memory.total [3];
остальные видеокарты — ключ реестра класса дисплея (DriverDesc, HardwareInformation.qwMemorySize); у значения бывает отрицательное число из 32-битного переполнения, его надо поправить;
ОЗУ — GlobalMemoryStatusEx через ctypes.
Дискретной считается NVIDIA и AMD с заметным объёмом видеопамяти; встроенная графика равна режиму «только процессор». Свободное место считается по диску папки моделей, а не по диску C:, потому что папку пользователь может перенести.
В каталоге у каждой модели размер в ГиБ (сверен с registry.ollama.ai [4]) и возможности. Модели нужно больше места, чем её файл: контекст и буферы. Грубая оценка и три режима:
OVERHEAD = 1.2 # множитель на контекст и буферы
EXTRA = 0.6 # ГБ запаса
def _need(size):
return size * OVERHEAD + EXTRA
def rate(model, hw):
need = _need(model["size"])
vram, ram = hw["vram_gb"], hw["ram_gb"]
if vram and need <= vram * 0.95:
return "gpu" # целиком в видеопамяти — быстро
if need <= ram * 0.7:
return "mixed" if vram else "cpu"
return "no" # не влезает
Рекомендуется самая крупная из подходящих «основных» моделей (Qwen3 и Gemma 3), которая целиком влезает в видеопамять. Без видеокарты — лёгкая модель, не больше 5 ГБ: плотные модели побольше на процессоре слишком медленные. В окне выбора показываются только те модели, что подходят этому ПК (и по памяти [5], и по диску), так что неподходящую не выберешь случайно. Любое изменение модели идёт через окно подтверждения.

Установщик OllamaSetup.exe весит около 1,6 ГБ, поэтому качать его нужно с докачкой: файл лежит в %TEMP%LocalAI как .part, и после обрыва или отмены загрузка продолжается заголовком Range:
done = os.path.getsize(part) if os.path.exists(part) else 0
headers = dict(UA, **({"Range": f"bytes={done}-"} if done else {}))
resp = urllib.request.urlopen(urllib.request.Request(SETUP_URL, headers=headers), timeout=30)
if resp.status != 206: # сервер Range не поддержал — качаем заново
done = 0
Перед запуском проверяется цифровая подпись: статус Valid и подписант O=Ollama, иначе файл удаляется:
sig = subprocess.run(
["powershell", "-NoProfile", "-Command",
f"$s = Get-AuthenticodeSignature -LiteralPath '{path}'; "
""$($s.Status)|$($s.SignerCertificate.Subject)""],
capture_output=True, text=True, creationflags=NO_WINDOW).stdout.strip()
Установка тихая (/VERYSILENT /NORESTART /SUPPRESSMSGBOXES), с нужной папкой через /DIR="…"; ставится в профиль пользователя, права администратора не нужны. Дальше /api/pull скачивает модель, и прогресс идёт в интерфейс. У /api/pull длинный таймаут чтения: на этапе проверки sha256 Ollama долго молчит.
Окно Ollama поверх нашего. Установщик сам запускает ollama app.exe, и он открывает своё окно прямо поверх нашего. Программа находит это окно и шлёт ему WM_CLOSE: приложение уходит в трей, а движок продолжает работать.
Чёрные консольные окна. ollama serve нужно запускать с одним CREATE_NO_WINDOW и без DETACHED_PROCESS. У процесса без консоли каждый дочерний ollama.exe и llama-server.exe (раннер, он появляется при загрузке модели) открывает свою чёрную консоль. Проверял наблюдателем окон: EnumWindows каждые 10 мс. После правки новых окон, кроме «Local AI», нет.
Быстрая проверка порта. Если Ollama не запущена, обычный connect на 127.0.0.1:11434 на Windows возвращает отказ только через пару секунд из-за повторов SYN. /api/state из-за этого тормозил на 3–5 секунд. Теперь сначала быстрый socket.create_connection с таймаутом 0,3 с, а HTTP-запрос только если порт открыт.
Ollama гасится при выходе. Закрыли окно — модель выгружается из видеопамяти, трей не висит. Из-за этого первый ответ после запуска ждёт загрузки модели в память (у меня около 3 секунд на RTX 3070, у других дольше), и со стороны это выглядит как «ответ появился сразу целиком»: загрузка, потом ответ за секунду. Поэтому до первого токена в пузыре показывается «Загрузка модели в память…», а сервер первой строкой потока отдаёт {"status":"loading"}, если модели нет в /api/ps. При старте программа сама поднимает Ollama.
Перенос моделей. Папка моделей задаётся переменной OLLAMA_MODELS в HKCUEnvironment с рассылкой WM_SETTINGCHANGE. В Ollama 0.40 модели лежат не только в blobs и manifests, а ещё в manifests-v2 и metadata; перенести надо всё, иначе в новой папке модель не видна. На одном диске перенос — rename, на другом — копирование с прогрессом; отмена или ошибка [6] откатывают всё назад.
Удаление, которое стирает сам себя. Для кнопки «Удалить всё…» (модели, Ollama, программа — по галочкам, с двойным подтверждением) пришлось повозиться: деинсталлятор Ollama сам стирает ~/.ollama/models, поэтому папка моделей на время переименовывается, а потом возвращается. Inno-деинсталлятор перезапускает себя из %TEMP% и сразу отдаёт управление, так что ждать приходится исчезновения ollama.exe и записи в реестре. А exe программы удаляет скрытый PowerShell: он ждёт выхода наших процессов (и onefile-загрузчика PyInstaller, и потомка), потом стирает exe, %APPDATA%LocalAI, распакованную _MEI* и в конце себя.
localStorage и порт. Чаты хранятся в localStorage, а он привязан к origin вместе с портом. pywebview по умолчанию открывает окно в приватном режиме и ничего не сохраняет. Поэтому окно запускается с private_mode=False и своей папкой хранилища, а порт сервера постоянный (28765); если он занят, берётся любой свободный, но тогда у этого запуска будут свои чаты.
Анимация и requestAnimationFrame. Во время потока пузырь ответа перерисовывается по таймеру, а не в rAF: в перекрытом или скрытом окне кадры замирают, и ответ «приходил» бы сразу весь. Перерисовка меняет только innerHTML у .bubble, сам элемент сообщения не пересоздаётся, иначе анимация появления «мигала» бы всеми сообщениями.
Завершение процессов. taskkill /IM на моём ПК процессы не находил (тот же сломанный WMI), поэтому процессы завершаются через WinAPI: CreateToolhelp32Snapshot и TerminateProcess, сначала трей, потом сервер.
На RTX 3070 (8 ГБ), 32 ГБ ОЗУ:
реальная установка: Ollama 0.40.13, тихая установка около минуты, qwen3:8b в чате с think и без — поток работает; скорость ответа на gemma3:1b около 236 токенов в секунду (программа показывает её в боковой панели);
перенос моделей туда и обратно на одном диске, закрытие окна pywebview и режима Edge --app гасит Ollama;
удаление проверено в демо-режиме и на копии exe с подменёнными APPDATA и TEMP; настоящий деинсталлятор Ollama и удаление настоящих моделей я не запускал;
не проверено вживую: системный диалог выбора папки и переустановка Ollama в другую папку (только демо), а также реальное обновление Ollama (стоит последняя версия).
Для отладки интерфейса есть демо-режим: LOCALAI_DEMO=1 и python app/dev.py, он имитирует установку и чат без сети.
Только Windows 10 и 11.
Видеокарты: рекомендации рассчитаны на NVIDIA и AMD с заметным объёмом памяти; как именно Ollama использует вашу карту — вопрос к самой Ollama.
Генерации картинок и видео у моделей Ollama нет, поэтому в интерфейсе эти значки всегда серые.
Программа не подписана цифровой подписью: SmartScreen покажет предупреждение («Подробнее» → «Выполнить в любом случае»), а антивирусы иногда ругаются на exe от PyInstaller. Исходники открыты, собрать можно самому.
Исходный код, README на русском и английском и готовый LocalAI.zip [7] — на GitHub: https://github.com/OlegChe77/local-ai [8] (MIT). Сборка: pip install -r requirements.txt, python app/main.py или build.ps [9]1.
Если у вас другая схема подбора моделей или заметили, что Ollama ведёт себя иначе на вашей конфигурации, напишите в комментариях или в Issues, интересно сравнить.
Автор: OlegChe77
Источник [10]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/37946
URLs in this post:
[1] логика: http://www.braintools.ru/article/7640
[2] pywebview: https://pywebview.flowrl.com/
[3] memory.total: http://memory.total
[4] registry.ollama.ai: http://registry.ollama.ai
[5] памяти: http://www.braintools.ru/article/4140
[6] ошибка: http://www.braintools.ru/article/4192
[7] LocalAI.zip: http://LocalAI.zip
[8] https://github.com/OlegChe77/local-ai: https://github.com/OlegChe77/local-ai
[9] build.ps: http://build.ps
[10] Источник: https://habr.com/ru/articles/1102980/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1102980
Нажмите здесь для печати.