Files
ai-mailer/internal/ai/ai.go

111 lines
2.9 KiB
Go

package ai
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"paraclub-ai-mailer/config"
)
type AI struct {
config config.AIConfig
client *http.Client
}
type OpenRouterRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
Temperature float32 `json:"temperature"`
MaxTokens int `json:"max_tokens"`
}
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type OpenRouterResponse struct {
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
}
func New(cfg config.AIConfig) *AI {
return &AI{
config: cfg,
client: &http.Client{},
}
}
func (a *AI) GenerateReply(emailContent string, contextContent map[string]string) (string, error) {
// Prepare context from all URLs
var context string
for url, content := range contextContent {
context += fmt.Sprintf("\nContext from %s:\n%s\n", url, content)
}
// Prepare the system message and user message
systemMsg := "You are a helpful assistant responding to emails. Analyze the language of the incoming email and translate the response to the same language. Format your response in HTML. Do not include any explanations or extra text - just write the email response directly in HTML format. Use appropriate HTML tags for formatting."
userMsg := fmt.Sprintf("Using the following context:\n%s\n\nPlease analyze the language of and generate a reply in the same language for this email:\n%s", context, emailContent)
messages := []Message{
{Role: "system", Content: systemMsg},
{Role: "user", Content: userMsg},
}
const maxRetries = 3
var lastErr error
for attempt := 0; attempt < maxRetries; attempt++ {
reqBody := OpenRouterRequest{
Model: a.config.Model,
Messages: messages,
Temperature: a.config.Temperature,
MaxTokens: a.config.MaxTokens,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", "https://openrouter.ai/api/v1/chat/completions", bytes.NewBuffer(jsonData))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", a.config.OpenRouterAPIKey))
resp, err := a.client.Do(req)
if err != nil {
lastErr = err
continue
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
lastErr = fmt.Errorf("OpenRouter API returned status code: %d", resp.StatusCode)
continue
}
var result OpenRouterResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
lastErr = err
continue
}
if len(result.Choices) == 0 || result.Choices[0].Message.Content == "" {
lastErr = fmt.Errorf("empty response received")
continue
}
return result.Choices[0].Message.Content, nil
}
return "", fmt.Errorf("failed after %d attempts, last error: %v", maxRetries, lastErr)
}