feat: классификация писем Qwen3:8b + обработчики (urgent→TG, task→VTODO, meeting→VEVENT)

- mail_archive.py: фикс вложений himalaya --dir → --downloads-dir; attachments/ только при has_attachment; идемпотентно
- email_classifier.py: Qwen3:8b (Ollama) → теги info/urgent/task/meeting в frontmatter email.md
- email_handlers.py: urgent→Telegram (Bot API+SOCKS5), task→Radicale VTODO, meeting→Radicale VEVENT; handled_* идемпотентность; --dry-run
- .gitignore: игнор *.env.bak*
- openspec: чейндж email-classification-handlers (в работе)
- STATUS/TODO/WALKTHROUGH: прогресс сессии, подводные камни Radicale (http.client, Depth:1, формат дат)
This commit is contained in:
2026-09-13 20:35:58 +00:00
parent 8ea022f5c0
commit 7550aff102
22 changed files with 1728 additions and 76 deletions
+67
View File
@@ -0,0 +1,67 @@
# PRD — Email Assistant (локальный почтовый ассистент)
Обновлено: 2026-09-13
## Цель
Инкрементальный локальный архив корпоративной почты с последующей обработкой
локальной LLM: классификация писем, извлечение контактов, дайджесты, интеграция
с локальным календарём/задачами (Radicale CalDAV). Всё — локально (bigbox),
без облачных зависимостей.
## Пользователи
Один пользователь — estorozhenko (личная корпоративная почта
e.storozhenko@vinogorod.ru, IMAP mail.corpoffice.tech).
## Функциональные требования
1. **Архивация:** скачивать письма с IMAP, сохранять текст+метаданные в
`email.md` (YAML-frontmatter + текст), структура
`/opt/hermes/email/<folder>/YYYY/MM/<uid>/`.
2. **Вложения:** сохранять вложения в каталог письма `attachments/`
(ФТ-2, в работе).
3. **Поиск:** SQLite FTS5 по письмам (веб-интерфейс, Задача 1).
4. **Классификация:** локальная LLM (Qwen3:8b) классифицирует письмо →
тег info/urgent/task/meeting + обоснование (ФТ-3, в работе).
5. **Обработчики:** по тегам — urgent→Telegram, task→Radicale VTODO (календарь
«Задачи»), meeting→Radicale VEVENT (календарь «Рабочий»), info→ничего
(ФТ-4, в работе).
6. **Контакты:** извлечение контактов из подписей через LLM + двухсторонний
CardDAV sync с Radicale («Контакты»).
7. **Дайджест:** еженедельная сводка писем.
8. **Календарь/задачи:** Radicale CalDAV (Личный/Рабочий/Задачи), синхронизация
с Android (DAVx5 → календари/контакты, jtx board → VTODO-задачи).
## Нефункциональные требования
- **Приватность:** текст писем никогда не покидает bigbox (обработка только
локальной LLM Qwen3:8b через Ollama localhost:11434).
- **Идемпотентность:** повторный запуск не дублирует (классификацию,
обработчики, вложения).
- **Отказоустойчивость:** сбой обработчика не теряет письмо (лог + повторная
попытка по тегу).
- **Расположение:** всё в `/opt/hermes/` (единый каталог, бэкап = копия).
- **Порядок данных:** секреты — только в `.env`/`.htpasswd`, не в git и не в
README/WALKTHROUGH.
## Границы (что НЕ делаем)
- **НЕ** используем облачных ассистентов/API для содержимого писем (Nylas и
т.п. отклонено).
- **НЕ** используем Vikunja — задачи через Radicale VTODO (решение 2026-09-13).
- **НЕ** отправка почты (архив read-only).
- **НЕ** удаляем/теряем письма — архив только пополняется.
## Критерии готовности
- [ ] Вложения качаются в `attachments/` (ФТ-2)
- [ ] Классификатор проставляет теги на всю базу (ФТ-4)
- [ ] Обработчики срабатывают и видны в Telegram/Radicale (ФТ-5)
- [ ] Веб-интерфейс: поиск, тэги, «Создать задачу» (Задача 1)
- [ ] Календарь/задачи синхронизируются на Android по CalDAV
## Стек
Himalaya CLI → Python (mail_archive.py) → SQLite FTS5 → Ollama Qwen3:8b →
Radicale (CalDAV/CardDAV, docker :5232, cal.nixg.ru) → Telegram (уведомления).