Files
email-assistant/openspec/changes/email-classification-handlers/proposal.md
T
hermes 7550aff102 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, формат дат)
2026-09-13 20:35:58 +00:00

5.2 KiB
Raw Blame History

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: новый классификатор/обработчики