add main.go
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,7 +2,7 @@
|
|||||||
config.yaml
|
config.yaml
|
||||||
|
|
||||||
# Binary
|
# Binary
|
||||||
paraclub-ai-mailer
|
./paraclub-ai-mailer
|
||||||
|
|
||||||
# Log files
|
# Log files
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
172
cmd/paraclub-ai-mailer/main.go
Normal file
172
cmd/paraclub-ai-mailer/main.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"paraclub-ai-mailer/config"
|
||||||
|
"paraclub-ai-mailer/internal/ai"
|
||||||
|
"paraclub-ai-mailer/internal/fetcher"
|
||||||
|
"paraclub-ai-mailer/internal/imap"
|
||||||
|
"paraclub-ai-mailer/internal/logger"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
configPath := flag.String("config", "config.yaml", "Path to configuration file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
logger.Debug("Loading configuration from:", *configPath)
|
||||||
|
cfg, err := config.Load(*configPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("Failed to load configuration")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"logLevel": cfg.Logging.Level,
|
||||||
|
"logFile": cfg.Logging.FilePath,
|
||||||
|
}).Debug("Configuration loaded successfully")
|
||||||
|
|
||||||
|
// Initialize logger
|
||||||
|
if err := logger.Init(cfg.Logging.Level, cfg.Logging.FilePath); err != nil {
|
||||||
|
logger.WithError(err).Error("Failed to initialize logger")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logger.Debug("Logger initialized successfully")
|
||||||
|
|
||||||
|
// Initialize components
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"server": cfg.IMAP.Server,
|
||||||
|
"port": cfg.IMAP.Port,
|
||||||
|
"username": cfg.IMAP.Username,
|
||||||
|
"mailboxIn": cfg.IMAP.MailboxIn,
|
||||||
|
}).Debug("Initializing IMAP client")
|
||||||
|
|
||||||
|
imapClient, err := imap.New(cfg.IMAP)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("Failed to initialize IMAP client")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer imapClient.Close()
|
||||||
|
|
||||||
|
fetcher := fetcher.New()
|
||||||
|
aiProcessor := ai.New(cfg.AI)
|
||||||
|
logger.Debug("All components initialized successfully")
|
||||||
|
|
||||||
|
// Setup signal handling for graceful shutdown
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
done := make(chan bool, 1)
|
||||||
|
logger.Debug("Signal handlers configured")
|
||||||
|
|
||||||
|
// Start processing loop
|
||||||
|
logger.WithField("pollingInterval", cfg.Polling.Interval).Info("Starting email processing loop")
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(cfg.Polling.Interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
logger.Debug("Received shutdown signal in processing loop")
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
logger.Debug("Processing tick started")
|
||||||
|
processEmails(imapClient, fetcher, aiProcessor, cfg)
|
||||||
|
logger.Debug("Processing tick completed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for shutdown signal
|
||||||
|
sig := <-sigChan
|
||||||
|
logger.WithField("signal", sig.String()).Info("Received shutdown signal")
|
||||||
|
done <- true
|
||||||
|
logger.Info("Application shutdown complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
func processEmails(imapClient *imap.IMAPClient, fetcher *fetcher.Fetcher, aiProcessor *ai.AI, cfg *config.Config) {
|
||||||
|
logger.Debug("Starting email processing cycle")
|
||||||
|
|
||||||
|
// Fetch unprocessed emails
|
||||||
|
emails, err := imapClient.FetchUnprocessedEmails()
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("Failed to fetch emails")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.WithField("emailCount", len(emails)).Debug("Fetched unprocessed emails")
|
||||||
|
|
||||||
|
if len(emails) == 0 {
|
||||||
|
logger.Debug("No new emails to process")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch context from configured URLs
|
||||||
|
logger.WithField("urlCount", len(cfg.Context.URLs)).Debug("Fetching context from configured URLs")
|
||||||
|
contextContent, err := fetcher.FetchAllURLs(cfg.Context.URLs)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("Failed to fetch context content")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.WithField("contextCount", len(contextContent)).Debug("Successfully fetched context content")
|
||||||
|
|
||||||
|
// Process each email
|
||||||
|
var processedCount, errorCount int
|
||||||
|
for _, email := range emails {
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"subject": email.Subject,
|
||||||
|
"from": email.From,
|
||||||
|
"messageId": email.ID,
|
||||||
|
}).Info("Processing email")
|
||||||
|
|
||||||
|
// Generate AI response
|
||||||
|
response, err := aiProcessor.GenerateReply(email.Body, contextContent)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"subject": email.Subject,
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to generate reply")
|
||||||
|
errorCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.WithField("responseLength", len(response)).Debug("Generated AI response")
|
||||||
|
|
||||||
|
// Save as draft
|
||||||
|
if err := imapClient.SaveDraft(email, response); err != nil {
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"subject": email.Subject,
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to save draft")
|
||||||
|
errorCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.Debug("Saved response as draft")
|
||||||
|
|
||||||
|
// Mark email as processed
|
||||||
|
if err := imapClient.MarkAsProcessed(email); err != nil {
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"subject": email.Subject,
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to mark email as processed")
|
||||||
|
errorCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
processedCount++
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"subject": email.Subject,
|
||||||
|
"from": email.From,
|
||||||
|
}).Info("Successfully processed email")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.WithFields(logrus.Fields{
|
||||||
|
"totalEmails": len(emails),
|
||||||
|
"processed": processedCount,
|
||||||
|
"errors": errorCount,
|
||||||
|
}).Info("Completed email processing cycle")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user