- Wprowadzenie
- Architektura systemu
- Instalacja i uruchomienie
- Konfiguracja
- Główne komponenty
- Przepływ danych
- Baza danych
- System szablonów i automatycznych odpowiedzi
- Archiwizacja wiadomości
- Integracja z LLM
- Testowanie
- Rozszerzanie funkcjonalności
- Rozwiązywanie problemów
Email LLM Processor to minimalistyczna aplikacja napisana w Kotlinie z użyciem Apache Camel, umożliwiająca automatyczne przetwarzanie, analizę i generowanie odpowiedzi na wiadomości e-mail przy użyciu modeli językowych (LLM).
Aplikacja została zaprojektowana w podejściu skryptowym, bez wykorzystania frameworków takich jak Spring Boot, co minimalizuje ilość kodu i zależności, jednocześnie zachowując wszystkie niezbędne funkcjonalności.
- Odbieranie wiadomości e-mail przez IMAP
- Wysyłanie wiadomości e-mail przez SMTP
- Analiza treści wiadomości przy użyciu modeli językowych (LLM)
- Automatyczne generowanie odpowiedzi
- Przechowywanie wiadomości w lokalnej bazie danych SQLite
Projekt jest zorganizowany w następujący sposób:
src/main/kotlin/com/emailprocessor/
├── Main.kt # Główny punkt wejścia aplikacji
├── model/ # Modele danych
│ ├── EmailMessage.kt # Model wiadomości email
│ └── ToneAnalysis.kt # Model analizy tonu
├── routes/ # Trasy Apache Camel
│ ├── EmailProcessingRoute.kt # Odbieranie i przetwarzanie emaili
│ └── EmailSendingRoute.kt # Wysyłanie automatycznych odpowiedzi
├── services/ # Serwisy biznesowe
│ ├── EmailService.kt # Logika przetwarzania emaili
│ └── LlmService.kt # Integracja z modelami językowymi
└── util/ # Narzędzia pomocnicze
└── EmailParser.kt # Parser wiadomości email
+---------------+ +-------------------+ +-------------------+
| | | | | |
| Serwer Email |--->| EmailProcessing |--->| LLM Service |
| (IMAP) | | Route | | (Analiza tonu) |
| | | | | |
+---------------+ +-------------------+ +-------------------+
| |
v |
+-------------------+ |
| | |
| Baza danych |<-------------+
| SQLite |
| |
+-------------------+
|
v
+-------------------+ +-------------------+
| | | |
| Email Service |--->| EmailSending |
| (Decyzja o | | Route |
| odpowiedzi) | | (SMTP) |
+-------------------+ +-------------------+
|
v
+---------------+
| |
| Serwer Email |
| (Odbiorca) |
| |
+---------------+
- Java 17 lub nowsza
- Gradle 8.0 lub nowszy
- Docker i Docker Compose (do uruchomienia w kontenerach)
-
Sklonuj repozytorium:
git clone https://github.com/yourusername/email-llm-processor.git cd email-llm-processor -
Skopiuj plik przykładowy .env.example do .env:
cp .env.example .env -
Dostosuj zmienne w pliku .env według potrzeb.
docker-compose up -d
To polecenie uruchomi:
- Aplikację Email LLM Processor
- Serwer testowy MailHog do odbioru/wysyłania wiadomości
- Serwer Ollama do hostowania modelu LLM
- Adminer do zarządzania bazą danych SQLite
-
Zbuduj projekt:
./gradlew build -
Uruchom aplikację:
./gradlew run
Można również użyć dołączonego skryptu do uruchomienia aplikacji:
./run.sh
Aplikacja korzysta z następujących zmiennych środowiskowych, które można ustawić w pliku .env:
| Zmienna | Opis | Wartość domyślna |
|---|---|---|
| EMAIL_HOST | Host serwera email | mailhog |
| EMAIL_PORT | Port serwera email | 1025 |
| EMAIL_USER | Nazwa użytkownika email | test@example.com |
| EMAIL_PASSWORD | Hasło użytkownika email | password |
| LLM_API_URL | URL API modelu językowego | http://ollama:11434 |
| LLM_MODEL | Nazwa modelu językowego | llama2 |
| APP_PORT | Port aplikacji | 8080 |
| DATABASE_PATH | Ścieżka do bazy danych SQLite | /app/data/emails.db |
Główny punkt wejścia aplikacji, odpowiedzialny za inicjalizację wszystkich komponentów i uruchomienie Apache Camel. Zawiera konfigurację aplikacji, ładowanie zmiennych środowiskowych i inicjalizację bazy danych.
fun main() {
// Inicjalizacja i uruchomienie aplikacji
val app = EmailLlmProcessor()
app.init()
app.start()
}Trasa Camel odpowiedzialna za odbieranie i przetwarzanie wiadomości e-mail. Implementuje następujący przepływ:
- Odbieranie wiadomości przez IMAP
- Parsowanie wiadomości do modelu EmailMessage
- Zapisywanie wiadomości w bazie danych SQLite
- Przetwarzanie wiadomości przez EmailService
- Decydowanie o wysłaniu automatycznej odpowiedzi
Trasa Camel odpowiedzialna za wysyłanie automatycznych odpowiedzi. Formatuje odpowiedzi na podstawie analizy tonu i wysyła je przez SMTP.
Serwis zawierający logikę biznesową przetwarzania wiadomości. Odpowiada za:
- Przetwarzanie wiadomości email
- Decydowanie o automatycznej odpowiedzi na podstawie analizy tonu
- Generowanie treści odpowiedzi przy użyciu zaawansowanego systemu szablonów
- Archiwizację wiadomości do plików
Serwis do komunikacji z API modelu językowego. Odpowiada za:
- Tworzenie promptów dla modelu LLM
- Wysyłanie zapytań do API modelu (Ollama)
- Parsowanie odpowiedzi i tworzenie obiektów ToneAnalysis
Serwis do generowania zaawansowanych automatycznych odpowiedzi wykorzystujący dane z bazy SQLite oraz plików szablonów. Odpowiada za:
- Pobieranie historii komunikacji z bazy danych
- Zarządzanie szablonami odpowiedzi przechowywanymi w plikach
- Wybór odpowiedniego szablonu na podstawie analizy tonu i historii komunikacji
- Personalizację odpowiedzi z wykorzystaniem danych o nadawcy i historii
Narzędzie do parsowania wiadomości e-mail. Obsługuje różne formaty wiadomości (plain text, HTML, multipart) i ekstrahuje załączniki.
-
Odbieranie wiadomości:
- Komponent IMAP Apache Camel regularnie sprawdza skrzynkę pocztową
- Nowe wiadomości są pobierane i przekazywane do trasy przetwarzania
-
Parsowanie wiadomości:
EmailParserekstrahuje nadawcę, odbiorcę, temat i treść wiadomości- Wiadomość jest konwertowana do modelu
EmailMessage
-
Zapisywanie w bazie danych:
- Wiadomość jest zapisywana w tabeli
emailsw bazie SQLite - Status wiadomości jest ustawiany na
RECEIVED
- Wiadomość jest zapisywana w tabeli
-
Analiza tonu:
LlmServicewysyła treść wiadomości do API modelu językowego (Ollama)- Model analizuje sentyment, emocje, pilność i formalność wiadomości
- Wyniki są parsowane do modelu
ToneAnalysis
-
Decyzja o odpowiedzi:
EmailServicena podstawie analizy tonu decyduje, czy wysłać automatyczną odpowiedź- Wiadomości pilne lub o negatywnym sentymencie otrzymują automatyczną odpowiedź
-
Generowanie odpowiedzi:
- Jeśli zdecydowano o odpowiedzi,
EmailServicegeneruje odpowiednią treść - Treść jest dostosowana do tonu oryginalnej wiadomości
- Jeśli zdecydowano o odpowiedzi,
-
Wysyłanie odpowiedzi:
EmailSendingRouteformatuje wiadomość odpowiedzi- Odpowiedź jest wysyłana przez SMTP do oryginalnego nadawcy
- Status wiadomości jest aktualizowany na
REPLIED
Aplikacja wykorzystuje prostą bazę danych SQLite do przechowywania wiadomości e-mail i wyników analizy.
CREATE TABLE IF NOT EXISTS emails (
id INTEGER PRIMARY KEY AUTOINCREMENT,
from_address TEXT NOT NULL,
to_address TEXT NOT NULL,
subject TEXT,
content TEXT,
received_date TIMESTAMP,
processed_date TIMESTAMP,
tone_analysis TEXT,
status TEXT
)System automatycznych odpowiedzi wykorzystuje kombinację danych z bazy SQLite oraz plików szablonów przechowywanych w systemie plików. Dzięki temu może generować spersonalizowane odpowiedzi dostosowane do kontekstu komunikacji z danym nadawcą.
Szablony odpowiedzi są przechowywane w katalogu data/templates/ w postaci plików tekstowych z rozszerzeniem .template. Każdy szablon zawiera tekst odpowiedzi z placeholderami, które są zastępowane rzeczywistymi danymi podczas generowania odpowiedzi.
System zawiera następujące rodzaje szablonów:
default.template- domyślny szablon odpowiedziurgent_critical.template- odpowiedź na wiadomości o krytycznej pilnościurgent_high.template- odpowiedź na wiadomości o wysokiej pilnościnegative_very.template- odpowiedź na wiadomości o bardzo negatywnym sentymencienegative.template- odpowiedź na wiadomości o negatywnym sentymencienegative_repeated.template- odpowiedź na powtarzające się wiadomości o negatywnym sentymenciepositive_very.template- odpowiedź na wiadomości o bardzo pozytywnym sentymenciepositive.template- odpowiedź na wiadomości o pozytywnym sentymenciefirst_contact.template- odpowiedź na pierwszą wiadomość od nadawcyfrequent_sender.template- odpowiedź dla częstych nadawców
Szablony mogą zawierać następujące placeholdery, które są zastępowane rzeczywistymi danymi:
{{SENDER_NAME}}- imię nadawcy (ekstrahowane z adresu email){{SUBJECT}}- temat wiadomości{{CURRENT_DATE}}- bieżąca data{{SENTIMENT}}- sentyment wiadomości w języku polskim{{URGENCY}}- pilność wiadomości w języku polskim{{SUMMARY}}- krótkie podsumowanie treści wiadomości{{EMAIL_COUNT}}- liczba wiadomości otrzymanych od tego nadawcy{{LAST_EMAIL_DATE}}- data ostatniej wiadomości od tego nadawcy
Szanowny/a {{SENDER_NAME}},
Dziękujemy za Twoją wiadomość dotyczącą: "{{SUBJECT}}".
Doceniamy Twoją lojalność i częsty kontakt z nami. Jako nasz stały klient, Twoja sprawa zostanie rozpatrzona priorytetowo.
To już Twoja {{EMAIL_COUNT}}. wiadomość do nas. Ostatnio kontaktowałeś/aś się z nami {{LAST_EMAIL_DATE}}.
Z poważaniem,
Zespół Obsługi Klienta
Wybór odpowiedniego szablonu odbywa się na podstawie następujących kryteriów:
- Pilność wiadomości (CRITICAL, HIGH, NORMAL, LOW)
- Sentyment wiadomości (VERY_NEGATIVE, NEGATIVE, NEUTRAL, POSITIVE, VERY_POSITIVE)
- Historia komunikacji z nadawcą (pierwszy kontakt, częsty nadawca, powtarzające się skargi)
Algorytm wyboru szablonu jest zaimplementowany w metodzie selectTemplateKey() klasy AdvancedReplyService.
System automatycznie archiwizuje wszystkie otrzymane wiadomości email do plików tekstowych w celu:
- Zachowania pełnej historii komunikacji
- Umożliwienia dostępu do wiadomości nawet w przypadku awarii bazy danych
- Ułatwienia analizy wiadomości przez inne narzędzia
Zarchiwizowane wiadomości są przechowywane w katalogu data/archive/ w postaci plików tekstowych. Nazwy plików zawierają timestamp oraz adres nadawcy, co umożliwia łatwe wyszukiwanie wiadomości.
Każdy plik archiwalny zawiera:
- Nagłówki wiadomości (From, To, Subject, Received, Status)
- Pustą linię
- Pełną treść wiadomości
Przykład:
From: user@example.com
To: test@example.com
Subject: Zapytanie o produkt
Received: 2025-05-19T22:27:10+02:00
Status: RECEIVED
Dzień dobry,
Mam pytanie dotyczące Waszego produktu XYZ.
Czy jest on dostępny w kolorze niebieskim?
Pozdrawiam,
Jan Kowalski
Aplikacja używa następującego promptu do analizy tonu wiadomości:
Przeanalizuj poniższą wiadomość email i podaj:
1. Ogólny sentyment (VERY_NEGATIVE, NEGATIVE, NEUTRAL, POSITIVE, VERY_POSITIVE)
2. Główne emocje (ANGER, FEAR, HAPPINESS, SADNESS, SURPRISE, DISGUST, NEUTRAL) z wartościami od 0 do 1
3. Pilność (LOW, NORMAL, HIGH, CRITICAL)
4. Formalność (VERY_INFORMAL, INFORMAL, NEUTRAL, FORMAL, VERY_FORMAL)
5. Główne tematy (lista słów kluczowych)
6. Krótkie podsumowanie treści
Odpowiedź podaj w formacie JSON.
Wiadomość:
[TREŚĆ WIADOMOŚCI]
Oczekiwany format odpowiedzi od modelu LLM:
{
"sentiment": "NEUTRAL",
"emotions": {
"NEUTRAL": 0.8,
"HAPPINESS": 0.2
},
"urgency": "NORMAL",
"formality": "NEUTRAL",
"topTopics": ["zapytanie", "informacja"],
"summaryText": "Wiadomość zawiera ogólne zapytanie o informacje."
}Po uruchomieniu aplikacji z Docker Compose, można testować ją przy użyciu MailHog:
- Otwórz interfejs MailHog pod adresem http://localhost:8025
- Wyślij testową wiadomość e-mail na adres skonfigurowany w zmiennych środowiskowych (domyślnie test@example.com)
- Aplikacja powinna odebrać wiadomość, przetworzyć ją i wysłać automatyczną odpowiedź (jeśli spełnione są kryteria)
- Sprawdź w MailHog czy otrzymałeś odpowiedź
Aplikacja zawiera dwa skrypty testowe:
./test-email.sh [positive|negative|urgent|neutral]
Gdzie:
positive- Wysyła wiadomość o pozytywnym tonienegative- Wysyła wiadomość o negatywnym tonieurgent- Wysyła pilną wiadomośćneutral- Wysyła neutralne zapytanie
./test-advanced-reply.sh [frequent|negative|urgent|new]
Gdzie:
frequent- Symuluje odpowiedź dla częstego nadawcynegative- Symuluje odpowiedź dla nadawcy z negatywnym sentymentemurgent- Symuluje odpowiedź dla pilnej wiadomościnew- Symuluje odpowiedź dla nowego nadawcy
Ten skrypt tworzy przykładową bazę danych SQLite z historią komunikacji oraz pliki szablonów, a następnie demonstruje, jak system wybiera odpowiedni szablon i generuje spersonalizowaną odpowiedź.
Aby dodać nową trasę Camel:
- Utwórz nową klasę implementującą RouteBuilder w katalogu
src/main/kotlin/com/emailprocessor/routes/ - Zaimplementuj metodę
configure() - Zarejestruj trasę w
Main.ktdodając ją docamelMain.configure().addRoutesBuilder()
Aby dostosować analizę LLM:
- Zmodyfikuj prompt w metodzie
createAnalysisPrompt()w klasieLlmService.kt - Dostosuj parsowanie odpowiedzi w metodzie
parseAnalysisResponse() - Rozszerz model
ToneAnalysis.kto dodatkowe pola, jeśli są potrzebne
Aby dostosować system szablonów:
- Dodaj nowe pliki szablonów w katalogu
data/templates/z rozszerzeniem.template - Zmodyfikuj logikę wyboru szablonu w metodzie
selectTemplateKey()w klasieAdvancedReplyService.kt - Dodaj nowe placeholdery w metodzie
fillTemplate()w klasieAdvancedReplyService.kt
Aby dostosować system archiwizacji wiadomości:
- Zmodyfikuj metodę
archiveEmail()w klasieEmailService.kt - Dostosuj format pliku archiwalnego według potrzeb
Aby dodać nowe funkcjonalności:
- Rozszerz istniejące serwisy lub dodaj nowe w katalogu
services/ - Dodaj nowe modele danych w katalogu
model/jeśli są potrzebne - Zaktualizuj trasy Camel, aby wykorzystywały nowe funkcjonalności
Jeśli aplikacja nie może połączyć się z serwerem email:
- Sprawdź, czy serwer email jest uruchomiony i dostępny
- Sprawdź, czy dane dostępowe (host, port, użytkownik, hasło) są poprawne
- Sprawdź, czy firewall nie blokuje połączenia
Jeśli analiza LLM nie działa poprawnie:
- Sprawdź, czy serwer Ollama jest uruchomiony i dostępny
- Sprawdź, czy model językowy jest poprawnie załadowany
- Sprawdź logi serwera Ollama w poszukiwaniu błędów
Jeśli system szablonów nie działa poprawnie:
- Sprawdź, czy katalog
data/templates/istnieje i zawiera pliki szablonów - Sprawdź, czy pliki szablonów mają poprawny format i rozszerzenie
.template - Sprawdź, czy placeholdery w szablonach są poprawnie sformatowane (np.
{{SENDER_NAME}})
Jeśli archiwizacja wiadomości nie działa poprawnie:
- Sprawdź, czy katalog
data/archive/istnieje i czy aplikacja ma uprawnienia do zapisu - Sprawdź, czy jest wystarczająco dużo miejsca na dysku
- Sprawdź logi aplikacji w poszukiwaniu błędów związanych z zapisem plików
Jeśli występują problemy z bazą danych:
- Sprawdź, czy ścieżka do bazy danych jest poprawna
- Sprawdź, czy aplikacja ma uprawnienia do zapisu w katalogu bazy danych
- Sprawdź, czy schemat bazy danych jest poprawny
Aby debugować aplikację:
- Uruchom aplikację z większym poziomem logowania:
./gradlew run --info - Sprawdź logi w poszukiwaniu błędów
- Użyj narzędzia Adminer do sprawdzenia zawartości bazy danych