diff --git a/backend/controllers/cover/cover.go b/backend/controllers/cover/cover.go index 170aecb..8a196a8 100644 --- a/backend/controllers/cover/cover.go +++ b/backend/controllers/cover/cover.go @@ -3,6 +3,7 @@ package cover import ( "backend/models/template" "backend/utils" + "backend/utils/chatgpt" "backend/utils/jwt" res "backend/utils/responses" "net/http" @@ -43,9 +44,20 @@ func Post(c *gin.Context) { return } - // Call chat and ask for cover letter nicely + // Check if template exists + if len(templates) == 0 { + res.Error(c, "Template not found", http.StatusNotFound) + return + } - res.Success(c, templates) + // Call chat and ask for cover letter nicely + coverLetter, err := chatgpt.GenerateCoverLetter(templates[0].Template, data.Application) + if err != nil { + res.Error(c, err.Error(), http.StatusInternalServerError) + return + } + + res.Success(c, coverLetter) } func Put(c *gin.Context) { diff --git a/backend/utils/chatgpt/chatgpt.go b/backend/utils/chatgpt/chatgpt.go index 336a9b0..eb4df45 100644 --- a/backend/utils/chatgpt/chatgpt.go +++ b/backend/utils/chatgpt/chatgpt.go @@ -1 +1,86 @@ package chatgpt + +import ( + "backend/config" + "bytes" + "encoding/json" + "errors" + "fmt" + "net/http" + "time" +) + +type ChatRequest struct { + Model string `json:"model"` + Messages []ChatMessage `json:"messages"` +} + +type ChatMessage struct { + Role string `json:"role"` + Content string `json:"content"` +} + +func GenerateCoverLetter(templateHTML string, jobHTML string) (string, error) { + apiKey := config.Env["CHATGPT_KEY"] + if apiKey == "" { + return "", errors.New("no API key chat gpt provided") + } + + payload := ChatRequest{ + Model: "gpt-4o", // o4-mini + Messages: []ChatMessage{ + { + Role: "system", + Content: `You are a helpful assistant that fills out cover letter templates in HTML format. Replace all <...> tags like , , etc., with appropriate content based on the job application.`, + }, + { + Role: "user", + Content: fmt.Sprintf(`Template: +%s + +Job description: +%s + +Respond with ONLY the filled HTML cover letter.`, templateHTML, jobHTML), + }, + }, + } + + body, err := json.Marshal(payload) + if err != nil { + return "", err + } + + req, err := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", bytes.NewBuffer(body)) + if err != nil { + return "", err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+apiKey) + + client := &http.Client{Timeout: 20 * time.Second} + res, err := client.Do(req) + if err != nil { + return "", err + } + defer res.Body.Close() + + var result struct { + Choices []struct { + Message struct { + Content string `json:"content"` + } `json:"message"` + } `json:"choices"` + } + + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + return "", err + } + + if len(result.Choices) == 0 { + return "", fmt.Errorf("no response from GPT") + } + + return result.Choices[0].Message.Content, nil +} diff --git a/backend/utils/checkData.go b/backend/utils/checkData.go index 0ee8dae..d1cdaec 100644 --- a/backend/utils/checkData.go +++ b/backend/utils/checkData.go @@ -1,8 +1,6 @@ package utils import ( - "fmt" - "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" ) @@ -10,20 +8,12 @@ import ( var validate = validator.New() func BindAndValidate(data any, c *gin.Context) error { - fmt.Println("🔍 BindAndValidate called") - if err := c.ShouldBindJSON(data); err != nil { - fmt.Println("❌ Bind error:", err) return err } - fmt.Println("✅ Bind success:", data) - if err := validate.Struct(data); err != nil { - fmt.Println("❌ Validation error:", err) return err } - - fmt.Println("✅ Validation success") return nil }