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) }