feat(cover): request chatgpt to fill out template
This commit is contained in:
@@ -3,6 +3,7 @@ package cover
|
|||||||
import (
|
import (
|
||||||
"backend/models/template"
|
"backend/models/template"
|
||||||
"backend/utils"
|
"backend/utils"
|
||||||
|
"backend/utils/chatgpt"
|
||||||
"backend/utils/jwt"
|
"backend/utils/jwt"
|
||||||
res "backend/utils/responses"
|
res "backend/utils/responses"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -43,9 +44,20 @@ func Post(c *gin.Context) {
|
|||||||
return
|
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) {
|
func Put(c *gin.Context) {
|
||||||
|
|||||||
@@ -1 +1,86 @@
|
|||||||
package chatgpt
|
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 <company>, <experience>, 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
)
|
)
|
||||||
@@ -10,20 +8,12 @@ import (
|
|||||||
var validate = validator.New()
|
var validate = validator.New()
|
||||||
|
|
||||||
func BindAndValidate(data any, c *gin.Context) error {
|
func BindAndValidate(data any, c *gin.Context) error {
|
||||||
fmt.Println("🔍 BindAndValidate called")
|
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(data); err != nil {
|
if err := c.ShouldBindJSON(data); err != nil {
|
||||||
fmt.Println("❌ Bind error:", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Bind success:", data)
|
|
||||||
|
|
||||||
if err := validate.Struct(data); err != nil {
|
if err := validate.Struct(data); err != nil {
|
||||||
fmt.Println("❌ Validation error:", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Validation success")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user