---
name: notion_web2api_overview
description: notion-web2api — OpenAI-совместимый шлюз к моделям Notion AI (Fable5/Opus/GPT/GLM/DeepSeek/Kimi/Grok) через Enterprise-сиденье
metadata: 
  node_type: memory
  type: project
  originSessionId: 32127bdb-31c7-4402-a5e6-81684cfeaeff
  modified: 2026-07-21T06:44:54.426Z
---

Свой web2api к Notion AI. Код `~/Разработки/notion-web2api/notion_web2api.py` на mini, venv `~/.venvs/notion-web2api` (py3.9), launchd `com.cebers.notion-web2api`, порт **:1722**, тайл ops_dashboard `notion_web2api` (правило 8).

**⚠️ СМЕНА АККАУНТА (2026-07-19): старый аккаунт `CeBers's Space` (4 воркспейса S1-S4, ротация ×4 ниже) НЕДОСТУПЕН, "не восстановить".** Новый — ОДИН воркспейс `Rosario Jast's Space` (email grimeskarla1612002@gmail.com), `space_id=b0442161-c03a-81b0-b007-00033f3ad6ea`, `user_id=3a4d872b-594c-816b-865b-00028895df9d`. `workspaces[]`/`image_thread_id` убраны из config.json (ротация закрыта вместе со старым аккаунтом), верхнеуровневые space_id/user_id и т.п. переписаны под новый. ID нового воркспейса добываются разовым скриптом через `POST /api/v3/getSpaces` (через прокси, см. ниже). Проверено живьём: chat 2+2→«4», `refresh_token.py --force-seed` прошёл. Секция "ЧАТ-РОТАЦИЯ ×4" ниже — ИСТОРИЧЕСКАЯ, для старого аккаунта, сейчас неактуальна.

- Эндпоинт Notion: `POST www.notion.so/api/v3/runInferenceTranscript`, ответ NDJSON; финальный текст = последний шаг `type:"agent-inference"` → `value[].content`. Служебный тег `<lang…/>` в начале срезается (буферизация в стриме).
- **Модель = codename** в config-шаге транскрипта (Fable5=`acai-budino-high`, Opus4.8=`ambrosia-tart-high`, GLM5.2=`baseten-glm-5.2` …). Полный маппинг 25 моделей в коде. Голый LLM: все `enable*/use*` флаги=false (срезает ~20k преамбулы).
- **Прокси обязателен**: Notion блокирует РФ-IP mini → трафик через xray `socks5://127.0.0.1:2080` (как gemini/chatgpt web2api). Без прокси httpx таймаутит.
- **ЧАТ-РОТАЦИЯ ×4 воркспейса (2026-07-16, умножение квоты):** AI-квоты Notion РАЗДЕЛЬНЫ по воркспейсам, а token_v2 — ЮЗЕР-уровневый (адресует все воркспейсы юзера; воркспейс = заголовок `x-notion-space-id`+`spaceId` в теле, НЕ токен). `config.json` → массив `workspaces[]` (S1 ff218210/S2 0ef07613/S3 955f2f97/S4 979501af, один user_id 39ed872b, image_thread_id только S1). Код: `threading.local _REQ` = активный ws на запрос; `_cfg(key)` читает поле активного ws (фолбэк CONFIG); `stream_chat_text` round-robin (`_next_start_index`) + failover (401/non-200 → следующий ws до первого чанка). Картинки прибиты к S1 (единств. с тредом). Back-compat: без `workspaces` — как раньше. Проверено: 6 запросов раскидались S1→S2→S3→S4→S1→S2, все PING; живой сервис ok. NB: «второй аккаунт» юзера оказался ТЕМ ЖЕ user_id (4 воркспейса одного юзера), не отдельное сиденье — но т.к. квоты по воркспейсам, ротация по space_id всё равно умножает лимит. TODO картинки-ротация: нужен image_thread_id в S2-S4 (юзер создаёт AI-чат с картинкой в каждом; API-минтинг тредов не работает).
- **Токен**: кука `token_v2` (httpOnly, значение может быть v03-JWT), в `config.json`, добывается ВРУЧНУ из браузера (Storage→Cookies notion.so). Живёт ~дни, протухает → healthz `cookie_error`. Куку из app.notion.com сессии тоже подходит к www.notion.so.
- `/healthz` дёшево (токен+достижимость), `?deep=1` = реальная проба Haiku. Не жечь инференс на мониторинге. ⚠️ ДЕФЕКТ healthz: cheap-проба (`getAvailableModels`) = ЧТЕНИЕ, проходит даже когда ИНФЕРЕНС заблокирован → тайл зелёный при мёртвом Notion. Реальная проверка «работает ли» — только `?deep=1` или живой чат.
- **БЛОКИРОВКА `trust-rule-denied` (2026-07-16): Notion заблокировал AI-инференс АККАУНТ-УРОВНЕВО.** Сырой ответ на runInferenceTranscript: `{"type":"error","subType":"trust-rule-denied","message":"AI inference is not allowed."}` (`checkRunInferenceTranscriptRuleSet`). Все 4 воркспейса разом (не токен — чтение работает, healthz зелёный). Почти наверняка **флаг Enterprise-сиденья за интенсивный автодоступ** (наши прогоны 25 моделей + ротация + спорт-пробы + дистилляция за сессию). Чат отдавал HTTP200 с пустым `content` → пофикшено: `stream_chat_text` детектит `type:error` в стриме, пробует следующий воркспейс, при провале всех — **HTTP 500** с текстом (чтобы клиентские fallback'ы: Делор distill→mistral, CebersPost→Flux сработали). Восстановление: (1) ждать — trust-rule может быть rate-based/временным (часы-сутки), ретраить; (2) проверить в Notion admin/security настройки доступности AI; (3) снизить автонагрузку (не хаммерить). Bug-fix бэкап `/tmp/nw.bak-err`.
- OpenAI API: `/v1/models`, `/v1/chat/completions` (+stream). Проверено живьём: 25 моделей всех вендоров, non-stream+stream, 7*6=42.
- Самоидентификация моделей НЕнадёжна: glm/deepseek/grok/gemini отвечают «Claude» — гарантировать реальный андерлайинг нельзя.
- **Генерация картинок РАБОТАЕТ** (`/v1/images/generations`, b64_json/data-uri): `generate-image` (Google nano-banana 1408×768) в служебный `image_thread_id` (реальный тред; UUIDv4 отвергается), парс `imageUrlAlias`, скачивание через **`/image/`-прокси** (`GET /image/<enc alias>?table=thread&id=<thread>&spaceId=<space>` — signed S3 URL 403-ит серверно, только /image/ работает). ~20-30с. Все картинки в один тред (накопление).
- **Авто-рефреш токена** (`refresh_token.py`, venv `~/.venvs/notion-web2api-pw` py3.12+playwright): персистентный профиль `pw_profile/` через xray-прокси. launchd `com.cebers.notion-web2api-refresh` каждые 6ч + self-heal в сервисе при 401 (env-guard `NOTION_WEB2API_REFRESHING` рвёт рекурсию verify→refresh; flock+lock от штормов — БЫЛ форк-бомб-инцидент). Сервис перечитывает токен из config.json по mtime без рестарта.
  - КРИТИЧНО: token_v2 — СЕССИОННАЯ кука, при сиде в профиль ОБЯЗАТЕЛЕН `expires` (иначе Chromium не пишет на диск, профиль не переживает рестарт).
  - Notion НЕ ротирует token_v2 на заходе → рефреш = «keep-warm + детект протухания», НЕ giga-подобный авто-минт. Токен живёт недели; умер → профиль тоже мёртв, спасает только ручной пересид свежим токеном в config.json (потом refresh_token.py force_seed вернёт профиль к жизни). Полноценный авто-минт невозможен без автоматизации ЛОГИНА (креды/OAuth).
- **CebersPost рисует посты через nano-banana**: `images.py:_ai_image` пробует Notion-первым (`_notion_generate`→:1722, `_crop_square` 1408×768→квадрат), фолбэк Flux→вектор. Конфиг `notion_image_enabled`/`notion_image_url` (default ON).
  - **`_build_flux_prompt` ИСПРАВЛЕН 2026-07-15**: раньше бил в ОДИН `settings.draft_chat_url`(=nvidia) с `thinking:{disabled}` → NVIDIA 400 → сырой русский заголовок как image-промпт. Теперь перебирает всю цепочку `settings.draft_chat_providers` (gigachat→gemini→nvidia→zai:20129), `thinking` шлёт ТОЛЬКО провайдерам с флагом `thinking=true`, первый непустой ответ. Проверено: gigachat :1720 отдаёт English-сцену. Бэкап `/tmp/images.py.bak-flux`.
  - **nano-banana «регрессия» 2026-07-15 = исчерпанная КВОТА (не баг), РАЗОБРАНО 2026-07-16**: сырой ответ Notion — `generate-image` отрабатывает (status:completed), но `agent-tool-result` содержит `"state":"applied:error","error":"You've reached your image generation limit. Please try again later."` = дневной лимит генерации на Enterprise-сиденье (выжгли тестами). Токен валиден (чат=PING ✓), формат для успеха не менялся, `file_ids` = история треда. Сбрасывается сам со временем. Фикс обработки: `generate_image_bytes` вытаскивает причину (`_IMG_ERR_RE`), лимит→`ImageQuotaError`→хендлер отдаёт **HTTP 429** `{type:image_quota_exceeded}`; CebersPost `_ai_image` логирует 429 как INFO и уходит в Flux. Ложный след при диагностике: raw-скрипт с модульным `CONFIG` 401-ит при рабочем сервисе (сервис читает `token_v2` живьём по mtime) — диагностировать ТОЛЬКО через живой сервис (curl :1722), не raw-import.
- **Vision-вход (приём картинок) — ЗАБЛОКИРОВАН (глубокий wall).** Разобрано полностью: (1) upload-эндпоинт `getUploadFileUrlForAssistantChatTranscriptUpload` (payload name/contentType/`assistantChatTranscriptSessionPointer{spaceId,table:thread,id}`/contentLength/createThread) → ответ {url:`attachment:<file_id>:<name>`, signedGetUrl, signedUploadPostUrl(S3), fields}; (2) S3 POST form-upload (fields+file) → 204 OK. НО: загрузка в тред НЕ делает картинку видимой модели — инференс отвечает «ты не загружал картинок». Картинку надо ПРИВЯЗАТЬ К СООБЩЕНИЮ отдельной Notion-транзакцией (saveTransactions/message-запись с image-блоком) — НЕ раскрыто, глубокая RE транзакционной модели Notion. Плюс минтинг тредов через API не работает (v4 threadId→«[», createThread без id не отдаёт id). ИТОГ: vision через Notion непрактичен без реверса saveTransactions. Рекомендация для Делора — ГИБРИД: Fable5 текст+генерация, приём картинок оставить на llama-3.2-vision.
- **НЕ годится как backend кодинг-агента, и ШЛЮЗОМ ЭТО НЕ ЧИНИТСЯ (проверено 2026-07-16):** (1) отвергает персону/строгий формат — Opus 4.8 на «You are zcode... reply ONLY JSON» → «I'll stay as myself, won't lock replies into JSON»; (2) не отдаёт OpenAI `tool_calls` (на `tools[]` → `tool_calls:null`+проза). **Корень глубже: Notion AI — серверный продукт-агент с зашитой личностью и СВОИМ фикс-набором тулзов** (workspace-поиск/страницы/базы, web-search, generate-image). Отказывается ФАБРИКОВАТЬ tool-call для инструмента, которого у него нет («outputting that string wouldn't actually read any file — misleading») — под ЛЮБОЙ рамкой (персона/кооперативно/«я парсю твой ответ») и на любой модели (opus, glm — обёртка одна). tool-calling-шим на :1722 бесполезен: модель не выдаёт токены вызова, т.к. identity+tool-scope инжектятся НА СЕРВЕРЕ Notion (флаги `enable*=false` стрипают преамбулу, но не личность). Дёргаем чужой готовый агент, а не голую модель. Единственный потолок: Notion как ТЕКСТОВЫЙ мозг, где tool-execution делает харнесс агента (сам читает/пишет/запускает), а в Notion уходит только текст — и только если харнесс без function-calling и терпит дрейф формата. Для настоящего агента — function-calling модель через НЕ-Notion шлюз (OmniRoute, deepseek/qwen/gemini :1717-1719).
- **НЕ годится как chat/agent-провайдер под своим system-prompt** (проверено на Делоре 2026-07-15, откачено): Fable 5 навязывает identity «Я — Notion AI», отвергает чужой system-prompt → персона/тулзы деградируют; на спорте стабильно `[]` (0 пиков, ультра-консервативна). Мини-бенч vs DashScope сравнения не дал. Делор откачен на `cerebras/gpt-oss-120b` (fallback `mistral/mistral-small-latest`).
- **✅ ГОДИТСЯ как ТЕКСТОВЫЙ синтезатор в [[CebersResearch]] (2026-07-16):** ровно тот сценарий, что память и допускала (харнесс сам ищет, function-calling не нужен, персона-дрейф терпим — в Notion уходит только текст+источники). Реальный тест: opus-4.8/fable-5 на synth-промпте с пронумерованными источниками → корректные структурные ответы, **отсекают подсунутый мусорный источник**, персона НЕ лезет. Подключено: `research/notion-opus`+`research/notion-fable5` (выбираемые чат-модели) + Notion(**opus-4.8**) стал **primary синтезатором `/v1/research`** (fallback DeepSeek→Qwen→GigaChat-Ultra). Килсвитч `NOTION_SYNTH=0` (env, при квота-проблеме на хот-пути investpilot), модель `NOTION_SYNTH_MODEL`. **Грабля:** Notion пишет цитаты markdown-сносками `[^{{N}}]` вместо inline `[N]` → в main.py добавлен `_normalize_citations` (регекс `[^{{N}}]`→`[N]`, мусорные `[^{{url}}]` срезаются). Синтез ~28с. Итого годен: картинки (CebersPost), ручные запросы к 25 моделям, **синтез CebersResearch**.
- Enterprise-сиденье флагается жёстче → вспомогательный голос, не боевая шина. Связь: [[risky_llm_provider_isolation]], [[gemini_web2api_overview]], [[chatgpt_web2api]], [[sport_reliability_quality_pref]].
