docs: CHANGELOG.md — полное описание проекта для нового агента
This commit is contained in:
+255
@@ -0,0 +1,255 @@
|
||||
# elmAI — Changelog / Полное описание проекта
|
||||
|
||||
> Файл для нового агента: прочитай — и ты в курсе всего.
|
||||
> Актуально: v0.36.0-dev, 31 мая 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. Идентификация
|
||||
|
||||
| Поле | Значение |
|
||||
|------|----------|
|
||||
| Название | **elmAI** (ранее Elmer, elmAI rebrand в конце мая) |
|
||||
| Суть | OBD2-диагностика: Android → ELM327 → LLM (анализ ошибок) |
|
||||
| Репозиторий сервера | `gitea.services.ngcloud.ru/Nail/elmer` |
|
||||
| Репозиторий Android | `github.com/Repinoid/elmer-android` (отдельный!) |
|
||||
| Сервер (prod) | `obdai.ru` (5.172.178.213) |
|
||||
| Язык сервера | Python 3 + Flask + gunicorn |
|
||||
| Язык клиента | Kotlin, minSdk 24 |
|
||||
| LLM-провайдер | `api.aillm.ru` (OpenAI-совместимый) |
|
||||
| База данных | SQLite (WAL mode) |
|
||||
|
||||
---
|
||||
|
||||
## 2. Архитектура (master — продакшен, актуально)
|
||||
|
||||
```
|
||||
📱 Android → ELM327 (Bluetooth SPP)
|
||||
│
|
||||
▼ ScriptRunnerService (фоновая служба)
|
||||
│ выполняет скрипт: OBD-команды → ждёт ответы → пишет лог
|
||||
│ HTTPS POST /api/v1/session/upload
|
||||
▼
|
||||
🌐 obdai.ru (nginx :443 → gunicorn :8000)
|
||||
│
|
||||
├── web/app.py — точка входа Flask
|
||||
├── api/routes.py — 5 эндпоинтов
|
||||
├── api/db.py — SQLite (sessions, cars, dtc, params)
|
||||
├── api/parser.py — парсинг батча ELM-ответов (VIN, DTC, PID)
|
||||
├── api/scripts.py — сборка диагностических скриптов
|
||||
├── api/config.py — загрузка config.yaml (c lru_cache)
|
||||
├── brain/client.py — Diagnoser: HTTP к api.aillm.ru
|
||||
├── brain/prompts.py — SYSTEM_PROMPT (10 правил, табличный формат)
|
||||
└── obd/protocol.py — AndrOBD-стейт-машина (1:1 копия ElmProt.java)
|
||||
```
|
||||
|
||||
### Модули подробно
|
||||
|
||||
#### `api/` — REST + БД + парсинг
|
||||
|
||||
**5 эндпоинтов:**
|
||||
|
||||
| Эндпоинт | Метод | Что делает | Время |
|
||||
|----------|-------|-----------|-------|
|
||||
| `/api/v1/ping` | GET | `{"ok": true}` — проверка сервера | ~5ms |
|
||||
| `/api/v1/ping-llm` | GET | Проверка LLM (кэш 60с, глобальная переменная) | ~2s |
|
||||
| `/api/v1/script?mode=full` | GET | Выдача скрипта диагностики (JSON со steps) | ~50ms |
|
||||
| `/api/v1/session/upload` | POST | Приём батча + LLM-анализ, идемпотентность | ~30-120s |
|
||||
| `/api/v1/chat` | POST | Свободный вопрос к LLM (с историей) | ~5-15s |
|
||||
|
||||
**Ключевые особенности:**
|
||||
- `upload_session()`: принимает `responses` (массив `{cmd, raw, decoded}`) + `request_id` (UUID для идемпотентности). Если `request_id` уже есть в БД — возвращает кэшированный ответ (200).
|
||||
- LLM fallback: если нет API key или LLM ошибка — возвращает `format_no_llm()` (сырые данные без анализа).
|
||||
- `_build_diagnosis_prompt()`: собирает промпт из VIN, DTC stored/pending, параметров, raw_log. Требует глубокого разбора.
|
||||
- `/chat`: передаёт историю как массив `messages[{role, content}]`, срез последних 10.
|
||||
- `config.load()` — `@lru_cache(maxsize=1)`, сбрасывать рестартом процесса.
|
||||
|
||||
**База данных (SQLite, WAL):**
|
||||
- `sessions` — сводная таблица (клиент, ELM, авто, LLM, request_id, response_json для кэша)
|
||||
- `cars` — VIN → id (уникальные)
|
||||
- `diagnostic_tokens`, `llm_messages`, `ecu_parameters`, `dtc_codes` — детальные таблицы (не используются в upload, только legacy)
|
||||
- `PRAGMA journal_mode=WAL`, `busy_timeout=30000`, `check_same_thread=False`
|
||||
|
||||
**Парсер (`parser.py`):**
|
||||
- `parse_batch(responses)` → `{vin, dtc_stored[], dtc_pending[], parameters[{name,value}], raw_log[]}`
|
||||
- Парсит из `decoded` поля, fallback из сырого HEX (490201..., 43..., 47...)
|
||||
- DTC из HEX: декодирует P/B/C/U коды из байтов после 43/47
|
||||
- PID: всё что с `:` в decoded, кроме VIN/DTC/ELM/Protocol
|
||||
|
||||
**Скрипты (`scripts.py`):**
|
||||
- `build_full_script()`: 7 PID (ОЖ, RPM, скорость, дроссель, нагрузка, STFT, LTFT)
|
||||
- `build_default_script()`: 1 PID (0105 — температура ОЖ) для отладки
|
||||
|
||||
#### `brain/` — LLM
|
||||
|
||||
- `Diagnoser(api_key, model="gpt-oss-120b", base_url, timeout=180)`
|
||||
- `diagnose(system, user_prompt, history=None)` → str
|
||||
- Ошибки: `LLMError` с безопасным для клиента сообщением (без деталей)
|
||||
- Различает: Timeout, HTTP 429 («слишком много запросов»), HTTP 5xx, HTTP 4xx
|
||||
- `SYSTEM_PROMPT`: 10 правил, формат ответа — таблицы, степени уверенности в %, план действий по приоритету
|
||||
- Модели: `gpt-oss-120b` (основная), `qwen3-6-27b-fp8` (быстрая, но с CoT leak bug)
|
||||
|
||||
#### `obd/protocol.py` — ELM327 стейт-машина (AndrOBD)
|
||||
|
||||
**Состояния:** `UNDEFINED → INITIALIZING → READY → BUSY → READY`, ошибка → `ERROR`/`DISCONNECTED`
|
||||
|
||||
**Классификация ответов (Rsp.identify):**
|
||||
| Ответ | Тип | Реакция |
|
||||
|-------|-----|---------|
|
||||
| `>` | PROMPT | Конец ответа |
|
||||
| `OK` | OK | Уменьшить таймаут |
|
||||
| `SEARCHING...` | SEARCHING | Нормально при ините |
|
||||
| `NODATA` | NODATA | Увеличить таймаут, ATST |
|
||||
| `UNABLE/BUS BUSY/CAN ERROR` | BUS ERROR | DISCONNECTED → ATPC → ATSP0 |
|
||||
| `ERROR/DATA ERROR/BUFFER FULL` | ERROR | ATWS (warm start) |
|
||||
| Всё остальное | DATA | Успех, уменьшить таймаут |
|
||||
|
||||
**Ключевые особенности (1:1 с AndrOBD):**
|
||||
- Побайтовое чтение с поллингом 1ms (НЕ readLine!)
|
||||
- `>` (0x3E) — не спецсигнал, а разделитель строк как CR/LF
|
||||
- Адаптивный таймаут: 50-2000ms, шаг 20ms, ATST = timeout/4
|
||||
- `_write()`: `reset_input_buffer()` перед записью — чистит хвосты
|
||||
- Инициализация: ATSP0 → ATAT1 → ATST → ATS0 → ATL0 → ATE0 (без ATZ)
|
||||
- BUS ERROR recovery: ATPC → ATSP0
|
||||
- `_read()`: требует `>` перед возвратом, иначе TimeoutError
|
||||
|
||||
#### `web/app.py` — точка входа
|
||||
|
||||
- `sys.path.insert(0, корень_проекта)` — чтобы импортировать `api/`, `brain/`, `obd/`
|
||||
- `config = load()` — глобально
|
||||
- `register_api(app)` — подключает эндпоинты
|
||||
- `/elmer.apk` → `send_from_directory("static", "app-debug.apk")`
|
||||
|
||||
---
|
||||
|
||||
## 3. Версии и история
|
||||
|
||||
### Система версионирования
|
||||
- **Сервер:** `web/templates/index.html` (два места: подзаголовок и подпись APK)
|
||||
- **Android:** `android/app/build.gradle.kts` → `versionName`
|
||||
- **Документация:** заголовки `.md` файлов
|
||||
- **Менять одновременно во всех местах**
|
||||
|
||||
### История версий (сервер)
|
||||
|
||||
#### v0.36.0-dev (31 мая 2026)
|
||||
- Ребрендинг Elmer → elmAI (лого, сайт)
|
||||
- Opus review: серверные фиксы (WAL, идемпотентность, таймауты LLM, кэш ping-llm)
|
||||
- `api/config.py` — `@lru_cache`, `api/db.py` — контекстный менеджер + request_id
|
||||
- `brain/client.py` — обработка ошибок (различает 429, 5xx, Timeout), DEFAULT_MODEL
|
||||
- `obd/protocol.py` — `reset_input_buffer()`, не затирать ERROR
|
||||
- CI/CD в документацию (никаких GitHub Actions — всё вручную)
|
||||
- Правило №1 в `.instructions.md`: вопрос → только ответ, никаких действий
|
||||
|
||||
#### v0.35.0-dev (29-30 мая 2026)
|
||||
- Рефакторинг архитектуры: `elmer/` → `api/` + `brain/` + `obd/`
|
||||
- Удалён мёртвый код (`elmer/diagnose.py`, `elmer/elm.py`, `elmer/prompts.py`, `web/raw_endpoint.py`)
|
||||
- `doc/architecture.md` — полное описание структуры
|
||||
- `obd/protocol.py` — вынесен из elm_proto, доработан
|
||||
|
||||
#### v0.13.0-dev (28 мая 2026) — AndrOBD стейт-машина
|
||||
- Стейт-машина 1:1 с AndrOBD (ElmProt.java)
|
||||
- 5 багов исправлено (команды подряд без пауз, ATST не читал ответ, частичный read, таймаут 200ms, BUS ERROR recovery)
|
||||
- AdaptiveTiming (500ms start, 50-2000ms range, ATST)
|
||||
- OkHttp timeout 30→120с
|
||||
- `tools/mock_elm327_v2.py` — мок с реалистичными задержками
|
||||
- `tools/test_androbd.py` — тест стейт-машины (2/3 зелёные)
|
||||
|
||||
#### v0.11.0-prod (25-27 мая 2026) — fat-client архитектура
|
||||
- Fat-client: телефон сам гоняет протокол, сервер только батч-анализ
|
||||
- Скрипт диагностики: GET /api/v1/script
|
||||
- Загрузка батча: POST /api/v1/session/upload
|
||||
- Эндпоинт /chat
|
||||
- Исследование 19 ELM/BT проектов → AndrOBD = золотой стандарт
|
||||
- `doc/elm-reference.md` — 1100+ строк паттернов
|
||||
- Домен obdai.ru, решение НЕ деплоить до стабильного ELM↔Android
|
||||
|
||||
#### v0.x — ранние версии (fat-client ветка)
|
||||
- `TestService.kt` — зелёная кнопка: самостоятельный прогон протокола (100% работает)
|
||||
- `ElmForwardService.kt` — транспорт BT/TCP ↔ HTTP (проблемы: deadlock, паузы)
|
||||
- Побайтовое чтение в mock (исправлен мусор `\r` vs `\r\n`)
|
||||
- Фиксированный debug.keystore (пароль `android`, alias `androiddebugkey`)
|
||||
- `AndroidManifest.xml`: `usesCleartextTraffic="true"`
|
||||
|
||||
---
|
||||
|
||||
## 4. Android-клиент (отдельный репо)
|
||||
|
||||
### Структура
|
||||
```
|
||||
app/src/main/java/ru/elmer/client/
|
||||
├── elm/
|
||||
│ └── ElmProtocol.kt — ELM327 стейт-машина (AndrOBD)
|
||||
├── obd/
|
||||
│ └── ObdDecoder.kt — декодер PID/DTC/VIN
|
||||
├── server/
|
||||
│ └── ServerClient.kt — HTTP к серверу (retry 3x, OkHttp)
|
||||
├── script/
|
||||
│ ├── ScriptEngine.kt — движок скриптов
|
||||
│ └── ScriptRunnerService.kt — фоновая диагностика
|
||||
├── db/
|
||||
│ └── SessionDb.kt — локальная SQLite история
|
||||
└── ui/
|
||||
└── MainActivity.kt — UI + кнопки
|
||||
```
|
||||
|
||||
### Что НЕ ДОРАБОТАНО (по opus-fix-plan, этап 3-4):
|
||||
- [ ] `request_id` на клиенте (UUID до цикла ретраев, в JSON + заголовок Idempotency-Key)
|
||||
- [ ] `X-Api-Key` через `BuildConfig.API_KEY` из `local.properties`
|
||||
- [ ] `ElmProtocol.sendCommand()` — не затирать ERROR, дренаж буфера
|
||||
- [ ] `SessionDb.onUpgrade()` — ALTER TABLE вместо DROP TABLE
|
||||
- [ ] `MainActivity` — троттлинг `/ping-llm` (не чаще 60с), убрать дублирующий receiver
|
||||
- [ ] `ScriptRunnerService` — null intent → stopSelf, try/finally для progress.stop()
|
||||
- [ ] Exponential backoff в ретраях
|
||||
|
||||
---
|
||||
|
||||
## 5. Деплой
|
||||
|
||||
```bash
|
||||
# Сервер
|
||||
ssh obdai.ru "cd /opt/elmer && git pull origin master && sudo systemctl restart elmer"
|
||||
|
||||
# APK (локально)
|
||||
cd android && ./gradlew assembleDebug
|
||||
scp app/build/outputs/apk/debug/app-debug.apk obdai.ru:/opt/elmer/web/static/app-debug.apk
|
||||
```
|
||||
|
||||
**Сервер:** gunicorn `-w 4 -b 127.0.0.1:8000 web.app:app`, nginx :443 → :8000, SSL certbot.
|
||||
**Ветка:** `master` — продакшен.
|
||||
**НИКАКИХ** GitHub Actions, CI/CD сервисов, Docker, Kubernetes.
|
||||
|
||||
---
|
||||
|
||||
## 6. Правила работы (критически важно!)
|
||||
|
||||
1. **Вопрос в любой форме → только ответить. НИЧЕГО НЕ ПРЕДПРИНИМАТЬ.** Только прямые императивы («сделай», «исправь», «напиши») — команда к действию.
|
||||
2. **Не выдумывать инфраструктуру.** Никаких GitHub Actions, Docker, K8s, CI/CD.
|
||||
3. **Читать документацию перед действиями.** `doc/architecture.md` — канонический источник.
|
||||
4. **Не редактировать отчёты Опуса** (`doc/opus-review*.md` — только для чтения).
|
||||
5. **После правок:** коммит → пуш → (если сервер) деплой через SSH.
|
||||
6. **Версию менять в трёх местах:** `index.html`, `build.gradle.kts`, доки.
|
||||
7. **Не редактировать файлы Android-репо** (elmer-android) — это отдельный репо.
|
||||
|
||||
---
|
||||
|
||||
## 7. Известные архитектурные решения
|
||||
|
||||
- **Почему не Docker:** владелец принципиально против. Всё вручную через git + systemd.
|
||||
- **Почему fat-client (скрипт + батч):** в движении связи с сервером нет. Телефон сам гоняет протокол, потом заливает данные.
|
||||
- **Почему AndrOBD (не своё):** AndrOBD — 10 лет продакшена, 1993⭐, вылизанный протокол. Копировать 1:1, не изобретать.
|
||||
- **Почему не PostgreSQL:** SQLite достаточно для одного сервера. Миграция будет когда-нибудь потом.
|
||||
- **Почему obdai.ru не в продакшене:** пока не отлажен ELM↔Android на 100%. Телефон + ноутбук в одной WiFi — быстрее и надёжнее.
|
||||
|
||||
---
|
||||
|
||||
## 8. Ветки
|
||||
|
||||
| Ветка | Описание |
|
||||
|-------|----------|
|
||||
| `master` | Продакшен (актуальная: v0.36.0-dev) |
|
||||
| `opus-fixes` | Правки по отчётам Опуса (31 мая; влита в master) |
|
||||
| `arch-refactor` | Рефакторинг elmer/ → api/ brain/ obd/ |
|
||||
| `fat-client` | Старая fat-client архитектура (устарела) |
|
||||
| `androbd-proto` | Прототип AndrOBD стейт-машины (устарела) |
|
||||
| `elm-layer-v2` | Старый ELM-слой (устарела) |
|
||||
Reference in New Issue
Block a user