# deepseek-api **DeepSeek, притворяющийся Ollama.** У веб-версии DeepSeek нет API: ни ключа, ни эндпойнта — только вкладка в браузере, куда человек руками пишет вопросы. Эта программа открывает такую вкладку, пишет в неё за вас и отдаёт наружу обычный HTTP — тот самый протокол, на котором говорит [Ollama](https://ollama.com). Смысл: **любая программа, которая уже умеет работать с Ollama, начинает работать с DeepSeek после смены одного адреса.** Ни строчки кода в ней менять не нужно. ``` ваша программа ──HTTP──> deepseek-api ──> браузер ──> chat.deepseek.com (думает, что │ говорит с Ollama) <──────────── ответ ───────────────┘ ``` Платить не нужно — используется ваш обычный аккаунт DeepSeek. Взамен всё медленно (секунды, а не миллисекунды) и работает только пока открыт браузер. Программа самодостаточна: кроме Node и браузера ей ничего не требуется, внешних пакетов нет. --- ## Оглавление 1. [Что понадобится](#что-понадобится) 2. [Установка по шагам](#установка-по-шагам) 3. [Окно с индикатором](#окно-с-индикатором) 4. [Проверка, что всё работает](#проверка-что-всё-работает) 5. [Как подключить свою программу](#как-подключить-свою-программу) 6. [Что умеет и чего не умеет](#что-умеет-и-чего-не-умеет) 7. [Настройка](#настройка) 8. [Если не работает](#если-не-работает) 9. [Безопасность](#безопасность) 10. [Как это устроено внутри](#как-это-устроено-внутри) --- ## Что понадобится | Что | Зачем | Как проверить, что есть | |---|---|---| | **Windows** | скрипт запуска написан под неё | — | | **Node.js 22 или новее** | на нём написана программа | `node --version` → должно быть `v22.…` и выше | | **Браузер на движке Chromium** | Яндекс.Браузер, Chrome, Edge — любой | — | | **Аккаунт DeepSeek** | бесплатный, регистрация на [chat.deepseek.com](https://chat.deepseek.com) | — | Node.js, если его нет, ставится с [nodejs.org](https://nodejs.org) — берите версию LTS, кнопка слева. После установки **закройте и откройте заново** командную строку, иначе `node` в ней не найдётся. --- ## Установка по шагам Всего шагов пять. Делайте по порядку, каждый заканчивается проверкой — не переходите к следующему, пока предыдущий не дал ожидаемого результата. ### Шаг 1. Скачать ```cmd cd C:\#Projects git clone https://git.08h.ru/alex/deepseek-api.git ``` Без git можно скачать ZIP с той же страницы и распаковать. Папка может лежать где угодно. > **Проверка:** в папке есть `server.mjs`, `browser.mjs` и `start.cmd`. ### Шаг 2. Завести отдельный профиль браузера Браузером будет управлять программа, поэтому работать в нём вам не нужно — и не стоит: он будет сам открываться, переключать вкладки и удалять чаты. Заведите под него **отдельный профиль** — это просто пустая папка, браузер сам её заполнит: ```cmd mkdir C:\Browsers\deepseek ``` Имя любое, запомните путь — понадобится на следующем шаге. > **Профиль должен быть свой.** Если в том же профиле работает другая > программа, управляющая чатами DeepSeek, они начнут удалять чаты друг друга: > каждая считает лишним всё, чего нет в её собственном списке. На этом уже > обжигались — см. [OLD_DEEPSHIM.md](OLD_DEEPSHIM.md). ### Шаг 3. Указать путь к браузеру и профилю Откройте `config.json` и поправьте два значения: ```json { "browserExe": "C:\\Program Files\\Yandex\\YandexBrowser\\Application\\browser.exe", "profileDir": "C:\\Browsers\\deepseek" } ``` - **`profileDir`** — папка из шага 2. - **`browserExe`** — путь к браузеру. Типичные: | Браузер | Путь | |---|---| | Яндекс.Браузер | `C:\Program Files\Yandex\YandexBrowser\Application\browser.exe` | | Google Chrome | `C:\Program Files\Google\Chrome\Application\chrome.exe` | | Microsoft Edge | `C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe` | **Обратные слэши в JSON удваиваются** — `C:\\Browsers\\deepseek`, а не `C:\Browsers\deepseek`. С одинарными файл не прочитается. > Чтобы обновление программы не затирало ваши пути, их можно положить > не в `config.json`, а в `config.local.json` рядом — он перебивает основной > и в репозиторий не попадает. > **Проверка:** перетащите `config.json` в окно браузера. Показалась > структура — JSON верный. Ошибка — ищите пропущенную запятую или одинарный > слэш. ### Шаг 4. Запустить ```cmd start.cmd ``` > **Проверка:** в окне появилось > ``` > DeepSeek прикидывается Ollama: http://localhost:11500 > Модели: deepseek:think, deepseek:search, deepseek:vision > ``` Это окно должно оставаться открытым — пока оно живо, работает и сервис. Останов — `Ctrl+C` или просто закрыть окно. Чёрная консоль не обязательна: рядом лежит окно с индикатором в трее — см. [Окно с индикатором](#окно-с-индикатором). ### Шаг 5. Войти в DeepSeek Браузер поднимается сам, но в пустом профиле вы ещё не залогинены. Дайте сервису первый запрос — он откроет окно: ```cmd curl http://localhost:11500/api/tags ``` Первый вызов ответит `503` и поднимет браузер. **Войдите в аккаунт DeepSeek в открывшемся окне.** Логин сохранится в профиле — больше делать это не придётся. **Окно браузера не сворачивайте и не закрывайте.** Свёрнутое окно Windows не отрисовывает, и программа не сможет прочитать ответ. Достаточно перевести его на другой рабочий стол или оставить позади других окон. > **Проверка:** повторите `curl http://localhost:11500/api/tags` — теперь > должен прийти список из трёх «моделей». **Готово.** Чаты под каждый режим программа заведёт сама при первом же вопросе — создавать их руками не нужно. --- ## Окно с индикатором Тем, кому чёрная консоль мешает, есть маленькое окно: тот же вывод, но сворачивается в трей, а цвет значка показывает состояние сервиса. ```cmd build.cmd deepseek-api.exe ``` `build.cmd` собирает `deepseek-api.exe` (около 20 КБ) компилятором C# из состава Windows — `csc.exe`, он есть на любой машине с .NET Framework 4. Значок берётся из `icon.ico` и вшивается в exe, так что рядом с ним ничего лежать не обязано. Ставить ничего не нужно, прав администратора тоже. Сам `.exe` в репозиторий не кладётся: собирается за секунду. Окно запускает `node server.mjs` дочерним процессом и показывает его вывод. Крестик прячет окно в трей, выход — из меню значка. Node уходит вместе с окном в любом случае, даже если окно снять диспетчером задач; браузер переживает — он отдельный процесс и нужен вам. Цвет значка: | Цвет | Что значит | |---|---| | зелёный | готов, вопросы принимаются | | синий | идёт запрос: в подсказке — сколько секунд и длина очереди | | жёлтый | браузер есть, а вкладки с чатом нет; или сервер не отвечает | | красный | браузер не отвечает; текст беды — в подсказке и всплывающей записке | | серый | node не запущен или снимок состояния устарел (сторож молчит) | Второй запуск не поднимает второй сервер, а разворачивает уже открытое окно — заодно не будет `EADDRINUSE`. `start.cmd` никуда не делся: он для запуска без графики. --- ## Проверка, что всё работает Откройте **вторую** командную строку (первая занята сервисом): ```cmd curl http://localhost:11500/api/chat -d "{\"model\":\"deepseek:think\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":\"Ответь одним словом: столица Японии?\"}]}" ``` Через несколько секунд: ```json {"model":"deepseek:think","created_at":"…","message":{"role":"assistant","content":"Токио"},"done":true,"done_reason":"stop"} ``` В окне сервиса при этом видно, что происходило: ``` [think] 37 симв. чат think не найден, создаю сразу с вопросом открыт новый чат создан новый чат think: 660347d5-… [think] ответ 5 симв. за 9 с ``` Отдельная диагностика — что сейчас видно во вкладке: ```cmd curl http://localhost:11500/api/probe ``` Покажет адрес вкладки, найдено ли поле ввода, идёт ли генерация, список чатов и не просит ли сайт залогиниться. --- ## Как подключить свою программу Везде, где программа спрашивает **адрес Ollama**, укажите: ``` http://localhost:11500 ``` Моделью выберите `deepseek:think`. Если программа работает на **другом компьютере** в вашей сети — вместо `localhost` укажите адрес этого компьютера, например `http://192.168.0.10:11500`. Сервис слушает все адреса, ничего дополнительно настраивать не нужно. ### Три «модели» — это три режима | Модель | Что это | Когда брать | |---|---|---| | `deepseek:think` | обычный режим (expert) | почти всегда | | `deepseek:search` | с поиском в интернете | нужны свежие данные | | `deepseek:vision` | со зрением | разбор картинок | Картинку можно приложить к запросу так же, как это делает Ollama — в поле `images` массивом base64. Тогда режим `vision` включится сам, независимо от того, какую модель вы указали. **Незнакомое имя модели — не ошибка.** Если программа настойчиво шлёт свою `llama3` или `qwen3:8b`, запрос уйдёт в обычный чат. Это сделано нарочно: чужую программу можно переключить на DeepSeek, не разыскивая в её настройках поле с моделью. ### Пример: помощник hlamingo В [hlamingo](https://git.08h.ru/alex/hlamingo) на вкладке **⚙** есть выбор «Кто думает» — переключите на «DeepSeek», укажите адрес, сохраните. --- ## Что умеет и чего не умеет ### Эндпойнты | Адрес | Что делает | |---|---| | `GET /api/tags` | список «моделей». **Отвечает 503, пока браузер не поднят** — по этому клиенты понимают, что сервис не готов | | `GET /api/version` | опознавательная строка | | `GET /api/probe` | сверх протокола Ollama: что видно во вкладке прямо сейчас | | `POST /api/chat` | сообщения → ответ | | `POST /api/generate` | то же, но вопрос одной строкой | | `POST /api/embeddings` | **501** — веб-чат векторов не отдаёт | ### Чего нет и не будет - **Настоящего потока.** Ollama печатает ответ по словам; здесь он приходит целиком. Формат потока при этом соблюдается (клиент получит две строки JSON вместо многих), поэтому программы, которые ждут поток, не ломаются — просто ответ появляется разом. Хотите один объект вместо потока — присылайте `"stream": false`. - **`temperature`, `num_predict` и прочих настроек генерации.** Веб-чат их не принимает. Присланные — молча игнорируются. - **Эмбеддингов** (векторов для поиска по смыслу). Веб-чат их не считает. Вместо пустого вектора возвращается честная ошибка 501: молчаливая подделка испортила бы поиск так, что вы бы этого не заметили. Если вашей программе нужен и чат, и поиск по смыслу — оставьте поиск на настоящей Ollama. - **Параллельных запросов.** Вкладка одна, и два запроса разом затрут друг другу поле ввода. Запросы встают в очередь и идут по одному. ### Сколько ждать Порядок величин, замерено на коротких вопросах: | | Ollama (qwen3:8b, локально) | DeepSeek (веб) | |---|---|---| | короткий вопрос | 2–3 с | 7–12 с | | запрос, на котором меняется чат | — | ~16 с | | первый запрос после запуска браузера | — | +15 с на подъём окна | Если ваша программа считает, что модель обязана ответить за пару секунд, — увеличьте в ней таймаут. --- ## Настройка ### `config.json` | Ключ | По умолчанию | Смысл | |---|---|---| | `port` | `11500` | порт, на котором сервис слушает | | `host` | `0.0.0.0` | какие адреса слушать; `127.0.0.1` — только этот компьютер | | `cdpPort` | `9333` | порт, по которому программа управляет браузером | | `browserExe` | Яндекс.Браузер | путь к браузеру | | `profileDir` | `C:\Browsers\deepseek` | папка профиля браузера | | `chatUrl` | `https://chat.deepseek.com/` | что открывать во вкладке | | `defaultRole` | `think` | режим для незнакомых имён моделей | | `timeout` | `300` | сколько секунд ждать **бездействия** страницы | Про `timeout`: это не «сколько ждать ответа». Пока DeepSeek печатает, ждём сколько угодно; срок отсчитывается от последнего признака жизни страницы. `config.local.json` рядом перебивает `config.json` и в репозиторий не попадает — туда удобно класть пути конкретной машины. ### Переменные окружения Перебивают файлы, удобны для разовых запусков: ```cmd set DEEPSEEK_API_PORT=11501 set DEEPSEEK_CDP_PORT=9444 start.cmd ``` ### `chats.json` Заводится сам, руками его трогать не нужно — см. [Чаты изнашиваются](#чаты-изнашиваются-и-меняются-сами). --- ## Если не работает Сначала посмотрите в окно сервиса — там пишется, что происходит. | Что видно | В чём дело | Что делать | |---|---|---| | `Браузер с отладочным портом 9333 не отвечает` в ответе на `/api/tags` | браузер закрыт | Ничего: он поднимется сам при первом запросе к `/api/chat`. Если не поднялся — следующая строка | | `Браузер так и не открыл отладочный порт` | этот профиль уже открыт **без** порта управления: новый процесс отдаёт ссылку старому окну и молча завершается | Закройте **все** окна браузера с этим профилем и повторите. Проверить, что не осталось: диспетчер задач | | `Браузер не найден: …` | неверный `browserExe` | Проверьте путь и удвоенные слэши | | `не задан browserExe или profileDir` | шаг 3 пропущен | Заполните оба ключа | | `Вкладка chat.deepseek.com не открыта` | вкладку закрыли руками | Сервис откроет её сам на следующем запросе; если нет — откройте `chat.deepseek.com` в том же окне | | Ответ приходит **обрезанным**, без кода | окно браузера свёрнуто — Windows перестаёт его отрисовывать, а DeepSeek дорисовывает блоки кода лениво | Разверните окно. Не сворачивайте: уводите на другой рабочий стол или за другие окна | | Ответ приходит **чужой**, не на ваш вопрос | вкладка не успела обновиться | Повторите запрос. Если повторяется — перезапустите браузер | | В логе `правки в этом чате кончились, завожу новый` | исчерпан лимит в шесть правок одного сообщения | Ничего. Это штатная смена чата, см. [Чаты изнашиваются](#чаты-изнашиваются-и-меняются-сами) | | Чаты пропадают сами, хотя вы их не удаляли | тот же профиль браузера использует другая программа, управляющая чатами | Дайте каждой свой `profileDir` | | `EADDRINUSE: address already in use` | сервис уже запущен в другом окне | Закройте то окно либо возьмите другой порт (`DEEPSEEK_API_PORT`) | | `node не является внутренней или внешней командой` | Node не установлен или командная строка открыта до его установки | Поставьте Node, **закройте и откройте заново** командную строку | | Просит войти в DeepSeek при каждом запуске | профиль каждый раз новый | Проверьте, что `profileDir` указывает на одну и ту же существующую папку | Проверить перевод формата, не поднимая браузер: ```cmd node test.mjs ``` --- ## Безопасность Прочтите, это важнее, чем кажется. - **Сервис слушает все сетевые адреса** (`0.0.0.0`), а не только этот компьютер. Так задумано: подключаться должны и соседние машины, ровно как к самой Ollama. **Аутентификации нет.** - **Он ходит в DeepSeek под вашим логином.** Любой, кто достучится до порта 11500, задаёт вопросы от вашего имени и расходует ваши лимиты. - Поэтому: только домашняя или доверенная сеть. **Не пробрасывайте порт наружу** и не открывайте его на публичном Wi-Fi. - Всё, что вы отправляете, уходит на серверы DeepSeek — как если бы вы написали это в чат руками. Для приватных данных берите локальную Ollama. Если сервис нужен только на этом компьютере, впишите в `config.json`: ```json "host": "127.0.0.1" ``` Тогда снаружи к нему не подключиться вовсе. --- ## Как это устроено внутри ``` POST /api/chat │ ├─ склеить system + user в один текст (у веб-чата нет ролей) ├─ выбрать чат по имени модели (think / search / vision) ├─ встать в очередь (вкладка одна) │ ├─> поднять браузер, если он не отвечает ├─> Chrome DevTools Protocol │ └─> правка ПЕРВОГО сообщения чата │ └─> дождаться, пока DeepSeek допечатает │ └─ отдать в формате Ollama ``` Почему правка первого сообщения, а не новое: DeepSeek отбрасывает всё, что было после отредактированного сообщения, и чат остаётся из одного обмена. Контекст не растёт, мусор между запросами не копится, каждый вопрос — с чистого листа. Почему браузер запускается напрямую из программы, а не батником: батник рассчитан на человека за консолью — на занятом профиле он задаёт вопрос и ждёт ответа, а у сервиса некому отвечать. ### Чаты изнашиваются и меняются сами **Одно сообщение DeepSeek разрешает править ровно шесть раз.** После шестой правки кнопка перестаёт открывать поле ввода — и чат становится непригоден. Ничего делать не нужно, это предусмотрено. На седьмом вопросе программа заводит новый чат того же режима, задаёт вопрос сразу в нём, записывает новый номер в `chats.json` и **удаляет отработавший чат**. Снаружи не видно ничего: тот же запрос, тот же ответ, разве что на несколько секунд дольше. Отсюда следствия: - **`chats.json` — не настройка, а переменная.** Номера в нём меняются сами по мере работы. Не правьте его руками; в репозиторий он не попадает, образец структуры — `chats.example.json`. - **В сайдбаре DeepSeek не копится мусор.** Старые чаты удаляются, плюс перед каждым вопросом сайдбар подчищается от всего, чего нет в `chats.json`. Именно поэтому профиль браузера должен быть свой: чужие чаты в нём программа считает мусором. - Если вы удалите рабочий чат вручную — ничего страшного: следующий запрос заметит пропажу и создаст новый. ### Файлы | Файл | Что в нём | |---|---| | `server.mjs` | HTTP, перевод формата Ollama, очередь | | `browser.mjs` | всё про браузер: CDP, разметка DeepSeek, отправка, ожидание ответа, чаты | | `config.json` | настройки; `config.local.json` рядом перебивает их | | `chats.json` | рабочее состояние: id живых чатов (заводится сам) | | `start.cmd` | запуск в консоли | | `tray.cs`, `build.cmd`, `icon.ico` | окно с индикатором в трее; `.exe` собирается на месте | | `test.mjs` | проверка перевода формата, браузер не нужен | Зависимостей нет — только то, что есть в Node 22. Движок управления вкладкой перенесён из проекта DeepShim, который на этом и закрылся: своего в нём не осталось ничего. Всё, что удалось выяснить про разметку DeepSeek замерами, лежит рядом с кодом комментариями, а разбор «почему именно так» — в [OLD_DEEPSHIM.md](OLD_DEEPSHIM.md). Это знание дороже кода: оно добывалось живыми прогонами и переоткрывается неделями. --- ## Лицензия MIT.