79 lines
1.7 KiB
Go
79 lines
1.7 KiB
Go
// ©AngelaMos | 2026
|
|
// openai.go
|
|
|
|
package ai
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
openAIChatPath = "/chat/completions"
|
|
roleSystem = "system"
|
|
roleUser = "user"
|
|
headerAuth = "Authorization"
|
|
bearerPrefix = "Bearer "
|
|
)
|
|
|
|
type openAICompat struct {
|
|
name string
|
|
http *http.Client
|
|
baseURL string
|
|
model string
|
|
apiKey string
|
|
}
|
|
|
|
func newOpenAICompat(name string, client *http.Client, baseURL, model, apiKey string) *openAICompat {
|
|
return &openAICompat{
|
|
name: name,
|
|
http: client,
|
|
baseURL: strings.TrimRight(baseURL, "/"),
|
|
model: model,
|
|
apiKey: apiKey,
|
|
}
|
|
}
|
|
|
|
func (c *openAICompat) Name() string { return c.name }
|
|
|
|
type openAIMessage struct {
|
|
Role string `json:"role"`
|
|
Content string `json:"content"`
|
|
}
|
|
|
|
type openAIRequest struct {
|
|
Model string `json:"model"`
|
|
Messages []openAIMessage `json:"messages"`
|
|
}
|
|
|
|
type openAIResponse struct {
|
|
Choices []struct {
|
|
Message openAIMessage `json:"message"`
|
|
} `json:"choices"`
|
|
}
|
|
|
|
func (c *openAICompat) Generate(ctx context.Context, req IdeationRequest) (IdeationResult, error) {
|
|
system, user := buildPrompt(req)
|
|
body := openAIRequest{
|
|
Model: c.model,
|
|
Messages: []openAIMessage{
|
|
{Role: roleSystem, Content: system},
|
|
{Role: roleUser, Content: user},
|
|
},
|
|
}
|
|
header := http.Header{}
|
|
if c.apiKey != "" {
|
|
header.Set(headerAuth, bearerPrefix+c.apiKey)
|
|
}
|
|
var resp openAIResponse
|
|
if err := postJSON(ctx, c.http, c.baseURL+openAIChatPath, header, body, &resp); err != nil {
|
|
return IdeationResult{}, err
|
|
}
|
|
if len(resp.Choices) == 0 {
|
|
return IdeationResult{}, fmt.Errorf("ai: %s returned no choices", c.name)
|
|
}
|
|
return parseResult(resp.Choices[0].Message.Content)
|
|
}
|