coai/adapter/chatgpt/processor.go
2023-11-21 21:58:44 +08:00

148 lines
3.3 KiB
Go

package chatgpt
import (
"chat/globals"
"chat/utils"
"errors"
"fmt"
"strings"
)
func processFormat(data string) string {
rep := strings.NewReplacer(
"data: {",
"\"data\": {",
)
item := rep.Replace(data)
if !strings.HasPrefix(item, "{") {
item = "{" + item
}
if !strings.HasSuffix(item, "}}") {
item = item + "}"
}
return item
}
func formatMessages(props *ChatProps) []globals.Message {
if props.Model == globals.GPT4Vision {
base := props.Message[len(props.Message)-1].Content
urls := utils.ExtractUrls(base)
if len(urls) > 0 {
base = fmt.Sprintf("%s %s", strings.Join(urls, " "), base)
}
props.Message[len(props.Message)-1].Content = base
return props.Message
}
return props.Message
}
func processChatResponse(data string) *ChatStreamResponse {
if strings.HasPrefix(data, "{") {
var form *ChatStreamResponse
if form = utils.UnmarshalForm[ChatStreamResponse](data); form != nil {
return form
}
if form = utils.UnmarshalForm[ChatStreamResponse](data[:len(data)-1]); form != nil {
return form
}
}
return nil
}
func processCompletionResponse(data string) *CompletionResponse {
if strings.HasPrefix(data, "{") {
var form *CompletionResponse
if form = utils.UnmarshalForm[CompletionResponse](data); form != nil {
return form
}
if form = utils.UnmarshalForm[CompletionResponse](data[:len(data)-1]); form != nil {
return form
}
}
return nil
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
if strings.HasPrefix(data, "{") {
var form *ChatStreamErrorResponse
if form = utils.UnmarshalForm[ChatStreamErrorResponse](data); form != nil {
return form
}
if form = utils.UnmarshalForm[ChatStreamErrorResponse](data + "}"); form != nil {
return form
}
}
return nil
}
func isDone(data string) bool {
return utils.Contains[string](data, []string{
"{data: [DONE]}", "{data: [DONE]}}",
"{[DONE]}", "{data:}", "{data:}}",
})
}
func getChoices(form *ChatStreamResponse) string {
if len(form.Data.Choices) == 0 {
return ""
}
return form.Data.Choices[0].Delta.Content
}
func getCompletionChoices(form *CompletionResponse) string {
if len(form.Data.Choices) == 0 {
return ""
}
return form.Data.Choices[0].Text
}
func getToolCalls(form *ChatStreamResponse) *globals.ToolCalls {
if len(form.Data.Choices) == 0 {
return nil
}
return form.Data.Choices[0].Delta.ToolCalls
}
func (c *ChatInstance) ProcessLine(obj utils.Buffer, instruct bool, buf, data string) (string, error) {
item := processFormat(buf + data)
if isDone(item) {
return "", nil
}
if form := processChatResponse(item); form == nil {
if instruct {
// legacy support
if completion := processCompletionResponse(item); completion != nil {
return getCompletionChoices(completion), nil
}
}
// recursive call
if len(buf) > 0 {
return c.ProcessLine(obj, instruct, "", buf+item)
}
if err := processChatErrorResponse(item); err == nil || err.Data.Error.Message == "" {
globals.Warn(fmt.Sprintf("chatgpt error: cannot parse response: %s", item))
return data, errors.New("parser error: cannot parse response")
} else {
return "", fmt.Errorf("chatgpt error: %s (type: %s)", err.Data.Error.Message, err.Data.Error.Type)
}
} else {
obj.SetToolCalls(getToolCalls(form))
return getChoices(form), nil
}
}