Задача 8: классификация и обработчики — живой прогон, cron, archive change

This commit is contained in:
2026-09-14 04:50:50 +00:00
parent 7550aff102
commit 8bff6f9aa4
14 changed files with 257 additions and 28 deletions
@@ -0,0 +1,68 @@
# Proposal: Классификация писем и подключение обработчиков
## Why
Сейчас после скачивания письма с IMAP (`mail_archive.py`) письмо сохраняется как
`email.md` (YAML-frontmatter + текст) и на этом всё. Пользователь не получает
сигнала о том, что пришло важное письмо: что в письме задача, встреча, срочный
вопрос или просто информация. Каждое письмо нужно вручную открывать и читать.
При этом инфраструктура уже есть:
- Radicale (CalDAV/CardDAV) на `cal.nixg.ru` — календари Личный/Рабочий/Задачи
- Vikunja (трекер задач) — развёрнут, ждёт администратора
- Ollama с Qwen3:8b — локальная модель (не уходит в облако, приватно)
- Мессенджер — уведомления можно слать в Telegram
Хочется: после скачивания письма локальная модель классифицирует его и помечает
тегами (информационное, требует срочного ответа, есть задача, назначена встреча
и т.п.), а на основе тегов запускаются обработчики: уведомление в мессенджер,
создание задачи в Vikunja, создание события в календаре Radicale.
Параллельно найден баг: вложения сейчас **не скачиваются** — `get_attachments()`
вызывает `himalaya attachment download --dir`, но правильный флаг `--downloads-dir`,
команда падает (exit 2), ошибка молча глотается `except: pass`, и папка
`attachments/` всегда пустая. Чейндж чинит это: вложения должны попадать в каталог
письма (что логично — каталог письма уже создаётся).
## What Changes
1. **Вложения скачиваются в каталог письма** — `mail_archive.py` правит вызов
`himalaya attachment download`: использует `--downloads-dir` вместо `--dir`,
кладёт файлы в `<msg_dir>/attachments/`. Проверяется на письме с вложением.
2. **Классификатор писем** — новый скрипт `email_classifier.py`, который:
- берёт неклассифицированные письма (нет `classification` в frontmatter)
- отдаёт текст письма локальной модели Qwen3:8b (Ollama localhost:11434)
- получает JSON с тегами: `info`, `urgent`, `task`, `meeting` (и, возможно,
`question`, `money`, `deadline`)
- пишет результат в frontmatter `email.md`: поле `classification` (тег) +
`classification_reason` (короткое обоснование)
3. **Обработчики по тегам** — новый скрипт `email_handlers.py`:
- `urgent` → уведомление в мессенджер (Telegram, через Hermes gateway)
- `task` → создание задачи в Vikunja (API tasks.nixg.ru)
- `meeting` → создание события в Radicale (календарь Рабочий, cal.nixg.ru)
- `info` → ничего, письмо просто помечено тегом
- идемпотентность: письмо обрабатывается один раз (трекинг в state/SQLite)
4. **Cron** — новый Hermes cron (или расширение существующего), который после
архивации запускает классификатор и обработчики.
## Capabilities
### New Capabilities
- `email-classification`: классификация писем локальной LLM + теги в frontmatter
- `email-handlers`: подключение обработчиков (уведомление, задача, встреча) по тегам
- `email-attachments`: скачивание вложений письма в его каталог (фикс бага)
### Modified Capabilities
- (нет) — существующая capability `email-storage-format` не меняет требования
по формату файла, только добавляет новые поля; это расширение, а не изменение
существующих требований.
## Impact
- Скрипты: `mail_archive.py` (фикс вложений), новые `email_classifier.py`,
`email_handlers.py`
- Конфиг: Ollama (Qwen3:8b, уже есть), Vikunja API (нужен токен), Telegram
(gateway/уведомления), Radicale (события)
- Frontmatter `email.md`: новые поля `classification`, `classification_reason`,
`has_attachments` (если ещё нет)
- Cron: новый классификатор/обработчики