DeepShim (ollama_orchestro) закрыт: движок браузера переехал сюда, веб-пульт с галочками и помощь с git — в deepwork, потребители ходят по HTTP, а Claude Code на локальной модели похоронен как неудачный. Своего в нём не осталось, зато осталось знание про веб-интерфейс DeepSeek, добытое живыми прогонами: почему признак конца ответа ищется в кнопке отправки, почему блоки кода пропадают у фонового окна, почему New chat нельзя жать из DOM, а кнопку редактирования — только из DOM, в каком порядке удаляется чат и на чём там уже ошибались. Почти всё это действует внутри browser.mjs и продублировано комментариями рядом с кодом. Файл — на случай, когда нужно понять ПОЧЕМУ, а комментария не хватило. Первым разделом — почему DeepShim больше не нужен, с тремя доводами, почему держать его дальше было бы вредно: дубликат знания разошёлся бы молча, две программы на одном профиле браузера удаляют чаты друг друга, потребителей не осталось. Намеренно не перенесено: заметки про бюджет контекста Claude Code, плагины и запуск оркестратора — они про мёртвую часть и к DeepSeek отношения не имеют. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
442 lines
25 KiB
Markdown
442 lines
25 KiB
Markdown
# 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. [Как это устроено внутри](#как-это-устроено-внутри)
|
||
|
||
---
|
||
|
||
## Что понадобится
|
||
|
||
| Что | Зачем | Как проверить, что есть |
|
||
|---|---|---|
|
||
| **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 (например,
|
||
> [DeepShim](https://git.08h.ru/alex/deepshim)), они начнут удалять чаты друг
|
||
> друга: каждая считает лишним всё, чего нет в её собственном списке.
|
||
|
||
### Шаг 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
|
||
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` | запуск |
|
||
| `test.mjs` | проверка перевода формата, браузер не нужен |
|
||
|
||
Зависимостей нет — только то, что есть в Node 22.
|
||
|
||
Движок управления вкладкой перенесён из проекта DeepShim, который на этом
|
||
и закрылся: своего в нём не осталось ничего. Всё, что удалось выяснить про
|
||
разметку DeepSeek замерами, лежит рядом с кодом комментариями, а разбор
|
||
«почему именно так» — в [OLD_DEEPSHIM.md](OLD_DEEPSHIM.md). Это знание дороже
|
||
кода: оно добывалось живыми прогонами и переоткрывается неделями.
|
||
|
||
---
|
||
|
||
## Лицензия
|
||
|
||
MIT.
|