openai/chat.go

231 lines
6.4 KiB
Go
Raw Normal View History

2024-09-07 23:13:36 +08:00
package openai
import (
2024-10-25 16:04:36 +08:00
"apigo.cc/ai/llm/llm"
"bytes"
2024-09-07 23:13:36 +08:00
"context"
2024-10-25 16:04:36 +08:00
"encoding/binary"
"fmt"
2024-09-07 23:13:36 +08:00
"github.com/sashabaranov/go-openai"
"github.com/ssgo/log"
2024-10-25 16:04:36 +08:00
"github.com/ssgo/u"
2024-09-07 23:13:36 +08:00
"strings"
2024-10-25 16:04:36 +08:00
"time"
2024-09-07 23:13:36 +08:00
)
2024-10-25 16:04:36 +08:00
func (lm *LLM) FastAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4o_mini_2024_07_18,
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) LongAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4_32k_0613,
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) BatterAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4_turbo,
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) BestAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4o_2024_08_06,
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) MultiAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4o_mini_2024_07_18,
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) BestMultiAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4o_2024_08_06,
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) CodeInterpreterAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4o,
2024-10-25 16:04:36 +08:00
Tools: map[string]any{llm.ToolCodeInterpreter: nil},
2024-09-07 23:13:36 +08:00
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) WebSearchAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
return lm.Ask(messages, llm.ChatConfig{
2024-09-07 23:13:36 +08:00
Model: ModelGPT_4o_mini_2024_07_18,
2024-10-25 16:04:36 +08:00
Tools: map[string]any{llm.ToolWebSearch: nil},
2024-09-07 23:13:36 +08:00
}, callback)
}
2024-10-25 16:04:36 +08:00
func (lm *LLM) Ask(messages []llm.ChatMessage, config llm.ChatConfig, callback func(answer string)) (string, llm.Usage, error) {
openaiConf := openai.DefaultConfig(lm.config.ApiKey)
if lm.config.Endpoint != "" {
openaiConf.BaseURL = lm.config.Endpoint
2024-09-07 23:13:36 +08:00
}
2024-10-25 16:04:36 +08:00
config.SetDefault(&lm.config.ChatConfig)
2024-09-07 23:13:36 +08:00
agentMessages := make([]openai.ChatCompletionMessage, len(messages))
for i, msg := range messages {
var contents []openai.ChatMessagePart
if msg.Contents != nil {
contents = make([]openai.ChatMessagePart, len(msg.Contents))
for j, inPart := range msg.Contents {
part := openai.ChatMessagePart{}
part.Type = TypeMap[inPart.Type]
switch inPart.Type {
2024-10-25 16:04:36 +08:00
case llm.TypeText:
2024-09-07 23:13:36 +08:00
part.Text = inPart.Content
2024-10-25 16:04:36 +08:00
case llm.TypeImage:
2024-09-07 23:13:36 +08:00
part.ImageURL = &openai.ChatMessageImageURL{
URL: inPart.Content,
Detail: openai.ImageURLDetailAuto,
}
}
contents[j] = part
}
}
2024-10-25 16:04:36 +08:00
if len(contents) == 1 && contents[0].Type == llm.TypeText {
agentMessages[i] = openai.ChatCompletionMessage{
Role: RoleMap[msg.Role],
Content: contents[0].Text,
}
} else {
agentMessages[i] = openai.ChatCompletionMessage{
Role: RoleMap[msg.Role],
MultiContent: contents,
}
2024-09-07 23:13:36 +08:00
}
}
opt := openai.ChatCompletionRequest{
Model: config.GetModel(),
Messages: agentMessages,
MaxTokens: config.GetMaxTokens(),
Temperature: float32(config.GetTemperature()),
TopP: float32(config.GetTopP()),
StreamOptions: &openai.StreamOptions{
IncludeUsage: true,
},
}
for name := range config.GetTools() {
switch name {
2024-10-25 16:04:36 +08:00
case llm.ToolCodeInterpreter:
2024-09-07 23:13:36 +08:00
opt.Tools = append(opt.Tools, openai.Tool{Type: "code_interpreter"})
2024-10-25 16:04:36 +08:00
case llm.ToolWebSearch:
2024-09-07 23:13:36 +08:00
}
}
c := openai.NewClientWithConfig(openaiConf)
if callback != nil {
opt.Stream = true
r, err := c.CreateChatCompletionStream(context.Background(), opt)
if err == nil {
results := make([]string, 0)
2024-10-25 16:04:36 +08:00
usage := llm.Usage{}
2024-09-07 23:13:36 +08:00
for {
if r2, err := r.Recv(); err == nil {
if r2.Choices != nil {
for _, ch := range r2.Choices {
text := ch.Delta.Content
callback(text)
results = append(results, text)
}
}
if r2.Usage != nil {
usage.AskTokens += int64(r2.Usage.PromptTokens)
usage.AnswerTokens += int64(r2.Usage.CompletionTokens)
usage.TotalTokens += int64(r2.Usage.TotalTokens)
}
} else {
break
}
}
_ = r.Close()
return strings.Join(results, ""), usage, nil
} else {
log.DefaultLogger.Error(err.Error())
2024-10-25 16:04:36 +08:00
return "", llm.Usage{}, err
2024-09-07 23:13:36 +08:00
}
} else {
2024-10-25 16:04:36 +08:00
t1 := time.Now().UnixMilli()
if r, err := c.CreateChatCompletion(context.Background(), opt); err == nil {
t2 := time.Now().UnixMilli() - t1
2024-09-07 23:13:36 +08:00
results := make([]string, 0)
if r.Choices != nil {
for _, ch := range r.Choices {
results = append(results, ch.Message.Content)
}
}
2024-10-25 16:04:36 +08:00
return strings.Join(results, ""), llm.Usage{
2024-09-07 23:13:36 +08:00
AskTokens: int64(r.Usage.PromptTokens),
AnswerTokens: int64(r.Usage.CompletionTokens),
TotalTokens: int64(r.Usage.TotalTokens),
2024-10-25 16:04:36 +08:00
UsedTime: t2,
2024-09-07 23:13:36 +08:00
}, nil
} else {
//fmt.Println(u.BMagenta(err.Error()), u.BMagenta(u.JsonP(r)))
2024-10-25 16:04:36 +08:00
return "", llm.Usage{}, err
}
}
}
func (lm *LLM) FastEmbedding(text string) ([]byte, llm.Usage, error) {
return lm.Embedding(text, string(openai.AdaEmbeddingV2))
}
func (lm *LLM) BestEmbedding(text string) ([]byte, llm.Usage, error) {
return lm.Embedding(text, string(openai.LargeEmbedding3))
}
func (lm *LLM) Embedding(text, model string) ([]byte, llm.Usage, error) {
fmt.Println(111, model, text)
openaiConf := openai.DefaultConfig(lm.config.ApiKey)
if lm.config.Endpoint != "" {
openaiConf.BaseURL = lm.config.Endpoint
}
c := openai.NewClientWithConfig(openaiConf)
req := openai.EmbeddingRequest{
Input: text,
Model: openai.EmbeddingModel(model),
User: "",
EncodingFormat: "",
Dimensions: 0,
}
if lm.config.Debug {
fmt.Println(u.JsonP(req))
}
t1 := time.Now().UnixMilli()
if r, err := c.CreateEmbeddings(context.Background(), req); err == nil {
t2 := time.Now().UnixMilli() - t1
buf := new(bytes.Buffer)
if r.Data != nil {
for _, ch := range r.Data {
for _, v := range ch.Embedding {
_ = binary.Write(buf, binary.LittleEndian, v)
}
}
2024-09-07 23:13:36 +08:00
}
2024-10-25 16:04:36 +08:00
fmt.Println(len(buf.Bytes()))
return buf.Bytes(), llm.Usage{
AskTokens: int64(r.Usage.PromptTokens),
AnswerTokens: int64(r.Usage.CompletionTokens),
TotalTokens: int64(r.Usage.TotalTokens),
UsedTime: t2,
}, nil
} else {
fmt.Println(err.Error())
return nil, llm.Usage{}, err
2024-09-07 23:13:36 +08:00
}
}