mirror of
https://github.com/ManyakRus/starter.git
synced 2025-11-26 23:10:42 +02:00
сделал chatgpt_proxy
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/ManyakRus/starter/logger"
|
||||
"github.com/rugatling/go-openai"
|
||||
"time"
|
||||
|
||||
//"github.com/jackc/pgconn"
|
||||
@@ -192,11 +193,19 @@ func SendMessage(Text string, user string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctxMain, 600*time.Second)
|
||||
defer cancel()
|
||||
|
||||
Messages := []gogpt.ChatCompletionMessage{
|
||||
{
|
||||
Name: user,
|
||||
Content: Text,
|
||||
Role: openai.ChatMessageRoleSystem,
|
||||
},
|
||||
}
|
||||
|
||||
req := gogpt.ChatCompletionRequest{
|
||||
Model: gogpt.GPT4o, //надо gogpt.GPT3TextDavinci003
|
||||
MaxTokens: 2048,
|
||||
//Prompt: Text,
|
||||
User: user,
|
||||
Messages: Messages,
|
||||
User: user,
|
||||
}
|
||||
resp, err := Conn.CreateChatCompletion(ctx, req)
|
||||
if err != nil {
|
||||
|
||||
216
chatgpt_proxy/chatgpt_proxy.go
Normal file
216
chatgpt_proxy/chatgpt_proxy.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package chatgpt_proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/ManyakRus/starter/logger"
|
||||
"time"
|
||||
|
||||
//"github.com/jackc/pgconn"
|
||||
"os"
|
||||
"sync"
|
||||
//"time"
|
||||
|
||||
"github.com/ManyakRus/starter/contextmain"
|
||||
"github.com/ManyakRus/starter/stopapp"
|
||||
|
||||
gogpt "github.com/rugatling/go-openai"
|
||||
)
|
||||
|
||||
// Conn - соединение к CHAT GPT
|
||||
// var Conn *gogpt.CompletionStream
|
||||
var Conn *gogpt.Client
|
||||
|
||||
// log - глобальный логгер
|
||||
var log = logger.GetLog()
|
||||
|
||||
// mutexReconnect - защита от многопоточности Reconnect()
|
||||
var mutexReconnect = &sync.Mutex{}
|
||||
|
||||
// Settings хранит все нужные переменные окружения
|
||||
var Settings SettingsINI
|
||||
|
||||
// SettingsINI - структура для хранения всех нужных переменных окружения
|
||||
type SettingsINI struct {
|
||||
CHATGPT_API_KEY string
|
||||
CHATGPT_NAME string
|
||||
CHATGPT_START_TEXT string
|
||||
CHATGPT_END_TEXT string
|
||||
CHATGPT_PROXY_API_URL string
|
||||
CHATGPT_PROXY_API_KEY string
|
||||
}
|
||||
|
||||
// Connect_err - подключается к базе данных
|
||||
func Connect() {
|
||||
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
log.Panicln("ChatGPT Connect_err() api_key: ", Settings.CHATGPT_API_KEY, " Error: ", err)
|
||||
} else {
|
||||
log.Info("ChatGPT connected. api_key: ", Settings.CHATGPT_API_KEY)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Connect_err - подключается к базе данных
|
||||
func Connect_err() error {
|
||||
var err error
|
||||
|
||||
if Settings.CHATGPT_API_KEY == "" {
|
||||
FillSettings()
|
||||
}
|
||||
|
||||
if Settings.CHATGPT_PROXY_API_KEY != "" {
|
||||
config := gogpt.DefaultConfig(Settings.CHATGPT_PROXY_API_KEY)
|
||||
config.BaseURL = Settings.CHATGPT_PROXY_API_URL
|
||||
Conn = gogpt.NewClientWithConfig(config)
|
||||
} else {
|
||||
Conn = gogpt.NewClient(Settings.CHATGPT_API_KEY)
|
||||
}
|
||||
|
||||
//req := gogpt.CompletionRequest{
|
||||
// Model: gogpt.GPT3Ada,
|
||||
// MaxTokens: 5,
|
||||
// Prompt: Settings.CHATGPT_NAME,
|
||||
// Stream: true,
|
||||
//}
|
||||
|
||||
//ctx := contextmain.GetContext()
|
||||
//stream, err := Conn.CreateCompletionStream(ctx, req)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// CloseConnection - закрытие соединения с базой данных
|
||||
func CloseConnection() error {
|
||||
if Conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := CloseConnection_err()
|
||||
if err != nil {
|
||||
log.Error("ChatGPT CloseConnection() error: ", err)
|
||||
} else {
|
||||
log.Debug("ChatGPT connection closed")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// CloseConnection - закрытие соединения с базой данных
|
||||
func CloseConnection_err() error {
|
||||
var err error
|
||||
if Conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
//ctx := contextmain.GetContext()
|
||||
//ctx := context.Background()
|
||||
//Conn.Close()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitStop - ожидает отмену глобального контекста
|
||||
func WaitStop() {
|
||||
|
||||
select {
|
||||
case <-contextmain.GetContext().Done():
|
||||
log.Warn("Context app is canceled.")
|
||||
}
|
||||
|
||||
//
|
||||
stopapp.WaitTotalMessagesSendingNow("ChatGPT")
|
||||
|
||||
//
|
||||
err := CloseConnection()
|
||||
if err != nil {
|
||||
log.Error("CloseConnection() error: ", err)
|
||||
}
|
||||
stopapp.GetWaitGroup_Main().Done()
|
||||
}
|
||||
|
||||
// Start - делает соединение с БД, отключение и др.
|
||||
func Start() {
|
||||
Connect()
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go WaitStop()
|
||||
|
||||
}
|
||||
|
||||
// FillSettings загружает переменные окружения в структуру из файла или из переменных окружения
|
||||
func FillSettings() {
|
||||
Settings = SettingsINI{}
|
||||
Settings.CHATGPT_API_KEY = os.Getenv("CHATGPT_API_KEY")
|
||||
Settings.CHATGPT_NAME = os.Getenv("CHATGPT_NAME")
|
||||
Settings.CHATGPT_START_TEXT = os.Getenv("CHATGPT_START_TEXT")
|
||||
Settings.CHATGPT_END_TEXT = os.Getenv("CHATGPT_END_TEXT")
|
||||
Settings.CHATGPT_PROXY_API_URL = os.Getenv("CHATGPT_PROXY_API_URL")
|
||||
Settings.CHATGPT_PROXY_API_KEY = os.Getenv("CHATGPT_PROXY_API_KEY")
|
||||
if Settings.CHATGPT_API_KEY == "" {
|
||||
log.Panicln("Need fill CHATGPT_API_KEY ! in os .env ")
|
||||
}
|
||||
if Settings.CHATGPT_NAME == "" {
|
||||
log.Warnln("Need fill CHATGPT_NAME ! in os .env ")
|
||||
}
|
||||
if Settings.CHATGPT_START_TEXT == "" {
|
||||
//log.Warnln("Need fill CHATGPT_NAME ! in os .env ")
|
||||
}
|
||||
if Settings.CHATGPT_END_TEXT == "" {
|
||||
//log.Warnln("Need fill CHATGPT_NAME ! in os .env ")
|
||||
}
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
func SendMessage(Text string, user string) (string, error) {
|
||||
var Otvet = ""
|
||||
var err error
|
||||
|
||||
if Conn == nil {
|
||||
Connect()
|
||||
}
|
||||
|
||||
if Settings.CHATGPT_START_TEXT != "" {
|
||||
Text = Settings.CHATGPT_START_TEXT + Text
|
||||
}
|
||||
|
||||
if Settings.CHATGPT_END_TEXT != "" {
|
||||
Text = Text + Settings.CHATGPT_END_TEXT
|
||||
}
|
||||
|
||||
ctxMain := context.Background()
|
||||
ctx, cancel := context.WithTimeout(ctxMain, 600*time.Second)
|
||||
defer cancel()
|
||||
|
||||
Messages := []gogpt.ChatCompletionMessage{
|
||||
{
|
||||
Role: gogpt.ChatMessageRoleSystem,
|
||||
Content: Text,
|
||||
},
|
||||
}
|
||||
|
||||
req := gogpt.ChatCompletionRequest{
|
||||
Model: gogpt.GPT4o,
|
||||
MaxTokens: 2048,
|
||||
Messages: Messages,
|
||||
User: user,
|
||||
}
|
||||
resp, err := Conn.CreateChatCompletion(ctx, req)
|
||||
if err != nil {
|
||||
log.Debug("ChatGPT CreateChatCompletion() error: ", err)
|
||||
return Otvet, err
|
||||
}
|
||||
|
||||
if len(resp.Choices) > 0 {
|
||||
Otvet = resp.Choices[0].Message.Content
|
||||
} else {
|
||||
err = errors.New("error: no response")
|
||||
}
|
||||
|
||||
return Otvet, err
|
||||
}
|
||||
72
chatgpt_proxy/chatgpt_proxy_test.go
Normal file
72
chatgpt_proxy/chatgpt_proxy_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package chatgpt_proxy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
//log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/ManyakRus/starter/config_main"
|
||||
"github.com/ManyakRus/starter/contextmain"
|
||||
"github.com/ManyakRus/starter/micro"
|
||||
|
||||
// logger "github.com/ManyakRus/starter/common/v0/logger"
|
||||
"github.com/ManyakRus/starter/stopapp"
|
||||
)
|
||||
|
||||
func TestConnect_err(t *testing.T) {
|
||||
//Connect_Panic()
|
||||
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
err := Connect_err()
|
||||
if err != nil {
|
||||
t.Error("TestConnect error: ", err)
|
||||
}
|
||||
|
||||
err = CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("TestConnect() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitStop(t *testing.T) {
|
||||
stopapp.StartWaitStop()
|
||||
|
||||
stopapp.GetWaitGroup_Main().Add(1)
|
||||
go WaitStop()
|
||||
|
||||
micro.Pause(10)
|
||||
|
||||
//stopapp.SignalInterrupt <- syscall.SIGINT
|
||||
contextmain.CancelContext()
|
||||
}
|
||||
|
||||
func TestStartDB(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
Start()
|
||||
err := CloseConnection_err()
|
||||
if err != nil {
|
||||
t.Error("chatgpt_connect_test.TestStart() CloseConnection() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnect(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
Connect()
|
||||
|
||||
CloseConnection()
|
||||
}
|
||||
|
||||
func TestSendMessage(t *testing.T) {
|
||||
//ProgramDir := micro.ProgramDir_Common()
|
||||
config_main.LoadEnv()
|
||||
|
||||
Text := "Is ChatGPT enabled now ?"
|
||||
Otvet, err := SendMessage(Text, "")
|
||||
if err != nil {
|
||||
t.Error("chatgpt_connect_test.TestSendMessage() error: ", err)
|
||||
}
|
||||
t.Log("chatgpt_connect_test.TestSendMessage() Otvet: ", Otvet)
|
||||
}
|
||||
1
go.mod
1
go.mod
@@ -77,6 +77,7 @@ require (
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rs/xid v1.5.0 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/rugatling/go-openai v0.0.0-20240602200622-19edf07d0a97 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -204,6 +204,8 @@ github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rugatling/go-openai v0.0.0-20240602200622-19edf07d0a97 h1:uZgYgoIP234Q1yPHV5uQPM0ZkhjKinT8VQafdDarvqU=
|
||||
github.com/rugatling/go-openai v0.0.0-20240602200622-19edf07d0a97/go.mod h1:D2GUNPklB0S39CynQAH+f09YMMvhGhi/pqc58PXnPPU=
|
||||
github.com/sashabaranov/go-openai v1.24.1 h1:DWK95XViNb+agQtuzsn+FyHhn3HQJ7Va8z04DQDJ1MI=
|
||||
github.com/sashabaranov/go-openai v1.24.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
|
||||
19
vendor/github.com/rugatling/go-openai/.gitignore
generated
vendored
Normal file
19
vendor/github.com/rugatling/go-openai/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Auth token for tests
|
||||
.openai-token
|
||||
.idea
|
||||
272
vendor/github.com/rugatling/go-openai/.golangci.yml
generated
vendored
Normal file
272
vendor/github.com/rugatling/go-openai/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
## Golden config for golangci-lint v1.47.3
|
||||
#
|
||||
# This is the best config for golangci-lint based on my experience and opinion.
|
||||
# It is very strict, but not extremely strict.
|
||||
# Feel free to adopt and change it for your needs.
|
||||
|
||||
run:
|
||||
# Timeout for analysis, e.g. 30s, 5m.
|
||||
# Default: 1m
|
||||
timeout: 3m
|
||||
|
||||
|
||||
# This file contains only configs which differ from defaults.
|
||||
# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
|
||||
linters-settings:
|
||||
cyclop:
|
||||
# The maximal code complexity to report.
|
||||
# Default: 10
|
||||
max-complexity: 30
|
||||
# The maximal average package complexity.
|
||||
# If it's higher than 0.0 (float) the check is enabled
|
||||
# Default: 0.0
|
||||
package-average: 10.0
|
||||
|
||||
errcheck:
|
||||
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
|
||||
# Such cases aren't reported by default.
|
||||
# Default: false
|
||||
check-type-assertions: true
|
||||
|
||||
funlen:
|
||||
# Checks the number of lines in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 60
|
||||
lines: 100
|
||||
# Checks the number of statements in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 40
|
||||
statements: 50
|
||||
|
||||
gocognit:
|
||||
# Minimal code complexity to report
|
||||
# Default: 30 (but we recommend 10-20)
|
||||
min-complexity: 20
|
||||
|
||||
gocritic:
|
||||
# Settings passed to gocritic.
|
||||
# The settings key is the name of a supported gocritic checker.
|
||||
# The list of supported checkers can be find in https://go-critic.github.io/overview.
|
||||
settings:
|
||||
captLocal:
|
||||
# Whether to restrict checker to params only.
|
||||
# Default: true
|
||||
paramsOnly: false
|
||||
underef:
|
||||
# Whether to skip (*x).method() calls where x is a pointer receiver.
|
||||
# Default: true
|
||||
skipRecvDeref: false
|
||||
|
||||
gomnd:
|
||||
# List of function patterns to exclude from analysis.
|
||||
# Values always ignored: `time.Date`
|
||||
# Default: []
|
||||
ignored-functions:
|
||||
- os.Chmod
|
||||
- os.Mkdir
|
||||
- os.MkdirAll
|
||||
- os.OpenFile
|
||||
- os.WriteFile
|
||||
- prometheus.ExponentialBuckets
|
||||
- prometheus.ExponentialBucketsRange
|
||||
- prometheus.LinearBuckets
|
||||
- strconv.FormatFloat
|
||||
- strconv.FormatInt
|
||||
- strconv.FormatUint
|
||||
- strconv.ParseFloat
|
||||
- strconv.ParseInt
|
||||
- strconv.ParseUint
|
||||
|
||||
gomodguard:
|
||||
blocked:
|
||||
# List of blocked modules.
|
||||
# Default: []
|
||||
modules:
|
||||
- github.com/golang/protobuf:
|
||||
recommendations:
|
||||
- google.golang.org/protobuf
|
||||
reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules"
|
||||
- github.com/satori/go.uuid:
|
||||
recommendations:
|
||||
- github.com/google/uuid
|
||||
reason: "satori's package is not maintained"
|
||||
- github.com/gofrs/uuid:
|
||||
recommendations:
|
||||
- github.com/google/uuid
|
||||
reason: "see recommendation from dev-infra team: https://confluence.gtforge.com/x/gQI6Aw"
|
||||
|
||||
govet:
|
||||
# Enable all analyzers.
|
||||
# Default: false
|
||||
enable-all: true
|
||||
# Disable analyzers by name.
|
||||
# Run `go tool vet help` to see all analyzers.
|
||||
# Default: []
|
||||
disable:
|
||||
- fieldalignment # too strict
|
||||
# Settings per analyzer.
|
||||
settings:
|
||||
shadow:
|
||||
# Whether to be strict about shadowing; can be noisy.
|
||||
# Default: false
|
||||
strict: true
|
||||
|
||||
nakedret:
|
||||
# Make an issue if func has more lines of code than this setting, and it has naked returns.
|
||||
# Default: 30
|
||||
max-func-lines: 0
|
||||
|
||||
nolintlint:
|
||||
# Exclude following linters from requiring an explanation.
|
||||
# Default: []
|
||||
allow-no-explanation: [ funlen, gocognit, lll ]
|
||||
# Enable to require an explanation of nonzero length after each nolint directive.
|
||||
# Default: false
|
||||
require-explanation: true
|
||||
# Enable to require nolint directives to mention the specific linter being suppressed.
|
||||
# Default: false
|
||||
require-specific: true
|
||||
|
||||
rowserrcheck:
|
||||
# database/sql is always checked
|
||||
# Default: []
|
||||
packages:
|
||||
- github.com/jmoiron/sqlx
|
||||
|
||||
tenv:
|
||||
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
|
||||
# Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
|
||||
# Default: false
|
||||
all: true
|
||||
|
||||
varcheck:
|
||||
# Check usage of exported fields and variables.
|
||||
# Default: false
|
||||
exported-fields: false # default false # TODO: enable after fixing false positives
|
||||
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
## enabled by default
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- gosimple # Linter for Go source code that specializes in simplifying a code
|
||||
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- ineffassign # Detects when assignments to existing variables are not used
|
||||
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
||||
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
|
||||
- unused # Checks Go code for unused constants, variables, functions and types
|
||||
## disabled by default
|
||||
# - asasalint # Check for pass []any as any in variadic func(...any)
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
|
||||
- bidichk # Checks for dangerous unicode character sequences
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- contextcheck # check the function whether use a non-inherited context
|
||||
- cyclop # checks function and package cyclomatic complexity
|
||||
- dupl # Tool for code clone detection
|
||||
- durationcheck # check for two durations multiplied together
|
||||
- errname # Checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error.
|
||||
- errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13.
|
||||
- execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- exportloopref # checks for pointers to enclosing loop variables
|
||||
- forbidigo # Forbids identifiers
|
||||
- funlen # Tool for detection of long functions
|
||||
# - gochecknoglobals # check that no global variables exist
|
||||
- gochecknoinits # Checks that no init functions are present in Go code
|
||||
- gocognit # Computes and checks the cognitive complexity of functions
|
||||
- goconst # Finds repeated strings that could be replaced by a constant
|
||||
- gocritic # Provides diagnostics that check for bugs, performance and style issues.
|
||||
- gocyclo # Computes and checks the cyclomatic complexity of functions
|
||||
- godot # Check if comments end in a period
|
||||
- goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt.
|
||||
- gomnd # An analyzer to detect magic numbers.
|
||||
- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.
|
||||
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
|
||||
- goprintffuncname # Checks that printf-like functions are named with f at the end
|
||||
- gosec # Inspects source code for security problems
|
||||
- lll # Reports long lines
|
||||
- makezero # Finds slice declarations with non-zero initial length
|
||||
# - nakedret # Finds naked returns in functions greater than a specified function length
|
||||
- nestif # Reports deeply nested if statements
|
||||
- nilerr # Finds the code that returns nil even if it checks that the error is not nil.
|
||||
- nilnil # Checks that there is no simultaneous return of nil error and an invalid value.
|
||||
# - noctx # noctx finds sending http request without context.Context
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives
|
||||
# - nonamedreturns # Reports all named returns
|
||||
- nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL.
|
||||
- predeclared # find code that shadows one of Go's predeclared identifiers
|
||||
- promlinter # Check Prometheus metrics naming via promlint
|
||||
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
|
||||
- rowserrcheck # checks whether Err of rows is checked successfully
|
||||
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
|
||||
- stylecheck # Stylecheck is a replacement for golint
|
||||
- tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17
|
||||
- testpackage # linter that makes you use a separate _test package
|
||||
- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes
|
||||
- unconvert # Remove unnecessary type conversions
|
||||
- unparam # Reports unused function parameters
|
||||
- wastedassign # wastedassign finds wasted assignment statements.
|
||||
- whitespace # Tool for detection of leading and trailing whitespace
|
||||
## you may want to enable
|
||||
#- decorder # check declaration order and count of types, constants, variables and functions
|
||||
#- exhaustruct # Checks if all structure fields are initialized
|
||||
#- goheader # Checks is file header matches to pattern
|
||||
#- ireturn # Accept Interfaces, Return Concrete Types
|
||||
#- prealloc # [premature optimization, but can be used in some cases] Finds slice declarations that could potentially be preallocated
|
||||
#- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope
|
||||
#- wrapcheck # Checks that errors returned from external packages are wrapped
|
||||
## disabled
|
||||
#- containedctx # containedctx is a linter that detects struct contained context.Context field
|
||||
#- depguard # [replaced by gomodguard] Go linter that checks if package imports are in a list of acceptable packages
|
||||
#- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
||||
#- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted.
|
||||
#- forcetypeassert # [replaced by errcheck] finds forced type assertions
|
||||
#- gci # Gci controls golang package import order and makes it always deterministic.
|
||||
#- godox # Tool for detection of FIXME, TODO and other comment keywords
|
||||
#- goerr113 # [too strict] Golang linter to check the errors handling expressions
|
||||
#- gofmt # [replaced by goimports] Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
#- gofumpt # [replaced by goimports, gofumports is not available yet] Gofumpt checks whether code was gofumpt-ed.
|
||||
#- grouper # An analyzer to analyze expression groups.
|
||||
#- ifshort # Checks that your code uses short syntax for if-statements whenever possible
|
||||
#- importas # Enforces consistent import aliases
|
||||
#- maintidx # maintidx measures the maintainability index of each function.
|
||||
#- misspell # [useless] Finds commonly misspelled English words in comments
|
||||
#- nlreturn # [too strict and mostly code is not more readable] nlreturn checks for a new line before return and branch statements to increase code clarity
|
||||
#- nosnakecase # Detects snake case of variable naming and function name. # TODO: maybe enable after https://github.com/sivchari/nosnakecase/issues/14
|
||||
#- paralleltest # [too many false positives] paralleltest detects missing usage of t.Parallel() method in your Go test
|
||||
#- tagliatelle # Checks the struct tags.
|
||||
#- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers
|
||||
#- wsl # [too strict and mostly code is not more readable] Whitespace Linter - Forces you to use empty lines!
|
||||
## deprecated
|
||||
#- exhaustivestruct # [deprecated, replaced by exhaustruct] Checks if all struct's fields are initialized
|
||||
#- golint # [deprecated, replaced by revive] Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
#- interfacer # [deprecated] Linter that suggests narrower interface types
|
||||
#- maligned # [deprecated, replaced by govet fieldalignment] Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
#- scopelint # [deprecated, replaced by exportloopref] Scopelint checks for unpinned variables in go programs
|
||||
|
||||
|
||||
issues:
|
||||
# Maximum count of issues with the same text.
|
||||
# Set to 0 to disable.
|
||||
# Default: 3
|
||||
max-same-issues: 50
|
||||
|
||||
exclude-rules:
|
||||
- source: "^//\\s*go:generate\\s"
|
||||
linters: [ lll ]
|
||||
- source: "(noinspection|TODO)"
|
||||
linters: [ godot ]
|
||||
- source: "//noinspection"
|
||||
linters: [ gocritic ]
|
||||
- source: "^\\s+if _, ok := err\\.\\([^.]+\\.InternalError\\); ok {"
|
||||
linters: [ errorlint ]
|
||||
- path: "_test\\.go"
|
||||
linters:
|
||||
- bodyclose
|
||||
- dupl
|
||||
- funlen
|
||||
- goconst
|
||||
- gosec
|
||||
- noctx
|
||||
- wrapcheck
|
||||
88
vendor/github.com/rugatling/go-openai/CONTRIBUTING.md
generated
vendored
Normal file
88
vendor/github.com/rugatling/go-openai/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
## Overview
|
||||
Thank you for your interest in contributing to the "Go OpenAI" project! By following this guideline, we hope to ensure that your contributions are made smoothly and efficiently. The Go OpenAI project is licensed under the [Apache 2.0 License](https://github.com/rugatling/go-openai/blob/master/LICENSE), and we welcome contributions through GitHub pull requests.
|
||||
|
||||
## Reporting Bugs
|
||||
If you discover a bug, first check the [GitHub Issues page](https://github.com/rugatling/go-openai/issues) to see if the issue has already been reported. If you're reporting a new issue, please use the "Bug report" template and provide detailed information about the problem, including steps to reproduce it.
|
||||
|
||||
## Suggesting Features
|
||||
If you want to suggest a new feature or improvement, first check the [GitHub Issues page](https://github.com/rugatling/go-openai/issues) to ensure a similar suggestion hasn't already been made. Use the "Feature request" template to provide a detailed description of your suggestion.
|
||||
|
||||
## Reporting Vulnerabilities
|
||||
If you identify a security concern, please use the "Report a security vulnerability" template on the [GitHub Issues page](https://github.com/rugatling/go-openai/issues) to share the details. This report will only be viewable to repository maintainers. You will be credited if the advisory is published.
|
||||
|
||||
## Questions for Users
|
||||
If you have questions, please utilize [StackOverflow](https://stackoverflow.com/) or the [GitHub Discussions page](https://github.com/rugatling/go-openai/discussions).
|
||||
|
||||
## Contributing Code
|
||||
There might already be a similar pull requests submitted! Please search for [pull requests](https://github.com/rugatling/go-openai/pulls) before creating one.
|
||||
|
||||
### Requirements for Merging a Pull Request
|
||||
|
||||
The requirements to accept a pull request are as follows:
|
||||
|
||||
- Features not provided by the OpenAI API will not be accepted.
|
||||
- The functionality of the feature must match that of the official OpenAI API.
|
||||
- All pull requests should be written in Go according to common conventions, formatted with `goimports`, and free of warnings from tools like `golangci-lint`.
|
||||
- Include tests and ensure all tests pass.
|
||||
- Maintain test coverage without any reduction.
|
||||
- All pull requests require approval from at least one Go OpenAI maintainer.
|
||||
|
||||
**Note:**
|
||||
The merging method for pull requests in this repository is squash merge.
|
||||
|
||||
### Creating a Pull Request
|
||||
- Fork the repository.
|
||||
- Create a new branch and commit your changes.
|
||||
- Push that branch to GitHub.
|
||||
- Start a new Pull Request on GitHub. (Please use the pull request template to provide detailed information.)
|
||||
|
||||
**Note:**
|
||||
If your changes introduce breaking changes, please prefix your pull request title with "[BREAKING_CHANGES]".
|
||||
|
||||
### Code Style
|
||||
In this project, we adhere to the standard coding style of Go. Your code should maintain consistency with the rest of the codebase. To achieve this, please format your code using tools like `goimports` and resolve any syntax or style issues with `golangci-lint`.
|
||||
|
||||
**Run goimports:**
|
||||
```
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
```
|
||||
|
||||
```
|
||||
goimports -w .
|
||||
```
|
||||
|
||||
**Run golangci-lint:**
|
||||
```
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
```
|
||||
|
||||
```
|
||||
golangci-lint run --out-format=github-actions
|
||||
```
|
||||
|
||||
### Unit Test
|
||||
Please create or update tests relevant to your changes. Ensure all tests run successfully to verify that your modifications do not adversely affect other functionalities.
|
||||
|
||||
**Run test:**
|
||||
```
|
||||
go test -v ./...
|
||||
```
|
||||
|
||||
### Integration Test
|
||||
Integration tests are requested against the production version of the OpenAI API. These tests will verify that the library is properly coded against the actual behavior of the API, and will fail upon any incompatible change in the API.
|
||||
|
||||
**Notes:**
|
||||
These tests send real network traffic to the OpenAI API and may reach rate limits. Temporary network problems may also cause the test to fail.
|
||||
|
||||
**Run integration test:**
|
||||
```
|
||||
OPENAI_TOKEN=XXX go test -v -tags=integration ./api_integration_test.go
|
||||
```
|
||||
|
||||
If the `OPENAI_TOKEN` environment variable is not available, integration tests will be skipped.
|
||||
|
||||
---
|
||||
|
||||
We wholeheartedly welcome your active participation. Let's build an amazing project together!
|
||||
201
vendor/github.com/rugatling/go-openai/LICENSE
generated
vendored
Normal file
201
vendor/github.com/rugatling/go-openai/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
35
vendor/github.com/rugatling/go-openai/Makefile
generated
vendored
Normal file
35
vendor/github.com/rugatling/go-openai/Makefile
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
##@ General
|
||||
|
||||
# The help target prints out all targets with their descriptions organized
|
||||
# beneath their categories. The categories are represented by '##@' and the
|
||||
# target descriptions by '##'. The awk commands is responsible for reading the
|
||||
# entire set of makefiles included in this invocation, looking for lines of the
|
||||
# file as xyz: ## something, and then pretty-format the target and help. Then,
|
||||
# if there's a line with ##@ something, that gets pretty-printed as a category.
|
||||
# More info on the usage of ANSI control characters for terminal formatting:
|
||||
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
|
||||
# More info on the awk command:
|
||||
# http://linuxcommand.org/lc3_adv_awk.php
|
||||
|
||||
.PHONY: help
|
||||
help: ## Display this help.
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
|
||||
##@ Development
|
||||
|
||||
.PHONY: test
|
||||
TEST_ARGS ?= -v
|
||||
TEST_TARGETS ?= ./...
|
||||
test: ## Test the Go modules within this package.
|
||||
@ echo ▶️ go test $(TEST_ARGS) $(TEST_TARGETS)
|
||||
go test $(TEST_ARGS) $(TEST_TARGETS)
|
||||
@ echo ✅ success!
|
||||
|
||||
|
||||
.PHONY: lint
|
||||
LINT_TARGETS ?= ./...
|
||||
lint: ## Lint Go code with the installed golangci-lint
|
||||
@ echo "▶️ golangci-lint run"
|
||||
golangci-lint run $(LINT_TARGETS)
|
||||
@ echo "✅ golangci-lint run"
|
||||
1
vendor/github.com/rugatling/go-openai/README.md
generated
vendored
Normal file
1
vendor/github.com/rugatling/go-openai/README.md
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
# Fork [Go OpenAI](https://github.com/sashabaranov/go-openai)
|
||||
303
vendor/github.com/rugatling/go-openai/assistant.go
generated
vendored
Normal file
303
vendor/github.com/rugatling/go-openai/assistant.go
generated
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
assistantsSuffix = "/assistants"
|
||||
assistantsFilesSuffix = "/files"
|
||||
)
|
||||
|
||||
type Assistant struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Model string `json:"model"`
|
||||
Instructions *string `json:"instructions,omitempty"`
|
||||
Tools []AssistantTool `json:"tools"`
|
||||
FileIDs []string `json:"file_ids,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type AssistantToolType string
|
||||
|
||||
const (
|
||||
AssistantToolTypeCodeInterpreter AssistantToolType = "code_interpreter"
|
||||
AssistantToolTypeRetrieval AssistantToolType = "retrieval"
|
||||
AssistantToolTypeFunction AssistantToolType = "function"
|
||||
)
|
||||
|
||||
type AssistantTool struct {
|
||||
Type AssistantToolType `json:"type"`
|
||||
Function *FunctionDefinition `json:"function,omitempty"`
|
||||
}
|
||||
|
||||
// AssistantRequest provides the assistant request parameters.
|
||||
// When modifying the tools the API functions as the following:
|
||||
// If Tools is undefined, no changes are made to the Assistant's tools.
|
||||
// If Tools is empty slice it will effectively delete all of the Assistant's tools.
|
||||
// If Tools is populated, it will replace all of the existing Assistant's tools with the provided tools.
|
||||
type AssistantRequest struct {
|
||||
Model string `json:"model"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Instructions *string `json:"instructions,omitempty"`
|
||||
Tools []AssistantTool `json:"-"`
|
||||
FileIDs []string `json:"file_ids,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON provides a custom marshaller for the assistant request to handle the API use cases
|
||||
// If Tools is nil, the field is omitted from the JSON.
|
||||
// If Tools is an empty slice, it's included in the JSON as an empty array ([]).
|
||||
// If Tools is populated, it's included in the JSON with the elements.
|
||||
func (a AssistantRequest) MarshalJSON() ([]byte, error) {
|
||||
type Alias AssistantRequest
|
||||
assistantAlias := &struct {
|
||||
Tools *[]AssistantTool `json:"tools,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(&a),
|
||||
}
|
||||
|
||||
if a.Tools != nil {
|
||||
assistantAlias.Tools = &a.Tools
|
||||
}
|
||||
|
||||
return json.Marshal(assistantAlias)
|
||||
}
|
||||
|
||||
// AssistantsList is a list of assistants.
|
||||
type AssistantsList struct {
|
||||
Assistants []Assistant `json:"data"`
|
||||
LastID *string `json:"last_id"`
|
||||
FirstID *string `json:"first_id"`
|
||||
HasMore bool `json:"has_more"`
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type AssistantDeleteResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Deleted bool `json:"deleted"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type AssistantFile struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
AssistantID string `json:"assistant_id"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type AssistantFileRequest struct {
|
||||
FileID string `json:"file_id"`
|
||||
}
|
||||
|
||||
type AssistantFilesList struct {
|
||||
AssistantFiles []AssistantFile `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// CreateAssistant creates a new assistant.
|
||||
func (c *Client) CreateAssistant(ctx context.Context, request AssistantRequest) (response Assistant, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(assistantsSuffix), withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveAssistant retrieves an assistant.
|
||||
func (c *Client) RetrieveAssistant(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
) (response Assistant, err error) {
|
||||
urlSuffix := fmt.Sprintf("%s/%s", assistantsSuffix, assistantID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ModifyAssistant modifies an assistant.
|
||||
func (c *Client) ModifyAssistant(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
request AssistantRequest,
|
||||
) (response Assistant, err error) {
|
||||
urlSuffix := fmt.Sprintf("%s/%s", assistantsSuffix, assistantID)
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteAssistant deletes an assistant.
|
||||
func (c *Client) DeleteAssistant(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
) (response AssistantDeleteResponse, err error) {
|
||||
urlSuffix := fmt.Sprintf("%s/%s", assistantsSuffix, assistantID)
|
||||
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ListAssistants Lists the currently available assistants.
|
||||
func (c *Client) ListAssistants(
|
||||
ctx context.Context,
|
||||
limit *int,
|
||||
order *string,
|
||||
after *string,
|
||||
before *string,
|
||||
) (response AssistantsList, err error) {
|
||||
urlValues := url.Values{}
|
||||
if limit != nil {
|
||||
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||
}
|
||||
if order != nil {
|
||||
urlValues.Add("order", *order)
|
||||
}
|
||||
if after != nil {
|
||||
urlValues.Add("after", *after)
|
||||
}
|
||||
if before != nil {
|
||||
urlValues.Add("before", *before)
|
||||
}
|
||||
|
||||
encodedValues := ""
|
||||
if len(urlValues) > 0 {
|
||||
encodedValues = "?" + urlValues.Encode()
|
||||
}
|
||||
|
||||
urlSuffix := fmt.Sprintf("%s%s", assistantsSuffix, encodedValues)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateAssistantFile creates a new assistant file.
|
||||
func (c *Client) CreateAssistantFile(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
request AssistantFileRequest,
|
||||
) (response AssistantFile, err error) {
|
||||
urlSuffix := fmt.Sprintf("%s/%s%s", assistantsSuffix, assistantID, assistantsFilesSuffix)
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||
withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveAssistantFile retrieves an assistant file.
|
||||
func (c *Client) RetrieveAssistantFile(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
fileID string,
|
||||
) (response AssistantFile, err error) {
|
||||
urlSuffix := fmt.Sprintf("%s/%s%s/%s", assistantsSuffix, assistantID, assistantsFilesSuffix, fileID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteAssistantFile deletes an existing file.
|
||||
func (c *Client) DeleteAssistantFile(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
fileID string,
|
||||
) (err error) {
|
||||
urlSuffix := fmt.Sprintf("%s/%s%s/%s", assistantsSuffix, assistantID, assistantsFilesSuffix, fileID)
|
||||
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ListAssistantFiles Lists the currently available files for an assistant.
|
||||
func (c *Client) ListAssistantFiles(
|
||||
ctx context.Context,
|
||||
assistantID string,
|
||||
limit *int,
|
||||
order *string,
|
||||
after *string,
|
||||
before *string,
|
||||
) (response AssistantFilesList, err error) {
|
||||
urlValues := url.Values{}
|
||||
if limit != nil {
|
||||
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||
}
|
||||
if order != nil {
|
||||
urlValues.Add("order", *order)
|
||||
}
|
||||
if after != nil {
|
||||
urlValues.Add("after", *after)
|
||||
}
|
||||
if before != nil {
|
||||
urlValues.Add("before", *before)
|
||||
}
|
||||
|
||||
encodedValues := ""
|
||||
if len(urlValues) > 0 {
|
||||
encodedValues = "?" + urlValues.Encode()
|
||||
}
|
||||
|
||||
urlSuffix := fmt.Sprintf("%s/%s%s%s", assistantsSuffix, assistantID, assistantsFilesSuffix, encodedValues)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
229
vendor/github.com/rugatling/go-openai/audio.go
generated
vendored
Normal file
229
vendor/github.com/rugatling/go-openai/audio.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
utils "github.com/rugatling/go-openai/internal"
|
||||
)
|
||||
|
||||
// Whisper Defines the models provided by OpenAI to use when processing audio with OpenAI.
|
||||
const (
|
||||
Whisper1 = "whisper-1"
|
||||
)
|
||||
|
||||
// Response formats; Whisper uses AudioResponseFormatJSON by default.
|
||||
type AudioResponseFormat string
|
||||
|
||||
const (
|
||||
AudioResponseFormatJSON AudioResponseFormat = "json"
|
||||
AudioResponseFormatText AudioResponseFormat = "text"
|
||||
AudioResponseFormatSRT AudioResponseFormat = "srt"
|
||||
AudioResponseFormatVerboseJSON AudioResponseFormat = "verbose_json"
|
||||
AudioResponseFormatVTT AudioResponseFormat = "vtt"
|
||||
)
|
||||
|
||||
type TranscriptionTimestampGranularity string
|
||||
|
||||
const (
|
||||
TranscriptionTimestampGranularityWord TranscriptionTimestampGranularity = "word"
|
||||
TranscriptionTimestampGranularitySegment TranscriptionTimestampGranularity = "segment"
|
||||
)
|
||||
|
||||
// AudioRequest represents a request structure for audio API.
|
||||
type AudioRequest struct {
|
||||
Model string
|
||||
|
||||
// FilePath is either an existing file in your filesystem or a filename representing the contents of Reader.
|
||||
FilePath string
|
||||
|
||||
// Reader is an optional io.Reader when you do not want to use an existing file.
|
||||
Reader io.Reader
|
||||
|
||||
Prompt string
|
||||
Temperature float32
|
||||
Language string // Only for transcription.
|
||||
Format AudioResponseFormat
|
||||
TimestampGranularities []TranscriptionTimestampGranularity // Only for transcription.
|
||||
}
|
||||
|
||||
// AudioResponse represents a response structure for audio API.
|
||||
type AudioResponse struct {
|
||||
Task string `json:"task"`
|
||||
Language string `json:"language"`
|
||||
Duration float64 `json:"duration"`
|
||||
Segments []struct {
|
||||
ID int `json:"id"`
|
||||
Seek int `json:"seek"`
|
||||
Start float64 `json:"start"`
|
||||
End float64 `json:"end"`
|
||||
Text string `json:"text"`
|
||||
Tokens []int `json:"tokens"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
AvgLogprob float64 `json:"avg_logprob"`
|
||||
CompressionRatio float64 `json:"compression_ratio"`
|
||||
NoSpeechProb float64 `json:"no_speech_prob"`
|
||||
Transient bool `json:"transient"`
|
||||
} `json:"segments"`
|
||||
Words []struct {
|
||||
Word string `json:"word"`
|
||||
Start float64 `json:"start"`
|
||||
End float64 `json:"end"`
|
||||
} `json:"words"`
|
||||
Text string `json:"text"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type audioTextResponse struct {
|
||||
Text string `json:"text"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
func (r *audioTextResponse) ToAudioResponse() AudioResponse {
|
||||
return AudioResponse{
|
||||
Text: r.Text,
|
||||
httpHeader: r.httpHeader,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTranscription — API call to create a transcription. Returns transcribed text.
|
||||
func (c *Client) CreateTranscription(
|
||||
ctx context.Context,
|
||||
request AudioRequest,
|
||||
) (response AudioResponse, err error) {
|
||||
return c.callAudioAPI(ctx, request, "transcriptions")
|
||||
}
|
||||
|
||||
// CreateTranslation — API call to translate audio into English.
|
||||
func (c *Client) CreateTranslation(
|
||||
ctx context.Context,
|
||||
request AudioRequest,
|
||||
) (response AudioResponse, err error) {
|
||||
return c.callAudioAPI(ctx, request, "translations")
|
||||
}
|
||||
|
||||
// callAudioAPI — API call to an audio endpoint.
|
||||
func (c *Client) callAudioAPI(
|
||||
ctx context.Context,
|
||||
request AudioRequest,
|
||||
endpointSuffix string,
|
||||
) (response AudioResponse, err error) {
|
||||
var formBody bytes.Buffer
|
||||
builder := c.createFormBuilder(&formBody)
|
||||
|
||||
if err = audioMultipartForm(request, builder); err != nil {
|
||||
return AudioResponse{}, err
|
||||
}
|
||||
|
||||
urlSuffix := fmt.Sprintf("/audio/%s", endpointSuffix)
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix, request.Model),
|
||||
withBody(&formBody), withContentType(builder.FormDataContentType()))
|
||||
if err != nil {
|
||||
return AudioResponse{}, err
|
||||
}
|
||||
|
||||
if request.HasJSONResponse() {
|
||||
err = c.sendRequest(req, &response)
|
||||
} else {
|
||||
var textResponse audioTextResponse
|
||||
err = c.sendRequest(req, &textResponse)
|
||||
response = textResponse.ToAudioResponse()
|
||||
}
|
||||
if err != nil {
|
||||
return AudioResponse{}, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HasJSONResponse returns true if the response format is JSON.
|
||||
func (r AudioRequest) HasJSONResponse() bool {
|
||||
return r.Format == "" || r.Format == AudioResponseFormatJSON || r.Format == AudioResponseFormatVerboseJSON
|
||||
}
|
||||
|
||||
// audioMultipartForm creates a form with audio file contents and the name of the model to use for
|
||||
// audio processing.
|
||||
func audioMultipartForm(request AudioRequest, b utils.FormBuilder) error {
|
||||
err := createFileField(request, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.WriteField("model", request.Model)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing model name: %w", err)
|
||||
}
|
||||
|
||||
// Create a form field for the prompt (if provided)
|
||||
if request.Prompt != "" {
|
||||
err = b.WriteField("prompt", request.Prompt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing prompt: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a form field for the format (if provided)
|
||||
if request.Format != "" {
|
||||
err = b.WriteField("response_format", string(request.Format))
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing format: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a form field for the temperature (if provided)
|
||||
if request.Temperature != 0 {
|
||||
err = b.WriteField("temperature", fmt.Sprintf("%.2f", request.Temperature))
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing temperature: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a form field for the language (if provided)
|
||||
if request.Language != "" {
|
||||
err = b.WriteField("language", request.Language)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing language: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(request.TimestampGranularities) > 0 {
|
||||
for _, tg := range request.TimestampGranularities {
|
||||
err = b.WriteField("timestamp_granularities[]", string(tg))
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing timestamp_granularities[]: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the multipart writer
|
||||
return b.Close()
|
||||
}
|
||||
|
||||
// createFileField creates the "file" form field from either an existing file or by using the reader.
|
||||
func createFileField(request AudioRequest, b utils.FormBuilder) error {
|
||||
if request.Reader != nil {
|
||||
err := b.CreateFormFileReader("file", request.Reader, request.FilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating form using reader: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Open(request.FilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening audio file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = b.CreateFormFile("file", f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating form file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
355
vendor/github.com/rugatling/go-openai/chat.go
generated
vendored
Normal file
355
vendor/github.com/rugatling/go-openai/chat.go
generated
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Chat message role defined by the OpenAI API.
|
||||
const (
|
||||
ChatMessageRoleSystem = "system"
|
||||
ChatMessageRoleUser = "user"
|
||||
ChatMessageRoleAssistant = "assistant"
|
||||
ChatMessageRoleFunction = "function"
|
||||
ChatMessageRoleTool = "tool"
|
||||
)
|
||||
|
||||
const chatCompletionsSuffix = "/chat/completions"
|
||||
|
||||
var (
|
||||
ErrChatCompletionInvalidModel = errors.New("this model is not supported with this method, please use CreateCompletion client method instead") //nolint:lll
|
||||
ErrChatCompletionStreamNotSupported = errors.New("streaming is not supported with this method, please use CreateChatCompletionStream") //nolint:lll
|
||||
ErrContentFieldsMisused = errors.New("can't use both Content and MultiContent properties simultaneously")
|
||||
)
|
||||
|
||||
type Hate struct {
|
||||
Filtered bool `json:"filtered"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
}
|
||||
type SelfHarm struct {
|
||||
Filtered bool `json:"filtered"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
}
|
||||
type Sexual struct {
|
||||
Filtered bool `json:"filtered"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
}
|
||||
type Violence struct {
|
||||
Filtered bool `json:"filtered"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
}
|
||||
|
||||
type ContentFilterResults struct {
|
||||
Hate Hate `json:"hate,omitempty"`
|
||||
SelfHarm SelfHarm `json:"self_harm,omitempty"`
|
||||
Sexual Sexual `json:"sexual,omitempty"`
|
||||
Violence Violence `json:"violence,omitempty"`
|
||||
}
|
||||
|
||||
type PromptAnnotation struct {
|
||||
PromptIndex int `json:"prompt_index,omitempty"`
|
||||
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||
}
|
||||
|
||||
type ImageURLDetail string
|
||||
|
||||
const (
|
||||
ImageURLDetailHigh ImageURLDetail = "high"
|
||||
ImageURLDetailLow ImageURLDetail = "low"
|
||||
ImageURLDetailAuto ImageURLDetail = "auto"
|
||||
)
|
||||
|
||||
type ChatMessageImageURL struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
Detail ImageURLDetail `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
type ChatMessagePartType string
|
||||
|
||||
const (
|
||||
ChatMessagePartTypeText ChatMessagePartType = "text"
|
||||
ChatMessagePartTypeImageURL ChatMessagePartType = "image_url"
|
||||
)
|
||||
|
||||
type ChatMessagePart struct {
|
||||
Type ChatMessagePartType `json:"type,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
ImageURL *ChatMessageImageURL `json:"image_url,omitempty"`
|
||||
}
|
||||
|
||||
type ChatCompletionMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
MultiContent []ChatMessagePart
|
||||
|
||||
// This property isn't in the official documentation, but it's in
|
||||
// the documentation for the official library for python:
|
||||
// - https://github.com/openai/openai-python/blob/main/chatml.md
|
||||
// - https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||
|
||||
// For Role=assistant prompts this may be set to the tool calls generated by the model, such as function calls.
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
|
||||
// For Role=tool prompts this should be set to the ID given in the assistant's prior request to call a tool.
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
||||
func (m ChatCompletionMessage) MarshalJSON() ([]byte, error) {
|
||||
if m.Content != "" && m.MultiContent != nil {
|
||||
return nil, ErrContentFieldsMisused
|
||||
}
|
||||
if len(m.MultiContent) > 0 {
|
||||
msg := struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"-"`
|
||||
MultiContent []ChatMessagePart `json:"content,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}(m)
|
||||
return json.Marshal(msg)
|
||||
}
|
||||
msg := struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
MultiContent []ChatMessagePart `json:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}(m)
|
||||
return json.Marshal(msg)
|
||||
}
|
||||
|
||||
func (m *ChatCompletionMessage) UnmarshalJSON(bs []byte) error {
|
||||
msg := struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
MultiContent []ChatMessagePart
|
||||
Name string `json:"name,omitempty"`
|
||||
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}{}
|
||||
if err := json.Unmarshal(bs, &msg); err == nil {
|
||||
*m = ChatCompletionMessage(msg)
|
||||
return nil
|
||||
}
|
||||
multiMsg := struct {
|
||||
Role string `json:"role"`
|
||||
Content string
|
||||
MultiContent []ChatMessagePart `json:"content"`
|
||||
Name string `json:"name,omitempty"`
|
||||
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}{}
|
||||
if err := json.Unmarshal(bs, &multiMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = ChatCompletionMessage(multiMsg)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ToolCall struct {
|
||||
// Index is not nil only in chat completion chunk object
|
||||
Index *int `json:"index,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Type ToolType `json:"type"`
|
||||
Function FunctionCall `json:"function"`
|
||||
}
|
||||
|
||||
type FunctionCall struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
// call function with arguments in JSON format
|
||||
Arguments string `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
type ChatCompletionResponseFormatType string
|
||||
|
||||
const (
|
||||
ChatCompletionResponseFormatTypeJSONObject ChatCompletionResponseFormatType = "json_object"
|
||||
ChatCompletionResponseFormatTypeText ChatCompletionResponseFormatType = "text"
|
||||
)
|
||||
|
||||
type ChatCompletionResponseFormat struct {
|
||||
Type ChatCompletionResponseFormatType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// ChatCompletionRequest represents a request structure for chat completion API.
|
||||
type ChatCompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []ChatCompletionMessage `json:"messages"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
Temperature float32 `json:"temperature,omitempty"`
|
||||
TopP float32 `json:"top_p,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
PresencePenalty float32 `json:"presence_penalty,omitempty"`
|
||||
ResponseFormat *ChatCompletionResponseFormat `json:"response_format,omitempty"`
|
||||
Seed *int `json:"seed,omitempty"`
|
||||
FrequencyPenalty float32 `json:"frequency_penalty,omitempty"`
|
||||
// LogitBias is must be a token id string (specified by their token ID in the tokenizer), not a word string.
|
||||
// incorrect: `"logit_bias":{"You": 6}`, correct: `"logit_bias":{"1639": 6}`
|
||||
// refs: https://platform.openai.com/docs/api-reference/chat/create#chat/create-logit_bias
|
||||
LogitBias map[string]int `json:"logit_bias,omitempty"`
|
||||
// LogProbs indicates whether to return log probabilities of the output tokens or not.
|
||||
// If true, returns the log probabilities of each output token returned in the content of message.
|
||||
// This option is currently not available on the gpt-4-vision-preview model.
|
||||
LogProbs bool `json:"logprobs,omitempty"`
|
||||
// TopLogProbs is an integer between 0 and 5 specifying the number of most likely tokens to return at each
|
||||
// token position, each with an associated log probability.
|
||||
// logprobs must be set to true if this parameter is used.
|
||||
TopLogProbs int `json:"top_logprobs,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
// Deprecated: use Tools instead.
|
||||
Functions []FunctionDefinition `json:"functions,omitempty"`
|
||||
// Deprecated: use ToolChoice instead.
|
||||
FunctionCall any `json:"function_call,omitempty"`
|
||||
Tools []Tool `json:"tools,omitempty"`
|
||||
// This can be either a string or an ToolChoice object.
|
||||
ToolChoice any `json:"tool_choice,omitempty"`
|
||||
// Options for streaming response. Only set this when you set stream: true.
|
||||
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
||||
}
|
||||
|
||||
type StreamOptions struct {
|
||||
// If set, an additional chunk will be streamed before the data: [DONE] message.
|
||||
// The usage field on this chunk shows the token usage statistics for the entire request,
|
||||
// and the choices field will always be an empty array.
|
||||
// All other chunks will also include a usage field, but with a null value.
|
||||
IncludeUsage bool `json:"include_usage,omitempty"`
|
||||
}
|
||||
|
||||
type ToolType string
|
||||
|
||||
const (
|
||||
ToolTypeFunction ToolType = "function"
|
||||
)
|
||||
|
||||
type Tool struct {
|
||||
Type ToolType `json:"type"`
|
||||
Function *FunctionDefinition `json:"function,omitempty"`
|
||||
}
|
||||
|
||||
type ToolChoice struct {
|
||||
Type ToolType `json:"type"`
|
||||
Function ToolFunction `json:"function,omitempty"`
|
||||
}
|
||||
|
||||
type ToolFunction struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type FunctionDefinition struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
// Parameters is an object describing the function.
|
||||
// You can pass json.RawMessage to describe the schema,
|
||||
// or you can pass in a struct which serializes to the proper JSON schema.
|
||||
// The jsonschema package is provided for convenience, but you should
|
||||
// consider another specialized library if you require more complex schemas.
|
||||
Parameters any `json:"parameters"`
|
||||
}
|
||||
|
||||
// Deprecated: use FunctionDefinition instead.
|
||||
type FunctionDefine = FunctionDefinition
|
||||
|
||||
type TopLogProbs struct {
|
||||
Token string `json:"token"`
|
||||
LogProb float64 `json:"logprob"`
|
||||
Bytes []byte `json:"bytes,omitempty"`
|
||||
}
|
||||
|
||||
// LogProb represents the probability information for a token.
|
||||
type LogProb struct {
|
||||
Token string `json:"token"`
|
||||
LogProb float64 `json:"logprob"`
|
||||
Bytes []byte `json:"bytes,omitempty"` // Omitting the field if it is null
|
||||
// TopLogProbs is a list of the most likely tokens and their log probability, at this token position.
|
||||
// In rare cases, there may be fewer than the number of requested top_logprobs returned.
|
||||
TopLogProbs []TopLogProbs `json:"top_logprobs"`
|
||||
}
|
||||
|
||||
// LogProbs is the top-level structure containing the log probability information.
|
||||
type LogProbs struct {
|
||||
// Content is a list of message content tokens with log probability information.
|
||||
Content []LogProb `json:"content"`
|
||||
}
|
||||
|
||||
type FinishReason string
|
||||
|
||||
const (
|
||||
FinishReasonStop FinishReason = "stop"
|
||||
FinishReasonLength FinishReason = "length"
|
||||
FinishReasonFunctionCall FinishReason = "function_call"
|
||||
FinishReasonToolCalls FinishReason = "tool_calls"
|
||||
FinishReasonContentFilter FinishReason = "content_filter"
|
||||
FinishReasonNull FinishReason = "null"
|
||||
)
|
||||
|
||||
func (r FinishReason) MarshalJSON() ([]byte, error) {
|
||||
if r == FinishReasonNull || r == "" {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(`"` + string(r) + `"`), nil // best effort to not break future API changes
|
||||
}
|
||||
|
||||
type ChatCompletionChoice struct {
|
||||
Index int `json:"index"`
|
||||
Message ChatCompletionMessage `json:"message"`
|
||||
// FinishReason
|
||||
// stop: API returned complete message,
|
||||
// or a message terminated by one of the stop sequences provided via the stop parameter
|
||||
// length: Incomplete model output due to max_tokens parameter or token limit
|
||||
// function_call: The model decided to call a function
|
||||
// content_filter: Omitted content due to a flag from our content filters
|
||||
// null: API response still in progress or incomplete
|
||||
FinishReason FinishReason `json:"finish_reason"`
|
||||
LogProbs *LogProbs `json:"logprobs,omitempty"`
|
||||
}
|
||||
|
||||
// ChatCompletionResponse represents a response structure for chat completion API.
|
||||
type ChatCompletionResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []ChatCompletionChoice `json:"choices"`
|
||||
Usage Usage `json:"usage"`
|
||||
SystemFingerprint string `json:"system_fingerprint"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// CreateChatCompletion — API call to Create a completion for the chat message.
|
||||
func (c *Client) CreateChatCompletion(
|
||||
ctx context.Context,
|
||||
request ChatCompletionRequest,
|
||||
) (response ChatCompletionResponse, err error) {
|
||||
if request.Stream {
|
||||
err = ErrChatCompletionStreamNotSupported
|
||||
return
|
||||
}
|
||||
|
||||
urlSuffix := chatCompletionsSuffix
|
||||
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||
err = ErrChatCompletionInvalidModel
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix, request.Model), withBody(request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
76
vendor/github.com/rugatling/go-openai/chat_stream.go
generated
vendored
Normal file
76
vendor/github.com/rugatling/go-openai/chat_stream.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ChatCompletionStreamChoiceDelta struct {
|
||||
Content string `json:"content,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type ChatCompletionStreamChoice struct {
|
||||
Index int `json:"index"`
|
||||
Delta ChatCompletionStreamChoiceDelta `json:"delta"`
|
||||
FinishReason FinishReason `json:"finish_reason"`
|
||||
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||
}
|
||||
|
||||
type PromptFilterResult struct {
|
||||
Index int `json:"index"`
|
||||
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||
}
|
||||
|
||||
type ChatCompletionStreamResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []ChatCompletionStreamChoice `json:"choices"`
|
||||
SystemFingerprint string `json:"system_fingerprint"`
|
||||
PromptAnnotations []PromptAnnotation `json:"prompt_annotations,omitempty"`
|
||||
PromptFilterResults []PromptFilterResult `json:"prompt_filter_results,omitempty"`
|
||||
// An optional field that will only be present when you set stream_options: {"include_usage": true} in your request.
|
||||
// When present, it contains a null value except for the last chunk which contains the token usage statistics
|
||||
// for the entire request.
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
// ChatCompletionStream
|
||||
// Note: Perhaps it is more elegant to abstract Stream using generics.
|
||||
type ChatCompletionStream struct {
|
||||
*streamReader[ChatCompletionStreamResponse]
|
||||
}
|
||||
|
||||
// CreateChatCompletionStream — API call to create a chat completion w/ streaming
|
||||
// support. It sets whether to stream back partial progress. If set, tokens will be
|
||||
// sent as data-only server-sent events as they become available, with the
|
||||
// stream terminated by a data: [DONE] message.
|
||||
func (c *Client) CreateChatCompletionStream(
|
||||
ctx context.Context,
|
||||
request ChatCompletionRequest,
|
||||
) (stream *ChatCompletionStream, err error) {
|
||||
urlSuffix := chatCompletionsSuffix
|
||||
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||
err = ErrChatCompletionInvalidModel
|
||||
return
|
||||
}
|
||||
|
||||
request.Stream = true
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix, request.Model), withBody(request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := sendRequestStream[ChatCompletionStreamResponse](c, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
stream = &ChatCompletionStream{
|
||||
streamReader: resp,
|
||||
}
|
||||
return
|
||||
}
|
||||
284
vendor/github.com/rugatling/go-openai/client.go
generated
vendored
Normal file
284
vendor/github.com/rugatling/go-openai/client.go
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
utils "github.com/rugatling/go-openai/internal"
|
||||
)
|
||||
|
||||
// Client is OpenAI GPT-3 API client.
|
||||
type Client struct {
|
||||
config ClientConfig
|
||||
|
||||
requestBuilder utils.RequestBuilder
|
||||
createFormBuilder func(io.Writer) utils.FormBuilder
|
||||
}
|
||||
|
||||
type Response interface {
|
||||
SetHeader(http.Header)
|
||||
}
|
||||
|
||||
type httpHeader http.Header
|
||||
|
||||
func (h *httpHeader) SetHeader(header http.Header) {
|
||||
*h = httpHeader(header)
|
||||
}
|
||||
|
||||
func (h *httpHeader) Header() http.Header {
|
||||
return http.Header(*h)
|
||||
}
|
||||
|
||||
func (h *httpHeader) GetRateLimitHeaders() RateLimitHeaders {
|
||||
return newRateLimitHeaders(h.Header())
|
||||
}
|
||||
|
||||
type RawResponse struct {
|
||||
io.ReadCloser
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// NewClient creates new OpenAI API client.
|
||||
func NewClient(authToken string) *Client {
|
||||
config := DefaultConfig(authToken)
|
||||
return NewClientWithConfig(config)
|
||||
}
|
||||
|
||||
// NewClientWithConfig creates new OpenAI API client for specified config.
|
||||
func NewClientWithConfig(config ClientConfig) *Client {
|
||||
return &Client{
|
||||
config: config,
|
||||
requestBuilder: utils.NewRequestBuilder(),
|
||||
createFormBuilder: func(body io.Writer) utils.FormBuilder {
|
||||
return utils.NewFormBuilder(body)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewOrgClient creates new OpenAI API client for specified Organization ID.
|
||||
//
|
||||
// Deprecated: Please use NewClientWithConfig.
|
||||
func NewOrgClient(authToken, org string) *Client {
|
||||
config := DefaultConfig(authToken)
|
||||
config.OrgID = org
|
||||
return NewClientWithConfig(config)
|
||||
}
|
||||
|
||||
type requestOptions struct {
|
||||
body any
|
||||
header http.Header
|
||||
}
|
||||
|
||||
type requestOption func(*requestOptions)
|
||||
|
||||
func withBody(body any) requestOption {
|
||||
return func(args *requestOptions) {
|
||||
args.body = body
|
||||
}
|
||||
}
|
||||
|
||||
func withContentType(contentType string) requestOption {
|
||||
return func(args *requestOptions) {
|
||||
args.header.Set("Content-Type", contentType)
|
||||
}
|
||||
}
|
||||
|
||||
func withBetaAssistantVersion(version string) requestOption {
|
||||
return func(args *requestOptions) {
|
||||
args.header.Set("OpenAI-Beta", fmt.Sprintf("assistants=%s", version))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(ctx context.Context, method, url string, setters ...requestOption) (*http.Request, error) {
|
||||
// Default Options
|
||||
args := &requestOptions{
|
||||
body: nil,
|
||||
header: make(http.Header),
|
||||
}
|
||||
for _, setter := range setters {
|
||||
setter(args)
|
||||
}
|
||||
req, err := c.requestBuilder.Build(ctx, method, url, args.body, args.header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.setCommonHeaders(req)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) sendRequest(req *http.Request, v Response) error {
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
// Check whether Content-Type is already set, Upload Files API requires
|
||||
// Content-Type == multipart/form-data
|
||||
contentType := req.Header.Get("Content-Type")
|
||||
if contentType == "" {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
res, err := c.config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
if v != nil {
|
||||
v.SetHeader(res.Header)
|
||||
}
|
||||
|
||||
if isFailureStatusCode(res) {
|
||||
return c.handleErrorResp(res)
|
||||
}
|
||||
|
||||
return decodeResponse(res.Body, v)
|
||||
}
|
||||
|
||||
func (c *Client) sendRequestRaw(req *http.Request) (response RawResponse, err error) {
|
||||
resp, err := c.config.HTTPClient.Do(req) //nolint:bodyclose // body should be closed by outer function
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if isFailureStatusCode(resp) {
|
||||
err = c.handleErrorResp(resp)
|
||||
return
|
||||
}
|
||||
|
||||
response.SetHeader(resp.Header)
|
||||
response.ReadCloser = resp.Body
|
||||
return
|
||||
}
|
||||
|
||||
func sendRequestStream[T streamable](client *Client, req *http.Request) (*streamReader[T], error) {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "text/event-stream")
|
||||
req.Header.Set("Cache-Control", "no-cache")
|
||||
req.Header.Set("Connection", "keep-alive")
|
||||
|
||||
resp, err := client.config.HTTPClient.Do(req) //nolint:bodyclose // body is closed in stream.Close()
|
||||
if err != nil {
|
||||
return new(streamReader[T]), err
|
||||
}
|
||||
if isFailureStatusCode(resp) {
|
||||
return new(streamReader[T]), client.handleErrorResp(resp)
|
||||
}
|
||||
return &streamReader[T]{
|
||||
emptyMessagesLimit: client.config.EmptyMessagesLimit,
|
||||
reader: bufio.NewReader(resp.Body),
|
||||
response: resp,
|
||||
errAccumulator: utils.NewErrorAccumulator(),
|
||||
unmarshaler: &utils.JSONUnmarshaler{},
|
||||
httpHeader: httpHeader(resp.Header),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) setCommonHeaders(req *http.Request) {
|
||||
// https://learn.microsoft.com/en-us/azure/cognitive-services/openai/reference#authentication
|
||||
// Azure API Key authentication
|
||||
if c.config.APIType == APITypeAzure || c.config.APIType == APITypeCloudflareAzure {
|
||||
req.Header.Set(AzureAPIKeyHeader, c.config.authToken)
|
||||
} else if c.config.authToken != "" {
|
||||
// OpenAI or Azure AD authentication
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.config.authToken))
|
||||
}
|
||||
if c.config.OrgID != "" {
|
||||
req.Header.Set("OpenAI-Organization", c.config.OrgID)
|
||||
}
|
||||
}
|
||||
|
||||
func isFailureStatusCode(resp *http.Response) bool {
|
||||
return resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest
|
||||
}
|
||||
|
||||
func decodeResponse(body io.Reader, v any) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch o := v.(type) {
|
||||
case *string:
|
||||
return decodeString(body, o)
|
||||
case *audioTextResponse:
|
||||
return decodeString(body, &o.Text)
|
||||
default:
|
||||
return json.NewDecoder(body).Decode(v)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeString(body io.Reader, output *string) error {
|
||||
b, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*output = string(b)
|
||||
return nil
|
||||
}
|
||||
|
||||
// fullURL returns full URL for request.
|
||||
// args[0] is model name, if API type is Azure, model name is required to get deployment name.
|
||||
func (c *Client) fullURL(suffix string, args ...any) string {
|
||||
// /openai/deployments/{model}/chat/completions?api-version={api_version}
|
||||
if c.config.APIType == APITypeAzure || c.config.APIType == APITypeAzureAD {
|
||||
baseURL := c.config.BaseURL
|
||||
baseURL = strings.TrimRight(baseURL, "/")
|
||||
// if suffix is /models change to {endpoint}/openai/models?api-version=2022-12-01
|
||||
// https://learn.microsoft.com/en-us/rest/api/cognitiveservices/azureopenaistable/models/list?tabs=HTTP
|
||||
if containsSubstr([]string{"/models", "/assistants", "/threads", "/files"}, suffix) {
|
||||
return fmt.Sprintf("%s/%s%s?api-version=%s", baseURL, azureAPIPrefix, suffix, c.config.APIVersion)
|
||||
}
|
||||
azureDeploymentName := "UNKNOWN"
|
||||
if len(args) > 0 {
|
||||
model, ok := args[0].(string)
|
||||
if ok {
|
||||
azureDeploymentName = c.config.GetAzureDeploymentByModel(model)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s/%s/%s/%s%s?api-version=%s",
|
||||
baseURL, azureAPIPrefix, azureDeploymentsPrefix,
|
||||
azureDeploymentName, suffix, c.config.APIVersion,
|
||||
)
|
||||
}
|
||||
|
||||
// https://developers.cloudflare.com/ai-gateway/providers/azureopenai/
|
||||
if c.config.APIType == APITypeCloudflareAzure {
|
||||
baseURL := c.config.BaseURL
|
||||
baseURL = strings.TrimRight(baseURL, "/")
|
||||
return fmt.Sprintf("%s%s?api-version=%s", baseURL, suffix, c.config.APIVersion)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s", c.config.BaseURL, suffix)
|
||||
}
|
||||
|
||||
func (c *Client) handleErrorResp(resp *http.Response) error {
|
||||
var errRes ErrorResponse
|
||||
err := json.NewDecoder(resp.Body).Decode(&errRes)
|
||||
if err != nil || errRes.Error == nil {
|
||||
reqErr := &RequestError{
|
||||
HTTPStatusCode: resp.StatusCode,
|
||||
Err: err,
|
||||
}
|
||||
if errRes.Error != nil {
|
||||
reqErr.Err = errRes.Error
|
||||
}
|
||||
return reqErr
|
||||
}
|
||||
|
||||
errRes.Error.HTTPStatusCode = resp.StatusCode
|
||||
return errRes.Error
|
||||
}
|
||||
|
||||
func containsSubstr(s []string, e string) bool {
|
||||
for _, v := range s {
|
||||
if strings.Contains(e, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
10
vendor/github.com/rugatling/go-openai/common.go
generated
vendored
Normal file
10
vendor/github.com/rugatling/go-openai/common.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package openai
|
||||
|
||||
// common.go defines common types used throughout the OpenAI API.
|
||||
|
||||
// Usage Represents the total token usage per request to OpenAI.
|
||||
type Usage struct {
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
}
|
||||
213
vendor/github.com/rugatling/go-openai/completion.go
generated
vendored
Normal file
213
vendor/github.com/rugatling/go-openai/completion.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCompletionUnsupportedModel = errors.New("this model is not supported with this method, please use CreateChatCompletion client method instead") //nolint:lll
|
||||
ErrCompletionStreamNotSupported = errors.New("streaming is not supported with this method, please use CreateCompletionStream") //nolint:lll
|
||||
ErrCompletionRequestPromptTypeNotSupported = errors.New("the type of CompletionRequest.Prompt only supports string and []string") //nolint:lll
|
||||
)
|
||||
|
||||
// GPT3 Defines the models provided by OpenAI to use when generating
|
||||
// completions from OpenAI.
|
||||
// GPT3 Models are designed for text-based tasks. For code-specific
|
||||
// tasks, please refer to the Codex series of models.
|
||||
const (
|
||||
GPT432K0613 = "gpt-4-32k-0613"
|
||||
GPT432K0314 = "gpt-4-32k-0314"
|
||||
GPT432K = "gpt-4-32k"
|
||||
GPT40613 = "gpt-4-0613"
|
||||
GPT40314 = "gpt-4-0314"
|
||||
GPT4o = "gpt-4o"
|
||||
GPT4o20240513 = "gpt-4o-2024-05-13"
|
||||
GPT4Turbo = "gpt-4-turbo"
|
||||
GPT4Turbo20240409 = "gpt-4-turbo-2024-04-09"
|
||||
GPT4Turbo0125 = "gpt-4-0125-preview"
|
||||
GPT4Turbo1106 = "gpt-4-1106-preview"
|
||||
GPT4TurboPreview = "gpt-4-turbo-preview"
|
||||
GPT4VisionPreview = "gpt-4-vision-preview"
|
||||
GPT4 = "gpt-4"
|
||||
GPT3Dot5Turbo0125 = "gpt-3.5-turbo-0125"
|
||||
GPT3Dot5Turbo1106 = "gpt-3.5-turbo-1106"
|
||||
GPT3Dot5Turbo0613 = "gpt-3.5-turbo-0613"
|
||||
GPT3Dot5Turbo0301 = "gpt-3.5-turbo-0301"
|
||||
GPT3Dot5Turbo16K = "gpt-3.5-turbo-16k"
|
||||
GPT3Dot5Turbo16K0613 = "gpt-3.5-turbo-16k-0613"
|
||||
GPT3Dot5Turbo = "gpt-3.5-turbo"
|
||||
GPT3Dot5TurboInstruct = "gpt-3.5-turbo-instruct"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3TextDavinci003 = "text-davinci-003"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3TextDavinci002 = "text-davinci-002"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3TextCurie001 = "text-curie-001"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3TextBabbage001 = "text-babbage-001"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3TextAda001 = "text-ada-001"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3TextDavinci001 = "text-davinci-001"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3DavinciInstructBeta = "davinci-instruct-beta"
|
||||
GPT3Davinci = "davinci"
|
||||
GPT3Davinci002 = "davinci-002"
|
||||
// Deprecated: Will be shut down on January 04, 2024. Use gpt-3.5-turbo-instruct instead.
|
||||
GPT3CurieInstructBeta = "curie-instruct-beta"
|
||||
GPT3Curie = "curie"
|
||||
GPT3Curie002 = "curie-002"
|
||||
GPT3Ada = "ada"
|
||||
GPT3Ada002 = "ada-002"
|
||||
GPT3Babbage = "babbage"
|
||||
GPT3Babbage002 = "babbage-002"
|
||||
)
|
||||
|
||||
// Codex Defines the models provided by OpenAI.
|
||||
// These models are designed for code-specific tasks, and use
|
||||
// a different tokenizer which optimizes for whitespace.
|
||||
const (
|
||||
CodexCodeDavinci002 = "code-davinci-002"
|
||||
CodexCodeCushman001 = "code-cushman-001"
|
||||
CodexCodeDavinci001 = "code-davinci-001"
|
||||
)
|
||||
|
||||
var disabledModelsForEndpoints = map[string]map[string]bool{
|
||||
"/completions": {
|
||||
GPT3Dot5Turbo: true,
|
||||
GPT3Dot5Turbo0301: true,
|
||||
GPT3Dot5Turbo0613: true,
|
||||
GPT3Dot5Turbo1106: true,
|
||||
GPT3Dot5Turbo0125: true,
|
||||
GPT3Dot5Turbo16K: true,
|
||||
GPT3Dot5Turbo16K0613: true,
|
||||
GPT4: true,
|
||||
GPT4o: true,
|
||||
GPT4o20240513: true,
|
||||
GPT4TurboPreview: true,
|
||||
GPT4VisionPreview: true,
|
||||
GPT4Turbo1106: true,
|
||||
GPT4Turbo0125: true,
|
||||
GPT4Turbo: true,
|
||||
GPT4Turbo20240409: true,
|
||||
GPT40314: true,
|
||||
GPT40613: true,
|
||||
GPT432K: true,
|
||||
GPT432K0314: true,
|
||||
GPT432K0613: true,
|
||||
},
|
||||
chatCompletionsSuffix: {
|
||||
CodexCodeDavinci002: true,
|
||||
CodexCodeCushman001: true,
|
||||
CodexCodeDavinci001: true,
|
||||
GPT3TextDavinci003: true,
|
||||
GPT3TextDavinci002: true,
|
||||
GPT3TextCurie001: true,
|
||||
GPT3TextBabbage001: true,
|
||||
GPT3TextAda001: true,
|
||||
GPT3TextDavinci001: true,
|
||||
GPT3DavinciInstructBeta: true,
|
||||
GPT3Davinci: true,
|
||||
GPT3CurieInstructBeta: true,
|
||||
GPT3Curie: true,
|
||||
GPT3Ada: true,
|
||||
GPT3Babbage: true,
|
||||
},
|
||||
}
|
||||
|
||||
func checkEndpointSupportsModel(endpoint, model string) bool {
|
||||
return !disabledModelsForEndpoints[endpoint][model]
|
||||
}
|
||||
|
||||
func checkPromptType(prompt any) bool {
|
||||
_, isString := prompt.(string)
|
||||
_, isStringSlice := prompt.([]string)
|
||||
return isString || isStringSlice
|
||||
}
|
||||
|
||||
// CompletionRequest represents a request structure for completion API.
|
||||
type CompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Prompt any `json:"prompt,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
Temperature float32 `json:"temperature,omitempty"`
|
||||
TopP float32 `json:"top_p,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
LogProbs int `json:"logprobs,omitempty"`
|
||||
Echo bool `json:"echo,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
PresencePenalty float32 `json:"presence_penalty,omitempty"`
|
||||
FrequencyPenalty float32 `json:"frequency_penalty,omitempty"`
|
||||
BestOf int `json:"best_of,omitempty"`
|
||||
// LogitBias is must be a token id string (specified by their token ID in the tokenizer), not a word string.
|
||||
// incorrect: `"logit_bias":{"You": 6}`, correct: `"logit_bias":{"1639": 6}`
|
||||
// refs: https://platform.openai.com/docs/api-reference/completions/create#completions/create-logit_bias
|
||||
LogitBias map[string]int `json:"logit_bias,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
// CompletionChoice represents one of possible completions.
|
||||
type CompletionChoice struct {
|
||||
Text string `json:"text"`
|
||||
Index int `json:"index"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
LogProbs LogprobResult `json:"logprobs"`
|
||||
}
|
||||
|
||||
// LogprobResult represents logprob result of Choice.
|
||||
type LogprobResult struct {
|
||||
Tokens []string `json:"tokens"`
|
||||
TokenLogprobs []float32 `json:"token_logprobs"`
|
||||
TopLogprobs []map[string]float32 `json:"top_logprobs"`
|
||||
TextOffset []int `json:"text_offset"`
|
||||
}
|
||||
|
||||
// CompletionResponse represents a response structure for completion API.
|
||||
type CompletionResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []CompletionChoice `json:"choices"`
|
||||
Usage Usage `json:"usage"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// CreateCompletion — API call to create a completion. This is the main endpoint of the API. Returns new text as well
|
||||
// as, if requested, the probabilities over each alternative token at each position.
|
||||
//
|
||||
// If using a fine-tuned model, simply provide the model's ID in the CompletionRequest object,
|
||||
// and the server will use the model's parameters to generate the completion.
|
||||
func (c *Client) CreateCompletion(
|
||||
ctx context.Context,
|
||||
request CompletionRequest,
|
||||
) (response CompletionResponse, err error) {
|
||||
if request.Stream {
|
||||
err = ErrCompletionStreamNotSupported
|
||||
return
|
||||
}
|
||||
|
||||
urlSuffix := "/completions"
|
||||
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||
err = ErrCompletionUnsupportedModel
|
||||
return
|
||||
}
|
||||
|
||||
if !checkPromptType(request.Prompt) {
|
||||
err = ErrCompletionRequestPromptTypeNotSupported
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix, request.Model), withBody(request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
85
vendor/github.com/rugatling/go-openai/config.go
generated
vendored
Normal file
85
vendor/github.com/rugatling/go-openai/config.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
openaiAPIURLv1 = "https://api.proxyapi.ru/openai/v1"
|
||||
defaultEmptyMessagesLimit uint = 300
|
||||
|
||||
azureAPIPrefix = "openai"
|
||||
azureDeploymentsPrefix = "deployments"
|
||||
)
|
||||
|
||||
type APIType string
|
||||
|
||||
const (
|
||||
APITypeOpenAI APIType = "OPEN_AI"
|
||||
APITypeAzure APIType = "AZURE"
|
||||
APITypeAzureAD APIType = "AZURE_AD"
|
||||
APITypeCloudflareAzure APIType = "CLOUDFLARE_AZURE"
|
||||
)
|
||||
|
||||
const AzureAPIKeyHeader = "api-key"
|
||||
|
||||
const defaultAssistantVersion = "v1" // This will be deprecated by the end of 2024.
|
||||
|
||||
// ClientConfig is a configuration of a client.
|
||||
type ClientConfig struct {
|
||||
authToken string
|
||||
|
||||
BaseURL string
|
||||
OrgID string
|
||||
APIType APIType
|
||||
APIVersion string // required when APIType is APITypeAzure or APITypeAzureAD
|
||||
AssistantVersion string
|
||||
AzureModelMapperFunc func(model string) string // replace model to azure deployment name func
|
||||
HTTPClient *http.Client
|
||||
|
||||
EmptyMessagesLimit uint
|
||||
}
|
||||
|
||||
func DefaultConfig(authToken string) ClientConfig {
|
||||
return ClientConfig{
|
||||
authToken: authToken,
|
||||
BaseURL: openaiAPIURLv1,
|
||||
APIType: APITypeOpenAI,
|
||||
AssistantVersion: defaultAssistantVersion,
|
||||
OrgID: "",
|
||||
|
||||
HTTPClient: &http.Client{},
|
||||
|
||||
EmptyMessagesLimit: defaultEmptyMessagesLimit,
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultAzureConfig(apiKey, baseURL string) ClientConfig {
|
||||
return ClientConfig{
|
||||
authToken: apiKey,
|
||||
BaseURL: baseURL,
|
||||
OrgID: "",
|
||||
APIType: APITypeAzure,
|
||||
APIVersion: "2023-05-15",
|
||||
AzureModelMapperFunc: func(model string) string {
|
||||
return regexp.MustCompile(`[.:]`).ReplaceAllString(model, "")
|
||||
},
|
||||
|
||||
HTTPClient: &http.Client{},
|
||||
|
||||
EmptyMessagesLimit: defaultEmptyMessagesLimit,
|
||||
}
|
||||
}
|
||||
|
||||
func (ClientConfig) String() string {
|
||||
return "<OpenAI API ClientConfig>"
|
||||
}
|
||||
|
||||
func (c ClientConfig) GetAzureDeploymentByModel(model string) string {
|
||||
if c.AzureModelMapperFunc != nil {
|
||||
return c.AzureModelMapperFunc(model)
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
48
vendor/github.com/rugatling/go-openai/edits.go
generated
vendored
Normal file
48
vendor/github.com/rugatling/go-openai/edits.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// EditsRequest represents a request structure for Edits API.
|
||||
type EditsRequest struct {
|
||||
Model *string `json:"model,omitempty"`
|
||||
Input string `json:"input,omitempty"`
|
||||
Instruction string `json:"instruction,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Temperature float32 `json:"temperature,omitempty"`
|
||||
TopP float32 `json:"top_p,omitempty"`
|
||||
}
|
||||
|
||||
// EditsChoice represents one of possible edits.
|
||||
type EditsChoice struct {
|
||||
Text string `json:"text"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
// EditsResponse represents a response structure for Edits API.
|
||||
type EditsResponse struct {
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Usage Usage `json:"usage"`
|
||||
Choices []EditsChoice `json:"choices"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Edits Perform an API call to the Edits endpoint.
|
||||
/* Deprecated: Users of the Edits API and its associated models (e.g., text-davinci-edit-001 or code-davinci-edit-001)
|
||||
will need to migrate to GPT-3.5 Turbo by January 4, 2024.
|
||||
You can use CreateChatCompletion or CreateChatCompletionStream instead.
|
||||
*/
|
||||
func (c *Client) Edits(ctx context.Context, request EditsRequest) (response EditsResponse, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/edits", fmt.Sprint(request.Model)), withBody(request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
262
vendor/github.com/rugatling/go-openai/embeddings.go
generated
vendored
Normal file
262
vendor/github.com/rugatling/go-openai/embeddings.go
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var ErrVectorLengthMismatch = errors.New("vector length mismatch")
|
||||
|
||||
// EmbeddingModel enumerates the models which can be used
|
||||
// to generate Embedding vectors.
|
||||
type EmbeddingModel string
|
||||
|
||||
const (
|
||||
// Deprecated: The following block will be shut down on January 04, 2024. Use text-embedding-ada-002 instead.
|
||||
AdaSimilarity EmbeddingModel = "text-similarity-ada-001"
|
||||
BabbageSimilarity EmbeddingModel = "text-similarity-babbage-001"
|
||||
CurieSimilarity EmbeddingModel = "text-similarity-curie-001"
|
||||
DavinciSimilarity EmbeddingModel = "text-similarity-davinci-001"
|
||||
AdaSearchDocument EmbeddingModel = "text-search-ada-doc-001"
|
||||
AdaSearchQuery EmbeddingModel = "text-search-ada-query-001"
|
||||
BabbageSearchDocument EmbeddingModel = "text-search-babbage-doc-001"
|
||||
BabbageSearchQuery EmbeddingModel = "text-search-babbage-query-001"
|
||||
CurieSearchDocument EmbeddingModel = "text-search-curie-doc-001"
|
||||
CurieSearchQuery EmbeddingModel = "text-search-curie-query-001"
|
||||
DavinciSearchDocument EmbeddingModel = "text-search-davinci-doc-001"
|
||||
DavinciSearchQuery EmbeddingModel = "text-search-davinci-query-001"
|
||||
AdaCodeSearchCode EmbeddingModel = "code-search-ada-code-001"
|
||||
AdaCodeSearchText EmbeddingModel = "code-search-ada-text-001"
|
||||
BabbageCodeSearchCode EmbeddingModel = "code-search-babbage-code-001"
|
||||
BabbageCodeSearchText EmbeddingModel = "code-search-babbage-text-001"
|
||||
|
||||
AdaEmbeddingV2 EmbeddingModel = "text-embedding-ada-002"
|
||||
SmallEmbedding3 EmbeddingModel = "text-embedding-3-small"
|
||||
LargeEmbedding3 EmbeddingModel = "text-embedding-3-large"
|
||||
)
|
||||
|
||||
// Embedding is a special format of data representation that can be easily utilized by machine
|
||||
// learning models and algorithms. The embedding is an information dense representation of the
|
||||
// semantic meaning of a piece of text. Each embedding is a vector of floating point numbers,
|
||||
// such that the distance between two embeddings in the vector space is correlated with semantic similarity
|
||||
// between two inputs in the original format. For example, if two texts are similar,
|
||||
// then their vector representations should also be similar.
|
||||
type Embedding struct {
|
||||
Object string `json:"object"`
|
||||
Embedding []float32 `json:"embedding"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
// DotProduct calculates the dot product of the embedding vector with another
|
||||
// embedding vector. Both vectors must have the same length; otherwise, an
|
||||
// ErrVectorLengthMismatch is returned. The method returns the calculated dot
|
||||
// product as a float32 value.
|
||||
func (e *Embedding) DotProduct(other *Embedding) (float32, error) {
|
||||
if len(e.Embedding) != len(other.Embedding) {
|
||||
return 0, ErrVectorLengthMismatch
|
||||
}
|
||||
|
||||
var dotProduct float32
|
||||
for i := range e.Embedding {
|
||||
dotProduct += e.Embedding[i] * other.Embedding[i]
|
||||
}
|
||||
|
||||
return dotProduct, nil
|
||||
}
|
||||
|
||||
// EmbeddingResponse is the response from a Create embeddings request.
|
||||
type EmbeddingResponse struct {
|
||||
Object string `json:"object"`
|
||||
Data []Embedding `json:"data"`
|
||||
Model EmbeddingModel `json:"model"`
|
||||
Usage Usage `json:"usage"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type base64String string
|
||||
|
||||
func (b base64String) Decode() ([]float32, error) {
|
||||
decodedData, err := base64.StdEncoding.DecodeString(string(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
const sizeOfFloat32 = 4
|
||||
floats := make([]float32, len(decodedData)/sizeOfFloat32)
|
||||
for i := 0; i < len(floats); i++ {
|
||||
floats[i] = math.Float32frombits(binary.LittleEndian.Uint32(decodedData[i*4 : (i+1)*4]))
|
||||
}
|
||||
|
||||
return floats, nil
|
||||
}
|
||||
|
||||
// Base64Embedding is a container for base64 encoded embeddings.
|
||||
type Base64Embedding struct {
|
||||
Object string `json:"object"`
|
||||
Embedding base64String `json:"embedding"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
// EmbeddingResponseBase64 is the response from a Create embeddings request with base64 encoding format.
|
||||
type EmbeddingResponseBase64 struct {
|
||||
Object string `json:"object"`
|
||||
Data []Base64Embedding `json:"data"`
|
||||
Model EmbeddingModel `json:"model"`
|
||||
Usage Usage `json:"usage"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// ToEmbeddingResponse converts an embeddingResponseBase64 to an EmbeddingResponse.
|
||||
func (r *EmbeddingResponseBase64) ToEmbeddingResponse() (EmbeddingResponse, error) {
|
||||
data := make([]Embedding, len(r.Data))
|
||||
|
||||
for i, base64Embedding := range r.Data {
|
||||
embedding, err := base64Embedding.Embedding.Decode()
|
||||
if err != nil {
|
||||
return EmbeddingResponse{}, err
|
||||
}
|
||||
|
||||
data[i] = Embedding{
|
||||
Object: base64Embedding.Object,
|
||||
Embedding: embedding,
|
||||
Index: base64Embedding.Index,
|
||||
}
|
||||
}
|
||||
|
||||
return EmbeddingResponse{
|
||||
Object: r.Object,
|
||||
Model: r.Model,
|
||||
Data: data,
|
||||
Usage: r.Usage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type EmbeddingRequestConverter interface {
|
||||
// Needs to be of type EmbeddingRequestStrings or EmbeddingRequestTokens
|
||||
Convert() EmbeddingRequest
|
||||
}
|
||||
|
||||
// EmbeddingEncodingFormat is the format of the embeddings data.
|
||||
// Currently, only "float" and "base64" are supported, however, "base64" is not officially documented.
|
||||
// If not specified OpenAI will use "float".
|
||||
type EmbeddingEncodingFormat string
|
||||
|
||||
const (
|
||||
EmbeddingEncodingFormatFloat EmbeddingEncodingFormat = "float"
|
||||
EmbeddingEncodingFormatBase64 EmbeddingEncodingFormat = "base64"
|
||||
)
|
||||
|
||||
type EmbeddingRequest struct {
|
||||
Input any `json:"input"`
|
||||
Model EmbeddingModel `json:"model"`
|
||||
User string `json:"user"`
|
||||
EncodingFormat EmbeddingEncodingFormat `json:"encoding_format,omitempty"`
|
||||
// Dimensions The number of dimensions the resulting output embeddings should have.
|
||||
// Only supported in text-embedding-3 and later models.
|
||||
Dimensions int `json:"dimensions,omitempty"`
|
||||
}
|
||||
|
||||
func (r EmbeddingRequest) Convert() EmbeddingRequest {
|
||||
return r
|
||||
}
|
||||
|
||||
// EmbeddingRequestStrings is the input to a create embeddings request with a slice of strings.
|
||||
type EmbeddingRequestStrings struct {
|
||||
// Input is a slice of strings for which you want to generate an Embedding vector.
|
||||
// Each input must not exceed 8192 tokens in length.
|
||||
// OpenAPI suggests replacing newlines (\n) in your input with a single space, as they
|
||||
// have observed inferior results when newlines are present.
|
||||
// E.g.
|
||||
// "The food was delicious and the waiter..."
|
||||
Input []string `json:"input"`
|
||||
// ID of the model to use. You can use the List models API to see all of your available models,
|
||||
// or see our Model overview for descriptions of them.
|
||||
Model EmbeddingModel `json:"model"`
|
||||
// A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||
User string `json:"user"`
|
||||
// EmbeddingEncodingFormat is the format of the embeddings data.
|
||||
// Currently, only "float" and "base64" are supported, however, "base64" is not officially documented.
|
||||
// If not specified OpenAI will use "float".
|
||||
EncodingFormat EmbeddingEncodingFormat `json:"encoding_format,omitempty"`
|
||||
// Dimensions The number of dimensions the resulting output embeddings should have.
|
||||
// Only supported in text-embedding-3 and later models.
|
||||
Dimensions int `json:"dimensions,omitempty"`
|
||||
}
|
||||
|
||||
func (r EmbeddingRequestStrings) Convert() EmbeddingRequest {
|
||||
return EmbeddingRequest{
|
||||
Input: r.Input,
|
||||
Model: r.Model,
|
||||
User: r.User,
|
||||
EncodingFormat: r.EncodingFormat,
|
||||
Dimensions: r.Dimensions,
|
||||
}
|
||||
}
|
||||
|
||||
type EmbeddingRequestTokens struct {
|
||||
// Input is a slice of slices of ints ([][]int) for which you want to generate an Embedding vector.
|
||||
// Each input must not exceed 8192 tokens in length.
|
||||
// OpenAPI suggests replacing newlines (\n) in your input with a single space, as they
|
||||
// have observed inferior results when newlines are present.
|
||||
// E.g.
|
||||
// "The food was delicious and the waiter..."
|
||||
Input [][]int `json:"input"`
|
||||
// ID of the model to use. You can use the List models API to see all of your available models,
|
||||
// or see our Model overview for descriptions of them.
|
||||
Model EmbeddingModel `json:"model"`
|
||||
// A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||
User string `json:"user"`
|
||||
// EmbeddingEncodingFormat is the format of the embeddings data.
|
||||
// Currently, only "float" and "base64" are supported, however, "base64" is not officially documented.
|
||||
// If not specified OpenAI will use "float".
|
||||
EncodingFormat EmbeddingEncodingFormat `json:"encoding_format,omitempty"`
|
||||
// Dimensions The number of dimensions the resulting output embeddings should have.
|
||||
// Only supported in text-embedding-3 and later models.
|
||||
Dimensions int `json:"dimensions,omitempty"`
|
||||
}
|
||||
|
||||
func (r EmbeddingRequestTokens) Convert() EmbeddingRequest {
|
||||
return EmbeddingRequest{
|
||||
Input: r.Input,
|
||||
Model: r.Model,
|
||||
User: r.User,
|
||||
EncodingFormat: r.EncodingFormat,
|
||||
Dimensions: r.Dimensions,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateEmbeddings returns an EmbeddingResponse which will contain an Embedding for every item in |body.Input|.
|
||||
// https://beta.openai.com/docs/api-reference/embeddings/create
|
||||
//
|
||||
// Body should be of type EmbeddingRequestStrings for embedding strings or EmbeddingRequestTokens
|
||||
// for embedding groups of text already converted to tokens.
|
||||
func (c *Client) CreateEmbeddings(
|
||||
ctx context.Context,
|
||||
conv EmbeddingRequestConverter,
|
||||
) (res EmbeddingResponse, err error) {
|
||||
baseReq := conv.Convert()
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/embeddings", string(baseReq.Model)), withBody(baseReq))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if baseReq.EncodingFormat != EmbeddingEncodingFormatBase64 {
|
||||
err = c.sendRequest(req, &res)
|
||||
return
|
||||
}
|
||||
|
||||
base64Response := &EmbeddingResponseBase64{}
|
||||
err = c.sendRequest(req, base64Response)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res, err = base64Response.ToEmbeddingResponse()
|
||||
return
|
||||
}
|
||||
52
vendor/github.com/rugatling/go-openai/engines.go
generated
vendored
Normal file
52
vendor/github.com/rugatling/go-openai/engines.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Engine struct represents engine from OpenAPI API.
|
||||
type Engine struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Owner string `json:"owner"`
|
||||
Ready bool `json:"ready"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// EnginesList is a list of engines.
|
||||
type EnginesList struct {
|
||||
Engines []Engine `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// ListEngines Lists the currently available engines, and provides basic
|
||||
// information about each option such as the owner and availability.
|
||||
func (c *Client) ListEngines(ctx context.Context) (engines EnginesList, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/engines"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &engines)
|
||||
return
|
||||
}
|
||||
|
||||
// GetEngine Retrieves an engine instance, providing basic information about
|
||||
// the engine such as the owner and availability.
|
||||
func (c *Client) GetEngine(
|
||||
ctx context.Context,
|
||||
engineID string,
|
||||
) (engine Engine, err error) {
|
||||
urlSuffix := fmt.Sprintf("/engines/%s", engineID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &engine)
|
||||
return
|
||||
}
|
||||
109
vendor/github.com/rugatling/go-openai/error.go
generated
vendored
Normal file
109
vendor/github.com/rugatling/go-openai/error.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// APIError provides error information returned by the OpenAI API.
|
||||
// InnerError struct is only valid for Azure OpenAI Service.
|
||||
type APIError struct {
|
||||
Code any `json:"code,omitempty"`
|
||||
Message string `json:"message"`
|
||||
Param *string `json:"param,omitempty"`
|
||||
Type string `json:"type"`
|
||||
HTTPStatusCode int `json:"-"`
|
||||
InnerError *InnerError `json:"innererror,omitempty"`
|
||||
}
|
||||
|
||||
// InnerError Azure Content filtering. Only valid for Azure OpenAI Service.
|
||||
type InnerError struct {
|
||||
Code string `json:"code,omitempty"`
|
||||
ContentFilterResults ContentFilterResults `json:"content_filter_result,omitempty"`
|
||||
}
|
||||
|
||||
// RequestError provides information about generic request errors.
|
||||
type RequestError struct {
|
||||
HTTPStatusCode int
|
||||
Err error
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Error *APIError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (e *APIError) Error() string {
|
||||
if e.HTTPStatusCode > 0 {
|
||||
return fmt.Sprintf("error, status code: %d, message: %s", e.HTTPStatusCode, e.Message)
|
||||
}
|
||||
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func (e *APIError) UnmarshalJSON(data []byte) (err error) {
|
||||
var rawMap map[string]json.RawMessage
|
||||
err = json.Unmarshal(data, &rawMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawMap["message"], &e.Message)
|
||||
if err != nil {
|
||||
// If the parameter field of a function call is invalid as a JSON schema
|
||||
// refs: https://github.com/rugatling/go-openai/issues/381
|
||||
var messages []string
|
||||
err = json.Unmarshal(rawMap["message"], &messages)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.Message = strings.Join(messages, ", ")
|
||||
}
|
||||
|
||||
// optional fields for azure openai
|
||||
// refs: https://github.com/rugatling/go-openai/issues/343
|
||||
if _, ok := rawMap["type"]; ok {
|
||||
err = json.Unmarshal(rawMap["type"], &e.Type)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := rawMap["innererror"]; ok {
|
||||
err = json.Unmarshal(rawMap["innererror"], &e.InnerError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// optional fields
|
||||
if _, ok := rawMap["param"]; ok {
|
||||
err = json.Unmarshal(rawMap["param"], &e.Param)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := rawMap["code"]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the api returned a number, we need to force an integer
|
||||
// since the json package defaults to float64
|
||||
var intCode int
|
||||
err = json.Unmarshal(rawMap["code"], &intCode)
|
||||
if err == nil {
|
||||
e.Code = intCode
|
||||
return nil
|
||||
}
|
||||
|
||||
return json.Unmarshal(rawMap["code"], &e.Code)
|
||||
}
|
||||
|
||||
func (e *RequestError) Error() string {
|
||||
return fmt.Sprintf("error, status code: %d, message: %s", e.HTTPStatusCode, e.Err)
|
||||
}
|
||||
|
||||
func (e *RequestError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
169
vendor/github.com/rugatling/go-openai/files.go
generated
vendored
Normal file
169
vendor/github.com/rugatling/go-openai/files.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type FileRequest struct {
|
||||
FileName string `json:"file"`
|
||||
FilePath string `json:"-"`
|
||||
Purpose string `json:"purpose"`
|
||||
}
|
||||
|
||||
// PurposeType represents the purpose of the file when uploading.
|
||||
type PurposeType string
|
||||
|
||||
const (
|
||||
PurposeFineTune PurposeType = "fine-tune"
|
||||
PurposeFineTuneResults PurposeType = "fine-tune-results"
|
||||
PurposeAssistants PurposeType = "assistants"
|
||||
PurposeAssistantsOutput PurposeType = "assistants_output"
|
||||
)
|
||||
|
||||
// FileBytesRequest represents a file upload request.
|
||||
type FileBytesRequest struct {
|
||||
// the name of the uploaded file in OpenAI
|
||||
Name string
|
||||
// the bytes of the file
|
||||
Bytes []byte
|
||||
// the purpose of the file
|
||||
Purpose PurposeType
|
||||
}
|
||||
|
||||
// File struct represents an OpenAPI file.
|
||||
type File struct {
|
||||
Bytes int `json:"bytes"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
ID string `json:"id"`
|
||||
FileName string `json:"filename"`
|
||||
Object string `json:"object"`
|
||||
Status string `json:"status"`
|
||||
Purpose string `json:"purpose"`
|
||||
StatusDetails string `json:"status_details"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// FilesList is a list of files that belong to the user or organization.
|
||||
type FilesList struct {
|
||||
Files []File `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// CreateFileBytes uploads bytes directly to OpenAI without requiring a local file.
|
||||
func (c *Client) CreateFileBytes(ctx context.Context, request FileBytesRequest) (file File, err error) {
|
||||
var b bytes.Buffer
|
||||
reader := bytes.NewReader(request.Bytes)
|
||||
builder := c.createFormBuilder(&b)
|
||||
|
||||
err = builder.WriteField("purpose", string(request.Purpose))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.CreateFormFileReader("file", reader, request.Name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/files"),
|
||||
withBody(&b), withContentType(builder.FormDataContentType()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &file)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateFile uploads a jsonl file to GPT3
|
||||
// FilePath must be a local file path.
|
||||
func (c *Client) CreateFile(ctx context.Context, request FileRequest) (file File, err error) {
|
||||
var b bytes.Buffer
|
||||
builder := c.createFormBuilder(&b)
|
||||
|
||||
err = builder.WriteField("purpose", request.Purpose)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fileData, err := os.Open(request.FilePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.CreateFormFile("file", fileData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/files"),
|
||||
withBody(&b), withContentType(builder.FormDataContentType()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &file)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteFile deletes an existing file.
|
||||
func (c *Client) DeleteFile(ctx context.Context, fileID string) (err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL("/files/"+fileID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ListFiles Lists the currently available files,
|
||||
// and provides basic information about each file such as the file name and purpose.
|
||||
func (c *Client) ListFiles(ctx context.Context) (files FilesList, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/files"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &files)
|
||||
return
|
||||
}
|
||||
|
||||
// GetFile Retrieves a file instance, providing basic information about the file
|
||||
// such as the file name and purpose.
|
||||
func (c *Client) GetFile(ctx context.Context, fileID string) (file File, err error) {
|
||||
urlSuffix := fmt.Sprintf("/files/%s", fileID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &file)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) GetFileContent(ctx context.Context, fileID string) (content RawResponse, err error) {
|
||||
urlSuffix := fmt.Sprintf("/files/%s/content", fileID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return c.sendRequestRaw(req)
|
||||
}
|
||||
178
vendor/github.com/rugatling/go-openai/fine_tunes.go
generated
vendored
Normal file
178
vendor/github.com/rugatling/go-openai/fine_tunes.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTuneRequest struct {
|
||||
TrainingFile string `json:"training_file"`
|
||||
ValidationFile string `json:"validation_file,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Epochs int `json:"n_epochs,omitempty"`
|
||||
BatchSize int `json:"batch_size,omitempty"`
|
||||
LearningRateMultiplier float32 `json:"learning_rate_multiplier,omitempty"`
|
||||
PromptLossRate float32 `json:"prompt_loss_rate,omitempty"`
|
||||
ComputeClassificationMetrics bool `json:"compute_classification_metrics,omitempty"`
|
||||
ClassificationClasses int `json:"classification_n_classes,omitempty"`
|
||||
ClassificationPositiveClass string `json:"classification_positive_class,omitempty"`
|
||||
ClassificationBetas []float32 `json:"classification_betas,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty"`
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTune struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Model string `json:"model"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
FineTuneEventList []FineTuneEvent `json:"events,omitempty"`
|
||||
FineTunedModel string `json:"fine_tuned_model"`
|
||||
HyperParams FineTuneHyperParams `json:"hyperparams"`
|
||||
OrganizationID string `json:"organization_id"`
|
||||
ResultFiles []File `json:"result_files"`
|
||||
Status string `json:"status"`
|
||||
ValidationFiles []File `json:"validation_files"`
|
||||
TrainingFiles []File `json:"training_files"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTuneEvent struct {
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Level string `json:"level"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTuneHyperParams struct {
|
||||
BatchSize int `json:"batch_size"`
|
||||
LearningRateMultiplier float64 `json:"learning_rate_multiplier"`
|
||||
Epochs int `json:"n_epochs"`
|
||||
PromptLossWeight float64 `json:"prompt_loss_weight"`
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTuneList struct {
|
||||
Object string `json:"object"`
|
||||
Data []FineTune `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTuneEventList struct {
|
||||
Object string `json:"object"`
|
||||
Data []FineTuneEvent `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
type FineTuneDeleteResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Deleted bool `json:"deleted"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
func (c *Client) CreateFineTune(ctx context.Context, request FineTuneRequest) (response FineTune, err error) {
|
||||
urlSuffix := "/fine-tunes"
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// CancelFineTune cancel a fine-tune job.
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
func (c *Client) CancelFineTune(ctx context.Context, fineTuneID string) (response FineTune, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/fine-tunes/"+fineTuneID+"/cancel"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
func (c *Client) ListFineTunes(ctx context.Context) (response FineTuneList, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/fine-tunes"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
func (c *Client) GetFineTune(ctx context.Context, fineTuneID string) (response FineTune, err error) {
|
||||
urlSuffix := fmt.Sprintf("/fine-tunes/%s", fineTuneID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
func (c *Client) DeleteFineTune(ctx context.Context, fineTuneID string) (response FineTuneDeleteResponse, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL("/fine-tunes/"+fineTuneID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||
// This API will be officially deprecated on January 4th, 2024.
|
||||
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||
func (c *Client) ListFineTuneEvents(ctx context.Context, fineTuneID string) (response FineTuneEventList, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/fine-tunes/"+fineTuneID+"/events"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
157
vendor/github.com/rugatling/go-openai/fine_tuning_job.go
generated
vendored
Normal file
157
vendor/github.com/rugatling/go-openai/fine_tuning_job.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type FineTuningJob struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
FinishedAt int64 `json:"finished_at"`
|
||||
Model string `json:"model"`
|
||||
FineTunedModel string `json:"fine_tuned_model,omitempty"`
|
||||
OrganizationID string `json:"organization_id"`
|
||||
Status string `json:"status"`
|
||||
Hyperparameters Hyperparameters `json:"hyperparameters"`
|
||||
TrainingFile string `json:"training_file"`
|
||||
ValidationFile string `json:"validation_file,omitempty"`
|
||||
ResultFiles []string `json:"result_files"`
|
||||
TrainedTokens int `json:"trained_tokens"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type Hyperparameters struct {
|
||||
Epochs any `json:"n_epochs,omitempty"`
|
||||
}
|
||||
|
||||
type FineTuningJobRequest struct {
|
||||
TrainingFile string `json:"training_file"`
|
||||
ValidationFile string `json:"validation_file,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Hyperparameters *Hyperparameters `json:"hyperparameters,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty"`
|
||||
}
|
||||
|
||||
type FineTuningJobEventList struct {
|
||||
Object string `json:"object"`
|
||||
Data []FineTuneEvent `json:"data"`
|
||||
HasMore bool `json:"has_more"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type FineTuningJobEvent struct {
|
||||
Object string `json:"object"`
|
||||
ID string `json:"id"`
|
||||
CreatedAt int `json:"created_at"`
|
||||
Level string `json:"level"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// CreateFineTuningJob create a fine tuning job.
|
||||
func (c *Client) CreateFineTuningJob(
|
||||
ctx context.Context,
|
||||
request FineTuningJobRequest,
|
||||
) (response FineTuningJob, err error) {
|
||||
urlSuffix := "/fine_tuning/jobs"
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// CancelFineTuningJob cancel a fine tuning job.
|
||||
func (c *Client) CancelFineTuningJob(ctx context.Context, fineTuningJobID string) (response FineTuningJob, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/fine_tuning/jobs/"+fineTuningJobID+"/cancel"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveFineTuningJob retrieve a fine tuning job.
|
||||
func (c *Client) RetrieveFineTuningJob(
|
||||
ctx context.Context,
|
||||
fineTuningJobID string,
|
||||
) (response FineTuningJob, err error) {
|
||||
urlSuffix := fmt.Sprintf("/fine_tuning/jobs/%s", fineTuningJobID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
type listFineTuningJobEventsParameters struct {
|
||||
after *string
|
||||
limit *int
|
||||
}
|
||||
|
||||
type ListFineTuningJobEventsParameter func(*listFineTuningJobEventsParameters)
|
||||
|
||||
func ListFineTuningJobEventsWithAfter(after string) ListFineTuningJobEventsParameter {
|
||||
return func(args *listFineTuningJobEventsParameters) {
|
||||
args.after = &after
|
||||
}
|
||||
}
|
||||
|
||||
func ListFineTuningJobEventsWithLimit(limit int) ListFineTuningJobEventsParameter {
|
||||
return func(args *listFineTuningJobEventsParameters) {
|
||||
args.limit = &limit
|
||||
}
|
||||
}
|
||||
|
||||
// ListFineTuningJobs list fine tuning jobs events.
|
||||
func (c *Client) ListFineTuningJobEvents(
|
||||
ctx context.Context,
|
||||
fineTuningJobID string,
|
||||
setters ...ListFineTuningJobEventsParameter,
|
||||
) (response FineTuningJobEventList, err error) {
|
||||
parameters := &listFineTuningJobEventsParameters{
|
||||
after: nil,
|
||||
limit: nil,
|
||||
}
|
||||
|
||||
for _, setter := range setters {
|
||||
setter(parameters)
|
||||
}
|
||||
|
||||
urlValues := url.Values{}
|
||||
if parameters.after != nil {
|
||||
urlValues.Add("after", *parameters.after)
|
||||
}
|
||||
if parameters.limit != nil {
|
||||
urlValues.Add("limit", fmt.Sprintf("%d", *parameters.limit))
|
||||
}
|
||||
|
||||
encodedValues := ""
|
||||
if len(urlValues) > 0 {
|
||||
encodedValues = "?" + urlValues.Encode()
|
||||
}
|
||||
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
c.fullURL("/fine_tuning/jobs/"+fineTuningJobID+"/events"+encodedValues),
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
194
vendor/github.com/rugatling/go-openai/image.go
generated
vendored
Normal file
194
vendor/github.com/rugatling/go-openai/image.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Image sizes defined by the OpenAI API.
|
||||
const (
|
||||
CreateImageSize256x256 = "256x256"
|
||||
CreateImageSize512x512 = "512x512"
|
||||
CreateImageSize1024x1024 = "1024x1024"
|
||||
// dall-e-3 supported only.
|
||||
CreateImageSize1792x1024 = "1792x1024"
|
||||
CreateImageSize1024x1792 = "1024x1792"
|
||||
)
|
||||
|
||||
const (
|
||||
CreateImageResponseFormatURL = "url"
|
||||
CreateImageResponseFormatB64JSON = "b64_json"
|
||||
)
|
||||
|
||||
const (
|
||||
CreateImageModelDallE2 = "dall-e-2"
|
||||
CreateImageModelDallE3 = "dall-e-3"
|
||||
)
|
||||
|
||||
const (
|
||||
CreateImageQualityHD = "hd"
|
||||
CreateImageQualityStandard = "standard"
|
||||
)
|
||||
|
||||
const (
|
||||
CreateImageStyleVivid = "vivid"
|
||||
CreateImageStyleNatural = "natural"
|
||||
)
|
||||
|
||||
// ImageRequest represents the request structure for the image API.
|
||||
type ImageRequest struct {
|
||||
Prompt string `json:"prompt,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Quality string `json:"quality,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
Style string `json:"style,omitempty"`
|
||||
ResponseFormat string `json:"response_format,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
// ImageResponse represents a response structure for image API.
|
||||
type ImageResponse struct {
|
||||
Created int64 `json:"created,omitempty"`
|
||||
Data []ImageResponseDataInner `json:"data,omitempty"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// ImageResponseDataInner represents a response data structure for image API.
|
||||
type ImageResponseDataInner struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
B64JSON string `json:"b64_json,omitempty"`
|
||||
RevisedPrompt string `json:"revised_prompt,omitempty"`
|
||||
}
|
||||
|
||||
// CreateImage - API call to create an image. This is the main endpoint of the DALL-E API.
|
||||
func (c *Client) CreateImage(ctx context.Context, request ImageRequest) (response ImageResponse, err error) {
|
||||
urlSuffix := "/images/generations"
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix, request.Model), withBody(request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ImageEditRequest represents the request structure for the image API.
|
||||
type ImageEditRequest struct {
|
||||
Image *os.File `json:"image,omitempty"`
|
||||
Mask *os.File `json:"mask,omitempty"`
|
||||
Prompt string `json:"prompt,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
ResponseFormat string `json:"response_format,omitempty"`
|
||||
}
|
||||
|
||||
// CreateEditImage - API call to create an image. This is the main endpoint of the DALL-E API.
|
||||
func (c *Client) CreateEditImage(ctx context.Context, request ImageEditRequest) (response ImageResponse, err error) {
|
||||
body := &bytes.Buffer{}
|
||||
builder := c.createFormBuilder(body)
|
||||
|
||||
// image
|
||||
err = builder.CreateFormFile("image", request.Image)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// mask, it is optional
|
||||
if request.Mask != nil {
|
||||
err = builder.CreateFormFile("mask", request.Mask)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = builder.WriteField("prompt", request.Prompt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.WriteField("n", strconv.Itoa(request.N))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.WriteField("size", request.Size)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.WriteField("response_format", request.ResponseFormat)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/images/edits", request.Model),
|
||||
withBody(body), withContentType(builder.FormDataContentType()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ImageVariRequest represents the request structure for the image API.
|
||||
type ImageVariRequest struct {
|
||||
Image *os.File `json:"image,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
ResponseFormat string `json:"response_format,omitempty"`
|
||||
}
|
||||
|
||||
// CreateVariImage - API call to create an image variation. This is the main endpoint of the DALL-E API.
|
||||
// Use abbreviations(vari for variation) because ci-lint has a single-line length limit ...
|
||||
func (c *Client) CreateVariImage(ctx context.Context, request ImageVariRequest) (response ImageResponse, err error) {
|
||||
body := &bytes.Buffer{}
|
||||
builder := c.createFormBuilder(body)
|
||||
|
||||
// image
|
||||
err = builder.CreateFormFile("image", request.Image)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.WriteField("n", strconv.Itoa(request.N))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.WriteField("size", request.Size)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.WriteField("response_format", request.ResponseFormat)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = builder.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/images/variations", request.Model),
|
||||
withBody(body), withContentType(builder.FormDataContentType()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
44
vendor/github.com/rugatling/go-openai/internal/error_accumulator.go
generated
vendored
Normal file
44
vendor/github.com/rugatling/go-openai/internal/error_accumulator.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ErrorAccumulator interface {
|
||||
Write(p []byte) error
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
type errorBuffer interface {
|
||||
io.Writer
|
||||
Len() int
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
type DefaultErrorAccumulator struct {
|
||||
Buffer errorBuffer
|
||||
}
|
||||
|
||||
func NewErrorAccumulator() ErrorAccumulator {
|
||||
return &DefaultErrorAccumulator{
|
||||
Buffer: &bytes.Buffer{},
|
||||
}
|
||||
}
|
||||
|
||||
func (e *DefaultErrorAccumulator) Write(p []byte) error {
|
||||
_, err := e.Buffer.Write(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error accumulator write error, %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *DefaultErrorAccumulator) Bytes() (errBytes []byte) {
|
||||
if e.Buffer.Len() == 0 {
|
||||
return
|
||||
}
|
||||
errBytes = e.Buffer.Bytes()
|
||||
return
|
||||
}
|
||||
65
vendor/github.com/rugatling/go-openai/internal/form_builder.go
generated
vendored
Normal file
65
vendor/github.com/rugatling/go-openai/internal/form_builder.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
type FormBuilder interface {
|
||||
CreateFormFile(fieldname string, file *os.File) error
|
||||
CreateFormFileReader(fieldname string, r io.Reader, filename string) error
|
||||
WriteField(fieldname, value string) error
|
||||
Close() error
|
||||
FormDataContentType() string
|
||||
}
|
||||
|
||||
type DefaultFormBuilder struct {
|
||||
writer *multipart.Writer
|
||||
}
|
||||
|
||||
func NewFormBuilder(body io.Writer) *DefaultFormBuilder {
|
||||
return &DefaultFormBuilder{
|
||||
writer: multipart.NewWriter(body),
|
||||
}
|
||||
}
|
||||
|
||||
func (fb *DefaultFormBuilder) CreateFormFile(fieldname string, file *os.File) error {
|
||||
return fb.createFormFile(fieldname, file, file.Name())
|
||||
}
|
||||
|
||||
func (fb *DefaultFormBuilder) CreateFormFileReader(fieldname string, r io.Reader, filename string) error {
|
||||
return fb.createFormFile(fieldname, r, path.Base(filename))
|
||||
}
|
||||
|
||||
func (fb *DefaultFormBuilder) createFormFile(fieldname string, r io.Reader, filename string) error {
|
||||
if filename == "" {
|
||||
return fmt.Errorf("filename cannot be empty")
|
||||
}
|
||||
|
||||
fieldWriter, err := fb.writer.CreateFormFile(fieldname, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(fieldWriter, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fb *DefaultFormBuilder) WriteField(fieldname, value string) error {
|
||||
return fb.writer.WriteField(fieldname, value)
|
||||
}
|
||||
|
||||
func (fb *DefaultFormBuilder) Close() error {
|
||||
return fb.writer.Close()
|
||||
}
|
||||
|
||||
func (fb *DefaultFormBuilder) FormDataContentType() string {
|
||||
return fb.writer.FormDataContentType()
|
||||
}
|
||||
15
vendor/github.com/rugatling/go-openai/internal/marshaller.go
generated
vendored
Normal file
15
vendor/github.com/rugatling/go-openai/internal/marshaller.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Marshaller interface {
|
||||
Marshal(value any) ([]byte, error)
|
||||
}
|
||||
|
||||
type JSONMarshaller struct{}
|
||||
|
||||
func (jm *JSONMarshaller) Marshal(value any) ([]byte, error) {
|
||||
return json.Marshal(value)
|
||||
}
|
||||
52
vendor/github.com/rugatling/go-openai/internal/request_builder.go
generated
vendored
Normal file
52
vendor/github.com/rugatling/go-openai/internal/request_builder.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type RequestBuilder interface {
|
||||
Build(ctx context.Context, method, url string, body any, header http.Header) (*http.Request, error)
|
||||
}
|
||||
|
||||
type HTTPRequestBuilder struct {
|
||||
marshaller Marshaller
|
||||
}
|
||||
|
||||
func NewRequestBuilder() *HTTPRequestBuilder {
|
||||
return &HTTPRequestBuilder{
|
||||
marshaller: &JSONMarshaller{},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *HTTPRequestBuilder) Build(
|
||||
ctx context.Context,
|
||||
method string,
|
||||
url string,
|
||||
body any,
|
||||
header http.Header,
|
||||
) (req *http.Request, err error) {
|
||||
var bodyReader io.Reader
|
||||
if body != nil {
|
||||
if v, ok := body.(io.Reader); ok {
|
||||
bodyReader = v
|
||||
} else {
|
||||
var reqBytes []byte
|
||||
reqBytes, err = b.marshaller.Marshal(body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bodyReader = bytes.NewBuffer(reqBytes)
|
||||
}
|
||||
}
|
||||
req, err = http.NewRequestWithContext(ctx, method, url, bodyReader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if header != nil {
|
||||
req.Header = header
|
||||
}
|
||||
return
|
||||
}
|
||||
15
vendor/github.com/rugatling/go-openai/internal/unmarshaler.go
generated
vendored
Normal file
15
vendor/github.com/rugatling/go-openai/internal/unmarshaler.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Unmarshaler interface {
|
||||
Unmarshal(data []byte, v any) error
|
||||
}
|
||||
|
||||
type JSONUnmarshaler struct{}
|
||||
|
||||
func (jm *JSONUnmarshaler) Unmarshal(data []byte, v any) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
188
vendor/github.com/rugatling/go-openai/messages.go
generated
vendored
Normal file
188
vendor/github.com/rugatling/go-openai/messages.go
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
messagesSuffix = "messages"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int `json:"created_at"`
|
||||
ThreadID string `json:"thread_id"`
|
||||
Role string `json:"role"`
|
||||
Content []MessageContent `json:"content"`
|
||||
FileIds []string `json:"file_ids"` //nolint:revive //backwards-compatibility
|
||||
AssistantID *string `json:"assistant_id,omitempty"`
|
||||
RunID *string `json:"run_id,omitempty"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type MessagesList struct {
|
||||
Messages []Message `json:"data"`
|
||||
|
||||
Object string `json:"object"`
|
||||
FirstID *string `json:"first_id"`
|
||||
LastID *string `json:"last_id"`
|
||||
HasMore bool `json:"has_more"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type MessageContent struct {
|
||||
Type string `json:"type"`
|
||||
Text *MessageText `json:"text,omitempty"`
|
||||
ImageFile *ImageFile `json:"image_file,omitempty"`
|
||||
}
|
||||
type MessageText struct {
|
||||
Value string `json:"value"`
|
||||
Annotations []any `json:"annotations"`
|
||||
}
|
||||
|
||||
type ImageFile struct {
|
||||
FileID string `json:"file_id"`
|
||||
}
|
||||
|
||||
type MessageRequest struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
FileIds []string `json:"file_ids,omitempty"` //nolint:revive // backwards-compatibility
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type MessageFile struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int `json:"created_at"`
|
||||
MessageID string `json:"message_id"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type MessageFilesList struct {
|
||||
MessageFiles []MessageFile `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// CreateMessage creates a new message.
|
||||
func (c *Client) CreateMessage(ctx context.Context, threadID string, request MessageRequest) (msg Message, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/%s", threadID, messagesSuffix)
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
// ListMessage fetches all messages in the thread.
|
||||
func (c *Client) ListMessage(ctx context.Context, threadID string,
|
||||
limit *int,
|
||||
order *string,
|
||||
after *string,
|
||||
before *string,
|
||||
) (messages MessagesList, err error) {
|
||||
urlValues := url.Values{}
|
||||
if limit != nil {
|
||||
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||
}
|
||||
if order != nil {
|
||||
urlValues.Add("order", *order)
|
||||
}
|
||||
if after != nil {
|
||||
urlValues.Add("after", *after)
|
||||
}
|
||||
if before != nil {
|
||||
urlValues.Add("before", *before)
|
||||
}
|
||||
encodedValues := ""
|
||||
if len(urlValues) > 0 {
|
||||
encodedValues = "?" + urlValues.Encode()
|
||||
}
|
||||
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/%s%s", threadID, messagesSuffix, encodedValues)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &messages)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveMessage retrieves a Message.
|
||||
func (c *Client) RetrieveMessage(
|
||||
ctx context.Context,
|
||||
threadID, messageID string,
|
||||
) (msg Message, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
// ModifyMessage modifies a message.
|
||||
func (c *Client) ModifyMessage(
|
||||
ctx context.Context,
|
||||
threadID, messageID string,
|
||||
metadata map[string]string,
|
||||
) (msg Message, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||
withBody(map[string]any{"metadata": metadata}), withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveMessageFile fetches a message file.
|
||||
func (c *Client) RetrieveMessageFile(
|
||||
ctx context.Context,
|
||||
threadID, messageID, fileID string,
|
||||
) (file MessageFile, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s/files/%s", threadID, messagesSuffix, messageID, fileID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &file)
|
||||
return
|
||||
}
|
||||
|
||||
// ListMessageFiles fetches all files attached to a message.
|
||||
func (c *Client) ListMessageFiles(
|
||||
ctx context.Context,
|
||||
threadID, messageID string,
|
||||
) (files MessageFilesList, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s/files", threadID, messagesSuffix, messageID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &files)
|
||||
return
|
||||
}
|
||||
90
vendor/github.com/rugatling/go-openai/models.go
generated
vendored
Normal file
90
vendor/github.com/rugatling/go-openai/models.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Model struct represents an OpenAPI model.
|
||||
type Model struct {
|
||||
CreatedAt int64 `json:"created"`
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
OwnedBy string `json:"owned_by"`
|
||||
Permission []Permission `json:"permission"`
|
||||
Root string `json:"root"`
|
||||
Parent string `json:"parent"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Permission struct represents an OpenAPI permission.
|
||||
type Permission struct {
|
||||
CreatedAt int64 `json:"created"`
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
AllowCreateEngine bool `json:"allow_create_engine"`
|
||||
AllowSampling bool `json:"allow_sampling"`
|
||||
AllowLogprobs bool `json:"allow_logprobs"`
|
||||
AllowSearchIndices bool `json:"allow_search_indices"`
|
||||
AllowView bool `json:"allow_view"`
|
||||
AllowFineTuning bool `json:"allow_fine_tuning"`
|
||||
Organization string `json:"organization"`
|
||||
Group interface{} `json:"group"`
|
||||
IsBlocking bool `json:"is_blocking"`
|
||||
}
|
||||
|
||||
// FineTuneModelDeleteResponse represents the deletion status of a fine-tuned model.
|
||||
type FineTuneModelDeleteResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Deleted bool `json:"deleted"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// ModelsList is a list of models, including those that belong to the user or organization.
|
||||
type ModelsList struct {
|
||||
Models []Model `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// ListModels Lists the currently available models,
|
||||
// and provides basic information about each model such as the model id and parent.
|
||||
func (c *Client) ListModels(ctx context.Context) (models ModelsList, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/models"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &models)
|
||||
return
|
||||
}
|
||||
|
||||
// GetModel Retrieves a model instance, providing basic information about
|
||||
// the model such as the owner and permissioning.
|
||||
func (c *Client) GetModel(ctx context.Context, modelID string) (model Model, err error) {
|
||||
urlSuffix := fmt.Sprintf("/models/%s", modelID)
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &model)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteFineTuneModel Deletes a fine-tune model. You must have the Owner
|
||||
// role in your organization to delete a model.
|
||||
func (c *Client) DeleteFineTuneModel(ctx context.Context, modelID string) (
|
||||
response FineTuneModelDeleteResponse, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL("/models/"+modelID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
98
vendor/github.com/rugatling/go-openai/moderation.go
generated
vendored
Normal file
98
vendor/github.com/rugatling/go-openai/moderation.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// The moderation endpoint is a tool you can use to check whether content complies with OpenAI's usage policies.
|
||||
// Developers can thus identify content that our usage policies prohibits and take action, for instance by filtering it.
|
||||
|
||||
// The default is text-moderation-latest which will be automatically upgraded over time.
|
||||
// This ensures you are always using our most accurate model.
|
||||
// If you use text-moderation-stable, we will provide advanced notice before updating the model.
|
||||
// Accuracy of text-moderation-stable may be slightly lower than for text-moderation-latest.
|
||||
const (
|
||||
ModerationTextStable = "text-moderation-stable"
|
||||
ModerationTextLatest = "text-moderation-latest"
|
||||
// Deprecated: use ModerationTextStable and ModerationTextLatest instead.
|
||||
ModerationText001 = "text-moderation-001"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrModerationInvalidModel = errors.New("this model is not supported with moderation, please use text-moderation-stable or text-moderation-latest instead") //nolint:lll
|
||||
)
|
||||
|
||||
var validModerationModel = map[string]struct{}{
|
||||
ModerationTextStable: {},
|
||||
ModerationTextLatest: {},
|
||||
}
|
||||
|
||||
// ModerationRequest represents a request structure for moderation API.
|
||||
type ModerationRequest struct {
|
||||
Input string `json:"input,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
}
|
||||
|
||||
// Result represents one of possible moderation results.
|
||||
type Result struct {
|
||||
Categories ResultCategories `json:"categories"`
|
||||
CategoryScores ResultCategoryScores `json:"category_scores"`
|
||||
Flagged bool `json:"flagged"`
|
||||
}
|
||||
|
||||
// ResultCategories represents Categories of Result.
|
||||
type ResultCategories struct {
|
||||
Hate bool `json:"hate"`
|
||||
HateThreatening bool `json:"hate/threatening"`
|
||||
Harassment bool `json:"harassment"`
|
||||
HarassmentThreatening bool `json:"harassment/threatening"`
|
||||
SelfHarm bool `json:"self-harm"`
|
||||
SelfHarmIntent bool `json:"self-harm/intent"`
|
||||
SelfHarmInstructions bool `json:"self-harm/instructions"`
|
||||
Sexual bool `json:"sexual"`
|
||||
SexualMinors bool `json:"sexual/minors"`
|
||||
Violence bool `json:"violence"`
|
||||
ViolenceGraphic bool `json:"violence/graphic"`
|
||||
}
|
||||
|
||||
// ResultCategoryScores represents CategoryScores of Result.
|
||||
type ResultCategoryScores struct {
|
||||
Hate float32 `json:"hate"`
|
||||
HateThreatening float32 `json:"hate/threatening"`
|
||||
Harassment float32 `json:"harassment"`
|
||||
HarassmentThreatening float32 `json:"harassment/threatening"`
|
||||
SelfHarm float32 `json:"self-harm"`
|
||||
SelfHarmIntent float32 `json:"self-harm/intent"`
|
||||
SelfHarmInstructions float32 `json:"self-harm/instructions"`
|
||||
Sexual float32 `json:"sexual"`
|
||||
SexualMinors float32 `json:"sexual/minors"`
|
||||
Violence float32 `json:"violence"`
|
||||
ViolenceGraphic float32 `json:"violence/graphic"`
|
||||
}
|
||||
|
||||
// ModerationResponse represents a response structure for moderation API.
|
||||
type ModerationResponse struct {
|
||||
ID string `json:"id"`
|
||||
Model string `json:"model"`
|
||||
Results []Result `json:"results"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// Moderations — perform a moderation api call over a string.
|
||||
// Input can be an array or slice but a string will reduce the complexity.
|
||||
func (c *Client) Moderations(ctx context.Context, request ModerationRequest) (response ModerationResponse, err error) {
|
||||
if _, ok := validModerationModel[request.Model]; len(request.Model) > 0 && !ok {
|
||||
err = ErrModerationInvalidModel
|
||||
return
|
||||
}
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/moderations", request.Model), withBody(&request))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
43
vendor/github.com/rugatling/go-openai/ratelimit.go
generated
vendored
Normal file
43
vendor/github.com/rugatling/go-openai/ratelimit.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RateLimitHeaders struct represents Openai rate limits headers.
|
||||
type RateLimitHeaders struct {
|
||||
LimitRequests int `json:"x-ratelimit-limit-requests"`
|
||||
LimitTokens int `json:"x-ratelimit-limit-tokens"`
|
||||
RemainingRequests int `json:"x-ratelimit-remaining-requests"`
|
||||
RemainingTokens int `json:"x-ratelimit-remaining-tokens"`
|
||||
ResetRequests ResetTime `json:"x-ratelimit-reset-requests"`
|
||||
ResetTokens ResetTime `json:"x-ratelimit-reset-tokens"`
|
||||
}
|
||||
|
||||
type ResetTime string
|
||||
|
||||
func (r ResetTime) String() string {
|
||||
return string(r)
|
||||
}
|
||||
|
||||
func (r ResetTime) Time() time.Time {
|
||||
d, _ := time.ParseDuration(string(r))
|
||||
return time.Now().Add(d)
|
||||
}
|
||||
|
||||
func newRateLimitHeaders(h http.Header) RateLimitHeaders {
|
||||
limitReq, _ := strconv.Atoi(h.Get("x-ratelimit-limit-requests"))
|
||||
limitTokens, _ := strconv.Atoi(h.Get("x-ratelimit-limit-tokens"))
|
||||
remainingReq, _ := strconv.Atoi(h.Get("x-ratelimit-remaining-requests"))
|
||||
remainingTokens, _ := strconv.Atoi(h.Get("x-ratelimit-remaining-tokens"))
|
||||
return RateLimitHeaders{
|
||||
LimitRequests: limitReq,
|
||||
LimitTokens: limitTokens,
|
||||
RemainingRequests: remainingReq,
|
||||
RemainingTokens: remainingTokens,
|
||||
ResetRequests: ResetTime(h.Get("x-ratelimit-reset-requests")),
|
||||
ResetTokens: ResetTime(h.Get("x-ratelimit-reset-tokens")),
|
||||
}
|
||||
}
|
||||
437
vendor/github.com/rugatling/go-openai/run.go
generated
vendored
Normal file
437
vendor/github.com/rugatling/go-openai/run.go
generated
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Run struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
ThreadID string `json:"thread_id"`
|
||||
AssistantID string `json:"assistant_id"`
|
||||
Status RunStatus `json:"status"`
|
||||
RequiredAction *RunRequiredAction `json:"required_action,omitempty"`
|
||||
LastError *RunLastError `json:"last_error,omitempty"`
|
||||
ExpiresAt int64 `json:"expires_at"`
|
||||
StartedAt *int64 `json:"started_at,omitempty"`
|
||||
CancelledAt *int64 `json:"cancelled_at,omitempty"`
|
||||
FailedAt *int64 `json:"failed_at,omitempty"`
|
||||
CompletedAt *int64 `json:"completed_at,omitempty"`
|
||||
Model string `json:"model"`
|
||||
Instructions string `json:"instructions,omitempty"`
|
||||
Tools []Tool `json:"tools"`
|
||||
FileIDS []string `json:"file_ids"` //nolint:revive // backwards-compatibility
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
Usage Usage `json:"usage,omitempty"`
|
||||
|
||||
Temperature *float32 `json:"temperature,omitempty"`
|
||||
// The maximum number of prompt tokens that may be used over the course of the run.
|
||||
// If the run exceeds the number of prompt tokens specified, the run will end with status 'complete'.
|
||||
MaxPromptTokens int `json:"max_prompt_tokens,omitempty"`
|
||||
// The maximum number of completion tokens that may be used over the course of the run.
|
||||
// If the run exceeds the number of completion tokens specified, the run will end with status 'complete'.
|
||||
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
|
||||
// ThreadTruncationStrategy defines the truncation strategy to use for the thread.
|
||||
TruncationStrategy *ThreadTruncationStrategy `json:"truncation_strategy,omitempty"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type RunStatus string
|
||||
|
||||
const (
|
||||
RunStatusQueued RunStatus = "queued"
|
||||
RunStatusInProgress RunStatus = "in_progress"
|
||||
RunStatusRequiresAction RunStatus = "requires_action"
|
||||
RunStatusCancelling RunStatus = "cancelling"
|
||||
RunStatusFailed RunStatus = "failed"
|
||||
RunStatusCompleted RunStatus = "completed"
|
||||
RunStatusExpired RunStatus = "expired"
|
||||
RunStatusCancelled RunStatus = "cancelled"
|
||||
)
|
||||
|
||||
type RunRequiredAction struct {
|
||||
Type RequiredActionType `json:"type"`
|
||||
SubmitToolOutputs *SubmitToolOutputs `json:"submit_tool_outputs,omitempty"`
|
||||
}
|
||||
|
||||
type RequiredActionType string
|
||||
|
||||
const (
|
||||
RequiredActionTypeSubmitToolOutputs RequiredActionType = "submit_tool_outputs"
|
||||
)
|
||||
|
||||
type SubmitToolOutputs struct {
|
||||
ToolCalls []ToolCall `json:"tool_calls"`
|
||||
}
|
||||
|
||||
type RunLastError struct {
|
||||
Code RunError `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type RunError string
|
||||
|
||||
const (
|
||||
RunErrorServerError RunError = "server_error"
|
||||
RunErrorRateLimitExceeded RunError = "rate_limit_exceeded"
|
||||
)
|
||||
|
||||
type RunRequest struct {
|
||||
AssistantID string `json:"assistant_id"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Instructions string `json:"instructions,omitempty"`
|
||||
AdditionalInstructions string `json:"additional_instructions,omitempty"`
|
||||
Tools []Tool `json:"tools,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
|
||||
// Sampling temperature between 0 and 2. Higher values like 0.8 are more random.
|
||||
// lower values are more focused and deterministic.
|
||||
Temperature *float32 `json:"temperature,omitempty"`
|
||||
|
||||
// The maximum number of prompt tokens that may be used over the course of the run.
|
||||
// If the run exceeds the number of prompt tokens specified, the run will end with status 'complete'.
|
||||
MaxPromptTokens int `json:"max_prompt_tokens,omitempty"`
|
||||
|
||||
// The maximum number of completion tokens that may be used over the course of the run.
|
||||
// If the run exceeds the number of completion tokens specified, the run will end with status 'complete'.
|
||||
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
|
||||
|
||||
// ThreadTruncationStrategy defines the truncation strategy to use for the thread.
|
||||
TruncationStrategy *ThreadTruncationStrategy `json:"truncation_strategy,omitempty"`
|
||||
}
|
||||
|
||||
// ThreadTruncationStrategy defines the truncation strategy to use for the thread.
|
||||
// https://platform.openai.com/docs/assistants/how-it-works/truncation-strategy.
|
||||
type ThreadTruncationStrategy struct {
|
||||
// default 'auto'.
|
||||
Type TruncationStrategy `json:"type,omitempty"`
|
||||
// this field should be set if the truncation strategy is set to LastMessages.
|
||||
LastMessages *int `json:"last_messages,omitempty"`
|
||||
}
|
||||
|
||||
// TruncationStrategy defines the existing truncation strategies existing for thread management in an assistant.
|
||||
type TruncationStrategy string
|
||||
|
||||
const (
|
||||
// TruncationStrategyAuto messages in the middle of the thread will be dropped to fit the context length of the model.
|
||||
TruncationStrategyAuto = TruncationStrategy("auto")
|
||||
// TruncationStrategyLastMessages the thread will be truncated to the n most recent messages in the thread.
|
||||
TruncationStrategyLastMessages = TruncationStrategy("last_messages")
|
||||
)
|
||||
|
||||
type RunModifyRequest struct {
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// RunList is a list of runs.
|
||||
type RunList struct {
|
||||
Runs []Run `json:"data"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type SubmitToolOutputsRequest struct {
|
||||
ToolOutputs []ToolOutput `json:"tool_outputs"`
|
||||
}
|
||||
|
||||
type ToolOutput struct {
|
||||
ToolCallID string `json:"tool_call_id"`
|
||||
Output any `json:"output"`
|
||||
}
|
||||
|
||||
type CreateThreadAndRunRequest struct {
|
||||
RunRequest
|
||||
Thread ThreadRequest `json:"thread"`
|
||||
}
|
||||
|
||||
type RunStep struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
AssistantID string `json:"assistant_id"`
|
||||
ThreadID string `json:"thread_id"`
|
||||
RunID string `json:"run_id"`
|
||||
Type RunStepType `json:"type"`
|
||||
Status RunStepStatus `json:"status"`
|
||||
StepDetails StepDetails `json:"step_details"`
|
||||
LastError *RunLastError `json:"last_error,omitempty"`
|
||||
ExpiredAt *int64 `json:"expired_at,omitempty"`
|
||||
CancelledAt *int64 `json:"cancelled_at,omitempty"`
|
||||
FailedAt *int64 `json:"failed_at,omitempty"`
|
||||
CompletedAt *int64 `json:"completed_at,omitempty"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type RunStepStatus string
|
||||
|
||||
const (
|
||||
RunStepStatusInProgress RunStepStatus = "in_progress"
|
||||
RunStepStatusCancelling RunStepStatus = "cancelled"
|
||||
RunStepStatusFailed RunStepStatus = "failed"
|
||||
RunStepStatusCompleted RunStepStatus = "completed"
|
||||
RunStepStatusExpired RunStepStatus = "expired"
|
||||
)
|
||||
|
||||
type RunStepType string
|
||||
|
||||
const (
|
||||
RunStepTypeMessageCreation RunStepType = "message_creation"
|
||||
RunStepTypeToolCalls RunStepType = "tool_calls"
|
||||
)
|
||||
|
||||
type StepDetails struct {
|
||||
Type RunStepType `json:"type"`
|
||||
MessageCreation *StepDetailsMessageCreation `json:"message_creation,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type StepDetailsMessageCreation struct {
|
||||
MessageID string `json:"message_id"`
|
||||
}
|
||||
|
||||
// RunStepList is a list of steps.
|
||||
type RunStepList struct {
|
||||
RunSteps []RunStep `json:"data"`
|
||||
|
||||
FirstID string `json:"first_id"`
|
||||
LastID string `json:"last_id"`
|
||||
HasMore bool `json:"has_more"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type Pagination struct {
|
||||
Limit *int
|
||||
Order *string
|
||||
After *string
|
||||
Before *string
|
||||
}
|
||||
|
||||
// CreateRun creates a new run.
|
||||
func (c *Client) CreateRun(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
request RunRequest,
|
||||
) (response Run, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs", threadID)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
c.fullURL(urlSuffix),
|
||||
withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveRun retrieves a run.
|
||||
func (c *Client) RetrieveRun(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
runID string,
|
||||
) (response Run, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s", threadID, runID)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ModifyRun modifies a run.
|
||||
func (c *Client) ModifyRun(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
runID string,
|
||||
request RunModifyRequest,
|
||||
) (response Run, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s", threadID, runID)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
c.fullURL(urlSuffix),
|
||||
withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ListRuns lists runs.
|
||||
func (c *Client) ListRuns(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
pagination Pagination,
|
||||
) (response RunList, err error) {
|
||||
urlValues := url.Values{}
|
||||
if pagination.Limit != nil {
|
||||
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||
}
|
||||
if pagination.Order != nil {
|
||||
urlValues.Add("order", *pagination.Order)
|
||||
}
|
||||
if pagination.After != nil {
|
||||
urlValues.Add("after", *pagination.After)
|
||||
}
|
||||
if pagination.Before != nil {
|
||||
urlValues.Add("before", *pagination.Before)
|
||||
}
|
||||
|
||||
encodedValues := ""
|
||||
if len(urlValues) > 0 {
|
||||
encodedValues = "?" + urlValues.Encode()
|
||||
}
|
||||
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs%s", threadID, encodedValues)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// SubmitToolOutputs submits tool outputs.
|
||||
func (c *Client) SubmitToolOutputs(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
runID string,
|
||||
request SubmitToolOutputsRequest) (response Run, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/submit_tool_outputs", threadID, runID)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
c.fullURL(urlSuffix),
|
||||
withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// CancelRun cancels a run.
|
||||
func (c *Client) CancelRun(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
runID string) (response Run, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/cancel", threadID, runID)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateThreadAndRun submits tool outputs.
|
||||
func (c *Client) CreateThreadAndRun(
|
||||
ctx context.Context,
|
||||
request CreateThreadAndRunRequest) (response Run, err error) {
|
||||
urlSuffix := "/threads/runs"
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
c.fullURL(urlSuffix),
|
||||
withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveRunStep retrieves a run step.
|
||||
func (c *Client) RetrieveRunStep(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
runID string,
|
||||
stepID string,
|
||||
) (response RunStep, err error) {
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/steps/%s", threadID, runID, stepID)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ListRunSteps lists run steps.
|
||||
func (c *Client) ListRunSteps(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
runID string,
|
||||
pagination Pagination,
|
||||
) (response RunStepList, err error) {
|
||||
urlValues := url.Values{}
|
||||
if pagination.Limit != nil {
|
||||
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||
}
|
||||
if pagination.Order != nil {
|
||||
urlValues.Add("order", *pagination.Order)
|
||||
}
|
||||
if pagination.After != nil {
|
||||
urlValues.Add("after", *pagination.After)
|
||||
}
|
||||
if pagination.Before != nil {
|
||||
urlValues.Add("before", *pagination.Before)
|
||||
}
|
||||
|
||||
encodedValues := ""
|
||||
if len(urlValues) > 0 {
|
||||
encodedValues = "?" + urlValues.Encode()
|
||||
}
|
||||
|
||||
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/steps%s", threadID, runID, encodedValues)
|
||||
req, err := c.newRequest(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
87
vendor/github.com/rugatling/go-openai/speech.go
generated
vendored
Normal file
87
vendor/github.com/rugatling/go-openai/speech.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SpeechModel string
|
||||
|
||||
const (
|
||||
TTSModel1 SpeechModel = "tts-1"
|
||||
TTSModel1HD SpeechModel = "tts-1-hd"
|
||||
TTSModelCanary SpeechModel = "canary-tts"
|
||||
)
|
||||
|
||||
type SpeechVoice string
|
||||
|
||||
const (
|
||||
VoiceAlloy SpeechVoice = "alloy"
|
||||
VoiceEcho SpeechVoice = "echo"
|
||||
VoiceFable SpeechVoice = "fable"
|
||||
VoiceOnyx SpeechVoice = "onyx"
|
||||
VoiceNova SpeechVoice = "nova"
|
||||
VoiceShimmer SpeechVoice = "shimmer"
|
||||
)
|
||||
|
||||
type SpeechResponseFormat string
|
||||
|
||||
const (
|
||||
SpeechResponseFormatMp3 SpeechResponseFormat = "mp3"
|
||||
SpeechResponseFormatOpus SpeechResponseFormat = "opus"
|
||||
SpeechResponseFormatAac SpeechResponseFormat = "aac"
|
||||
SpeechResponseFormatFlac SpeechResponseFormat = "flac"
|
||||
SpeechResponseFormatWav SpeechResponseFormat = "wav"
|
||||
SpeechResponseFormatPcm SpeechResponseFormat = "pcm"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidSpeechModel = errors.New("invalid speech model")
|
||||
ErrInvalidVoice = errors.New("invalid voice")
|
||||
)
|
||||
|
||||
type CreateSpeechRequest struct {
|
||||
Model SpeechModel `json:"model"`
|
||||
Input string `json:"input"`
|
||||
Voice SpeechVoice `json:"voice"`
|
||||
ResponseFormat SpeechResponseFormat `json:"response_format,omitempty"` // Optional, default to mp3
|
||||
Speed float64 `json:"speed,omitempty"` // Optional, default to 1.0
|
||||
}
|
||||
|
||||
func contains[T comparable](s []T, e T) bool {
|
||||
for _, v := range s {
|
||||
if v == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isValidSpeechModel(model SpeechModel) bool {
|
||||
return contains([]SpeechModel{TTSModel1, TTSModel1HD, TTSModelCanary}, model)
|
||||
}
|
||||
|
||||
func isValidVoice(voice SpeechVoice) bool {
|
||||
return contains([]SpeechVoice{VoiceAlloy, VoiceEcho, VoiceFable, VoiceOnyx, VoiceNova, VoiceShimmer}, voice)
|
||||
}
|
||||
|
||||
func (c *Client) CreateSpeech(ctx context.Context, request CreateSpeechRequest) (response RawResponse, err error) {
|
||||
if !isValidSpeechModel(request.Model) {
|
||||
err = ErrInvalidSpeechModel
|
||||
return
|
||||
}
|
||||
if !isValidVoice(request.Voice) {
|
||||
err = ErrInvalidVoice
|
||||
return
|
||||
}
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/audio/speech", string(request.Model)),
|
||||
withBody(request),
|
||||
withContentType("application/json"),
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return c.sendRequestRaw(req)
|
||||
}
|
||||
49
vendor/github.com/rugatling/go-openai/stream.go
generated
vendored
Normal file
49
vendor/github.com/rugatling/go-openai/stream.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTooManyEmptyStreamMessages = errors.New("stream has sent too many empty messages")
|
||||
)
|
||||
|
||||
type CompletionStream struct {
|
||||
*streamReader[CompletionResponse]
|
||||
}
|
||||
|
||||
// CreateCompletionStream — API call to create a completion w/ streaming
|
||||
// support. It sets whether to stream back partial progress. If set, tokens will be
|
||||
// sent as data-only server-sent events as they become available, with the
|
||||
// stream terminated by a data: [DONE] message.
|
||||
func (c *Client) CreateCompletionStream(
|
||||
ctx context.Context,
|
||||
request CompletionRequest,
|
||||
) (stream *CompletionStream, err error) {
|
||||
urlSuffix := "/completions"
|
||||
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||
err = ErrCompletionUnsupportedModel
|
||||
return
|
||||
}
|
||||
|
||||
if !checkPromptType(request.Prompt) {
|
||||
err = ErrCompletionRequestPromptTypeNotSupported
|
||||
return
|
||||
}
|
||||
|
||||
request.Stream = true
|
||||
req, err := c.newRequest(ctx, "POST", c.fullURL(urlSuffix, request.Model), withBody(request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := sendRequestStream[CompletionResponse](c, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
stream = &CompletionStream{
|
||||
streamReader: resp,
|
||||
}
|
||||
return
|
||||
}
|
||||
113
vendor/github.com/rugatling/go-openai/stream_reader.go
generated
vendored
Normal file
113
vendor/github.com/rugatling/go-openai/stream_reader.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
utils "github.com/rugatling/go-openai/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
headerData = []byte("data: ")
|
||||
errorPrefix = []byte(`data: {"error":`)
|
||||
)
|
||||
|
||||
type streamable interface {
|
||||
ChatCompletionStreamResponse | CompletionResponse
|
||||
}
|
||||
|
||||
type streamReader[T streamable] struct {
|
||||
emptyMessagesLimit uint
|
||||
isFinished bool
|
||||
|
||||
reader *bufio.Reader
|
||||
response *http.Response
|
||||
errAccumulator utils.ErrorAccumulator
|
||||
unmarshaler utils.Unmarshaler
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
func (stream *streamReader[T]) Recv() (response T, err error) {
|
||||
if stream.isFinished {
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
response, err = stream.processLines()
|
||||
return
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func (stream *streamReader[T]) processLines() (T, error) {
|
||||
var (
|
||||
emptyMessagesCount uint
|
||||
hasErrorPrefix bool
|
||||
)
|
||||
|
||||
for {
|
||||
rawLine, readErr := stream.reader.ReadBytes('\n')
|
||||
if readErr != nil || hasErrorPrefix {
|
||||
respErr := stream.unmarshalError()
|
||||
if respErr != nil {
|
||||
return *new(T), fmt.Errorf("error, %w", respErr.Error)
|
||||
}
|
||||
return *new(T), readErr
|
||||
}
|
||||
|
||||
noSpaceLine := bytes.TrimSpace(rawLine)
|
||||
if bytes.HasPrefix(noSpaceLine, errorPrefix) {
|
||||
hasErrorPrefix = true
|
||||
}
|
||||
if !bytes.HasPrefix(noSpaceLine, headerData) || hasErrorPrefix {
|
||||
if hasErrorPrefix {
|
||||
noSpaceLine = bytes.TrimPrefix(noSpaceLine, headerData)
|
||||
}
|
||||
writeErr := stream.errAccumulator.Write(noSpaceLine)
|
||||
if writeErr != nil {
|
||||
return *new(T), writeErr
|
||||
}
|
||||
emptyMessagesCount++
|
||||
if emptyMessagesCount > stream.emptyMessagesLimit {
|
||||
return *new(T), ErrTooManyEmptyStreamMessages
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
noPrefixLine := bytes.TrimPrefix(noSpaceLine, headerData)
|
||||
if string(noPrefixLine) == "[DONE]" {
|
||||
stream.isFinished = true
|
||||
return *new(T), io.EOF
|
||||
}
|
||||
|
||||
var response T
|
||||
unmarshalErr := stream.unmarshaler.Unmarshal(noPrefixLine, &response)
|
||||
if unmarshalErr != nil {
|
||||
return *new(T), unmarshalErr
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (stream *streamReader[T]) unmarshalError() (errResp *ErrorResponse) {
|
||||
errBytes := stream.errAccumulator.Bytes()
|
||||
if len(errBytes) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
err := stream.unmarshaler.Unmarshal(errBytes, &errResp)
|
||||
if err != nil {
|
||||
errResp = nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (stream *streamReader[T]) Close() error {
|
||||
return stream.response.Body.Close()
|
||||
}
|
||||
107
vendor/github.com/rugatling/go-openai/thread.go
generated
vendored
Normal file
107
vendor/github.com/rugatling/go-openai/thread.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
threadsSuffix = "/threads"
|
||||
)
|
||||
|
||||
type Thread struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
type ThreadRequest struct {
|
||||
Messages []ThreadMessage `json:"messages,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ModifyThreadRequest struct {
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
}
|
||||
|
||||
type ThreadMessageRole string
|
||||
|
||||
const (
|
||||
ThreadMessageRoleUser ThreadMessageRole = "user"
|
||||
)
|
||||
|
||||
type ThreadMessage struct {
|
||||
Role ThreadMessageRole `json:"role"`
|
||||
Content string `json:"content"`
|
||||
FileIDs []string `json:"file_ids,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ThreadDeleteResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Deleted bool `json:"deleted"`
|
||||
|
||||
httpHeader
|
||||
}
|
||||
|
||||
// CreateThread creates a new thread.
|
||||
func (c *Client) CreateThread(ctx context.Context, request ThreadRequest) (response Thread, err error) {
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(threadsSuffix), withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// RetrieveThread retrieves a thread.
|
||||
func (c *Client) RetrieveThread(ctx context.Context, threadID string) (response Thread, err error) {
|
||||
urlSuffix := threadsSuffix + "/" + threadID
|
||||
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// ModifyThread modifies a thread.
|
||||
func (c *Client) ModifyThread(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
request ModifyThreadRequest,
|
||||
) (response Thread, err error) {
|
||||
urlSuffix := threadsSuffix + "/" + threadID
|
||||
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteThread deletes a thread.
|
||||
func (c *Client) DeleteThread(
|
||||
ctx context.Context,
|
||||
threadID string,
|
||||
) (response ThreadDeleteResponse, err error) {
|
||||
urlSuffix := threadsSuffix + "/" + threadID
|
||||
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.sendRequest(req, &response)
|
||||
return
|
||||
}
|
||||
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -316,6 +316,10 @@ github.com/rs/xid
|
||||
github.com/rs/zerolog
|
||||
github.com/rs/zerolog/internal/cbor
|
||||
github.com/rs/zerolog/internal/json
|
||||
# github.com/rugatling/go-openai v0.0.0-20240602200622-19edf07d0a97
|
||||
## explicit; go 1.18
|
||||
github.com/rugatling/go-openai
|
||||
github.com/rugatling/go-openai/internal
|
||||
# github.com/sashabaranov/go-openai v1.24.1
|
||||
## explicit; go 1.18
|
||||
github.com/sashabaranov/go-openai
|
||||
|
||||
Reference in New Issue
Block a user