Merge commit '2369025842b828ac38f4427fd1ebab8d03b1fe7f'

This commit is contained in:
Laisky.Cai
2024-04-20 01:07:29 +00:00
139 changed files with 2642 additions and 2625 deletions

View File

@@ -1,76 +1,84 @@
package tencent
// import (
// "github.com/Laisky/errors/v2"
// "fmt"
// "github.com/gin-gonic/gin"
// "github.com/songquanpeng/one-api/relay/channel"
// "github.com/songquanpeng/one-api/relay/channel/openai"
// "github.com/songquanpeng/one-api/relay/model"
// "github.com/songquanpeng/one-api/relay/util"
// "io"
// "net/http"
// "strings"
// )
import (
"errors"
"fmt"
"io"
"net/http"
"strings"
// // https://cloud.tencent.com/document/api/1729/101837
"github.com/Laisky/one-api/relay/adaptor"
"github.com/Laisky/one-api/relay/adaptor/openai"
"github.com/Laisky/one-api/relay/meta"
"github.com/Laisky/one-api/relay/model"
"github.com/gin-gonic/gin"
)
// type Adaptor struct {
// Sign string
// }
// https://cloud.tencent.com/document/api/1729/101837
// func (a *Adaptor) Init(meta *util.RelayMeta) {
type Adaptor struct {
Sign string
}
// }
func (a *Adaptor) Init(meta *meta.Meta) {
// func (a *Adaptor) GetRequestURL(meta *util.RelayMeta) (string, error) {
// return fmt.Sprintf("%s/hyllm/v1/chat/completions", meta.BaseURL), nil
// }
}
// func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *util.RelayMeta) error {
// channel.SetupCommonRequestHeader(c, req, meta)
// req.Header.Set("Authorization", a.Sign)
// req.Header.Set("X-TC-Action", meta.ActualModelName)
// return nil
// }
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
return fmt.Sprintf("%s/hyllm/v1/chat/completions", meta.BaseURL), nil
}
// func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
// if request == nil {
// return nil, errors.New("request is nil")
// }
// apiKey := c.Request.Header.Get("Authorization")
// apiKey = strings.TrimPrefix(apiKey, "Bearer ")
// appId, secretId, secretKey, err := ParseConfig(apiKey)
// if err != nil {
// return nil, err
// }
// tencentRequest := ConvertRequest(*request)
// tencentRequest.AppId = appId
// tencentRequest.SecretId = secretId
// // we have to calculate the sign here
// a.Sign = GetSign(*tencentRequest, secretKey)
// return tencentRequest, nil
// }
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
adaptor.SetupCommonRequestHeader(c, req, meta)
req.Header.Set("Authorization", a.Sign)
req.Header.Set("X-TC-Action", meta.ActualModelName)
return nil
}
// func (a *Adaptor) DoRequest(c *gin.Context, meta *util.RelayMeta, requestBody io.Reader) (*http.Response, error) {
// return channel.DoRequestHelper(a, c, meta, requestBody)
// }
func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
if request == nil {
return nil, errors.New("request is nil")
}
apiKey := c.Request.Header.Get("Authorization")
apiKey = strings.TrimPrefix(apiKey, "Bearer ")
appId, secretId, secretKey, err := ParseConfig(apiKey)
if err != nil {
return nil, err
}
tencentRequest := ConvertRequest(*request)
tencentRequest.AppId = appId
tencentRequest.SecretId = secretId
// we have to calculate the sign here
a.Sign = GetSign(*tencentRequest, secretKey)
return tencentRequest, nil
}
// func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *util.RelayMeta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
// if meta.IsStream {
// var responseText string
// err, responseText = StreamHandler(c, resp)
// usage = openai.ResponseText2Usage(responseText, meta.ActualModelName, meta.PromptTokens)
// } else {
// err, usage = Handler(c, resp)
// }
// return
// }
func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
if request == nil {
return nil, errors.New("request is nil")
}
return request, nil
}
// func (a *Adaptor) GetModelList() []string {
// return ModelList
// }
func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Reader) (*http.Response, error) {
return adaptor.DoRequestHelper(a, c, meta, requestBody)
}
// func (a *Adaptor) GetChannelName() string {
// return "tencent"
// }
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
if meta.IsStream {
var responseText string
err, responseText = StreamHandler(c, resp)
usage = openai.ResponseText2Usage(responseText, meta.ActualModelName, meta.PromptTokens)
} else {
err, usage = Handler(c, resp)
}
return
}
func (a *Adaptor) GetModelList() []string {
return ModelList
}
func (a *Adaptor) GetChannelName() string {
return "tencent"
}

View File

@@ -1,238 +1,231 @@
package tencent
// import (
// "bufio"
// "crypto/hmac"
// "crypto/sha1"
// "encoding/base64"
// "encoding/json"
// "github.com/Laisky/errors/v2"
// "fmt"
// "github.com/gin-gonic/gin"
// "github.com/songquanpeng/one-api/common"
// "github.com/songquanpeng/one-api/common/helper"
// "github.com/songquanpeng/one-api/common/logger"
// "github.com/songquanpeng/one-api/relay/channel/openai"
// "github.com/songquanpeng/one-api/relay/constant"
// "github.com/songquanpeng/one-api/relay/model"
// "io"
// "net/http"
// "sort"
// "strconv"
// "strings"
// )
import (
"bufio"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"sort"
"strconv"
"strings"
// // https://cloud.tencent.com/document/product/1729/97732
"github.com/Laisky/one-api/common"
"github.com/Laisky/one-api/common/conv"
"github.com/Laisky/one-api/common/helper"
"github.com/Laisky/one-api/common/logger"
"github.com/Laisky/one-api/common/random"
"github.com/Laisky/one-api/relay/adaptor/openai"
"github.com/Laisky/one-api/relay/constant"
"github.com/Laisky/one-api/relay/model"
"github.com/gin-gonic/gin"
)
// func ConvertRequest(request model.GeneralOpenAIRequest) *ChatRequest {
// messages := make([]Message, 0, len(request.Messages))
// for i := 0; i < len(request.Messages); i++ {
// message := request.Messages[i]
// if message.Role == "system" {
// messages = append(messages, Message{
// Role: "user",
// Content: message.StringContent(),
// })
// messages = append(messages, Message{
// Role: "assistant",
// Content: "Okay",
// })
// continue
// }
// messages = append(messages, Message{
// Content: message.StringContent(),
// Role: message.Role,
// })
// }
// stream := 0
// if request.Stream {
// stream = 1
// }
// return &ChatRequest{
// Timestamp: helper.GetTimestamp(),
// Expired: helper.GetTimestamp() + 24*60*60,
// QueryID: helper.GetUUID(),
// Temperature: request.Temperature,
// TopP: request.TopP,
// Stream: stream,
// Messages: messages,
// }
// }
// https://cloud.tencent.com/document/product/1729/97732
// func responseTencent2OpenAI(response *ChatResponse) *openai.TextResponse {
// fullTextResponse := openai.TextResponse{
// Object: "chat.completion",
// Created: helper.GetTimestamp(),
// Usage: response.Usage,
// }
// if len(response.Choices) > 0 {
// choice := openai.TextResponseChoice{
// Index: 0,
// Message: model.Message{
// Role: "assistant",
// Content: response.Choices[0].Messages.Content,
// },
// FinishReason: response.Choices[0].FinishReason,
// }
// fullTextResponse.Choices = append(fullTextResponse.Choices, choice)
// }
// return &fullTextResponse
// }
func ConvertRequest(request model.GeneralOpenAIRequest) *ChatRequest {
messages := make([]Message, 0, len(request.Messages))
for i := 0; i < len(request.Messages); i++ {
message := request.Messages[i]
messages = append(messages, Message{
Content: message.StringContent(),
Role: message.Role,
})
}
stream := 0
if request.Stream {
stream = 1
}
return &ChatRequest{
Timestamp: helper.GetTimestamp(),
Expired: helper.GetTimestamp() + 24*60*60,
QueryID: random.GetUUID(),
Temperature: request.Temperature,
TopP: request.TopP,
Stream: stream,
Messages: messages,
}
}
// func streamResponseTencent2OpenAI(TencentResponse *ChatResponse) *openai.ChatCompletionsStreamResponse {
// response := openai.ChatCompletionsStreamResponse{
// Object: "chat.completion.chunk",
// Created: helper.GetTimestamp(),
// Model: "tencent-hunyuan",
// }
// if len(TencentResponse.Choices) > 0 {
// var choice openai.ChatCompletionsStreamResponseChoice
// choice.Delta.Content = TencentResponse.Choices[0].Delta.Content
// if TencentResponse.Choices[0].FinishReason == "stop" {
// choice.FinishReason = &constant.StopFinishReason
// }
// response.Choices = append(response.Choices, choice)
// }
// return &response
// }
func responseTencent2OpenAI(response *ChatResponse) *openai.TextResponse {
fullTextResponse := openai.TextResponse{
Object: "chat.completion",
Created: helper.GetTimestamp(),
Usage: response.Usage,
}
if len(response.Choices) > 0 {
choice := openai.TextResponseChoice{
Index: 0,
Message: model.Message{
Role: "assistant",
Content: response.Choices[0].Messages.Content,
},
FinishReason: response.Choices[0].FinishReason,
}
fullTextResponse.Choices = append(fullTextResponse.Choices, choice)
}
return &fullTextResponse
}
// func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, string) {
// var responseText string
// scanner := bufio.NewScanner(resp.Body)
// scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
// if atEOF && len(data) == 0 {
// return 0, nil, nil
// }
// if i := strings.Index(string(data), "\n"); i >= 0 {
// return i + 1, data[0:i], nil
// }
// if atEOF {
// return len(data), data, nil
// }
// return 0, nil, nil
// })
// dataChan := make(chan string)
// stopChan := make(chan bool)
// go func() {
// for scanner.Scan() {
// data := scanner.Text()
// if len(data) < 5 { // ignore blank line or wrong format
// continue
// }
// if data[:5] != "data:" {
// continue
// }
// data = data[5:]
// dataChan <- data
// }
// stopChan <- true
// }()
// common.SetEventStreamHeaders(c)
// c.Stream(func(w io.Writer) bool {
// select {
// case data := <-dataChan:
// var TencentResponse ChatResponse
// err := json.Unmarshal([]byte(data), &TencentResponse)
// if err != nil {
// logger.SysError("error unmarshalling stream response: " + err.Error())
// return true
// }
// response := streamResponseTencent2OpenAI(&TencentResponse)
// if len(response.Choices) != 0 {
// responseText += response.Choices[0].Delta.Content
// }
// jsonResponse, err := json.Marshal(response)
// if err != nil {
// logger.SysError("error marshalling stream response: " + err.Error())
// return true
// }
// c.Render(-1, common.CustomEvent{Data: "data: " + string(jsonResponse)})
// return true
// case <-stopChan:
// c.Render(-1, common.CustomEvent{Data: "data: [DONE]"})
// return false
// }
// })
// err := resp.Body.Close()
// if err != nil {
// return openai.ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), ""
// }
// return nil, responseText
// }
func streamResponseTencent2OpenAI(TencentResponse *ChatResponse) *openai.ChatCompletionsStreamResponse {
response := openai.ChatCompletionsStreamResponse{
Id: fmt.Sprintf("chatcmpl-%s", random.GetUUID()),
Object: "chat.completion.chunk",
Created: helper.GetTimestamp(),
Model: "tencent-hunyuan",
}
if len(TencentResponse.Choices) > 0 {
var choice openai.ChatCompletionsStreamResponseChoice
choice.Delta.Content = TencentResponse.Choices[0].Delta.Content
if TencentResponse.Choices[0].FinishReason == "stop" {
choice.FinishReason = &constant.StopFinishReason
}
response.Choices = append(response.Choices, choice)
}
return &response
}
// func Handler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, *model.Usage) {
// var TencentResponse ChatResponse
// responseBody, err := io.ReadAll(resp.Body)
// if err != nil {
// return openai.ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
// }
// err = resp.Body.Close()
// if err != nil {
// return openai.ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
// }
// err = json.Unmarshal(responseBody, &TencentResponse)
// if err != nil {
// return openai.ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
// }
// if TencentResponse.Error.Code != 0 {
// return &model.ErrorWithStatusCode{
// Error: model.Error{
// Message: TencentResponse.Error.Message,
// Code: TencentResponse.Error.Code,
// },
// StatusCode: resp.StatusCode,
// }, nil
// }
// fullTextResponse := responseTencent2OpenAI(&TencentResponse)
// fullTextResponse.Model = "hunyuan"
// jsonResponse, err := json.Marshal(fullTextResponse)
// if err != nil {
// return openai.ErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
// }
// c.Writer.Header().Set("Content-Type", "application/json")
// c.Writer.WriteHeader(resp.StatusCode)
// _, err = c.Writer.Write(jsonResponse)
// if err != nil {
// return openai.ErrorWrapper(err, "write_response_body_failed", http.StatusInternalServerError), nil
// }
// return nil, &fullTextResponse.Usage
// }
func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, string) {
var responseText string
scanner := bufio.NewScanner(resp.Body)
scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := strings.Index(string(data), "\n"); i >= 0 {
return i + 1, data[0:i], nil
}
if atEOF {
return len(data), data, nil
}
return 0, nil, nil
})
dataChan := make(chan string)
stopChan := make(chan bool)
go func() {
for scanner.Scan() {
data := scanner.Text()
if len(data) < 5 { // ignore blank line or wrong format
continue
}
if data[:5] != "data:" {
continue
}
data = data[5:]
dataChan <- data
}
stopChan <- true
}()
common.SetEventStreamHeaders(c)
c.Stream(func(w io.Writer) bool {
select {
case data := <-dataChan:
var TencentResponse ChatResponse
err := json.Unmarshal([]byte(data), &TencentResponse)
if err != nil {
logger.SysError("error unmarshalling stream response: " + err.Error())
return true
}
response := streamResponseTencent2OpenAI(&TencentResponse)
if len(response.Choices) != 0 {
responseText += conv.AsString(response.Choices[0].Delta.Content)
}
jsonResponse, err := json.Marshal(response)
if err != nil {
logger.SysError("error marshalling stream response: " + err.Error())
return true
}
c.Render(-1, common.CustomEvent{Data: "data: " + string(jsonResponse)})
return true
case <-stopChan:
c.Render(-1, common.CustomEvent{Data: "data: [DONE]"})
return false
}
})
err := resp.Body.Close()
if err != nil {
return openai.ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), ""
}
return nil, responseText
}
// func ParseConfig(config string) (appId int64, secretId string, secretKey string, err error) {
// parts := strings.Split(config, "|")
// if len(parts) != 3 {
// err = errors.New("invalid tencent config")
// return
// }
// appId, err = strconv.ParseInt(parts[0], 10, 64)
// secretId = parts[1]
// secretKey = parts[2]
// return
// }
func Handler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, *model.Usage) {
var TencentResponse ChatResponse
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return openai.ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
}
err = resp.Body.Close()
if err != nil {
return openai.ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
}
err = json.Unmarshal(responseBody, &TencentResponse)
if err != nil {
return openai.ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
}
if TencentResponse.Error.Code != 0 {
return &model.ErrorWithStatusCode{
Error: model.Error{
Message: TencentResponse.Error.Message,
Code: TencentResponse.Error.Code,
},
StatusCode: resp.StatusCode,
}, nil
}
fullTextResponse := responseTencent2OpenAI(&TencentResponse)
fullTextResponse.Model = "hunyuan"
jsonResponse, err := json.Marshal(fullTextResponse)
if err != nil {
return openai.ErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
}
c.Writer.Header().Set("Content-Type", "application/json")
c.Writer.WriteHeader(resp.StatusCode)
_, err = c.Writer.Write(jsonResponse)
if err != nil {
return openai.ErrorWrapper(err, "write_response_body_failed", http.StatusInternalServerError), nil
}
return nil, &fullTextResponse.Usage
}
// func GetSign(req ChatRequest, secretKey string) string {
// params := make([]string, 0)
// params = append(params, "app_id="+strconv.FormatInt(req.AppId, 10))
// params = append(params, "secret_id="+req.SecretId)
// params = append(params, "timestamp="+strconv.FormatInt(req.Timestamp, 10))
// params = append(params, "query_id="+req.QueryID)
// params = append(params, "temperature="+strconv.FormatFloat(req.Temperature, 'f', -1, 64))
// params = append(params, "top_p="+strconv.FormatFloat(req.TopP, 'f', -1, 64))
// params = append(params, "stream="+strconv.Itoa(req.Stream))
// params = append(params, "expired="+strconv.FormatInt(req.Expired, 10))
func ParseConfig(config string) (appId int64, secretId string, secretKey string, err error) {
parts := strings.Split(config, "|")
if len(parts) != 3 {
err = errors.New("invalid tencent config")
return
}
appId, err = strconv.ParseInt(parts[0], 10, 64)
secretId = parts[1]
secretKey = parts[2]
return
}
// var messageStr string
// for _, msg := range req.Messages {
// messageStr += fmt.Sprintf(`{"role":"%s","content":"%s"},`, msg.Role, msg.Content)
// }
// messageStr = strings.TrimSuffix(messageStr, ",")
// params = append(params, "messages=["+messageStr+"]")
func GetSign(req ChatRequest, secretKey string) string {
params := make([]string, 0)
params = append(params, "app_id="+strconv.FormatInt(req.AppId, 10))
params = append(params, "secret_id="+req.SecretId)
params = append(params, "timestamp="+strconv.FormatInt(req.Timestamp, 10))
params = append(params, "query_id="+req.QueryID)
params = append(params, "temperature="+strconv.FormatFloat(req.Temperature, 'f', -1, 64))
params = append(params, "top_p="+strconv.FormatFloat(req.TopP, 'f', -1, 64))
params = append(params, "stream="+strconv.Itoa(req.Stream))
params = append(params, "expired="+strconv.FormatInt(req.Expired, 10))
// sort.Strings(params)
// url := "hunyuan.cloud.tencent.com/hyllm/v1/chat/completions?" + strings.Join(params, "&")
// mac := hmac.New(sha1.New, []byte(secretKey))
// signURL := url
// mac.Write([]byte(signURL))
// sign := mac.Sum([]byte(nil))
// return base64.StdEncoding.EncodeToString(sign)
// }
var messageStr string
for _, msg := range req.Messages {
messageStr += fmt.Sprintf(`{"role":"%s","content":"%s"},`, msg.Role, msg.Content)
}
messageStr = strings.TrimSuffix(messageStr, ",")
params = append(params, "messages=["+messageStr+"]")
sort.Strings(params)
url := "hunyuan.cloud.tencent.com/hyllm/v1/chat/completions?" + strings.Join(params, "&")
mac := hmac.New(sha1.New, []byte(secretKey))
signURL := url
mac.Write([]byte(signURL))
sign := mac.Sum([]byte(nil))
return base64.StdEncoding.EncodeToString(sign)
}

View File

@@ -1,63 +1,63 @@
package tencent
// import (
// "github.com/songquanpeng/one-api/relay/model"
// )
import (
"github.com/Laisky/one-api/relay/model"
)
// type Message struct {
// Role string `json:"role"`
// Content string `json:"content"`
// }
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
// type ChatRequest struct {
// AppId int64 `json:"app_id"` // 腾讯云账号的 APPID
// SecretId string `json:"secret_id"` // 官网 SecretId
// // Timestamp当前 UNIX 时间戳,单位为秒,可记录发起 API 请求的时间。
// // 例如1529223702如果与当前时间相差过大会引起签名过期错误
// Timestamp int64 `json:"timestamp"`
// // Expired 签名的有效期,是一个符合 UNIX Epoch 时间戳规范的数值,
// // 单位为秒Expired 必须大于 Timestamp 且 Expired-Timestamp 小于90天
// Expired int64 `json:"expired"`
// QueryID string `json:"query_id"` //请求 Id用于问题排查
// // Temperature 较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定
// // 默认 1.0,取值区间为[0.0,2.0],非必要不建议使用,不合理的取值会影响效果
// // 建议该参数和 top_p 只设置1个不要同时更改 top_p
// Temperature float64 `json:"temperature"`
// // TopP 影响输出文本的多样性,取值越大,生成文本的多样性越强
// // 默认1.0,取值区间为[0.0, 1.0],非必要不建议使用, 不合理的取值会影响效果
// // 建议该参数和 temperature 只设置1个不要同时更改
// TopP float64 `json:"top_p"`
// // Stream 0同步1流式 默认协议SSE)
// // 同步请求超时60s如果内容较长建议使用流式
// Stream int `json:"stream"`
// // Messages 会话内容, 长度最多为40, 按对话时间从旧到新在数组中排列
// // 输入 content 总数最大支持 3000 token。
// Messages []Message `json:"messages"`
// }
type ChatRequest struct {
AppId int64 `json:"app_id"` // 腾讯云账号的 APPID
SecretId string `json:"secret_id"` // 官网 SecretId
// Timestamp当前 UNIX 时间戳,单位为秒,可记录发起 API 请求的时间。
// 例如1529223702如果与当前时间相差过大会引起签名过期错误
Timestamp int64 `json:"timestamp"`
// Expired 签名的有效期,是一个符合 UNIX Epoch 时间戳规范的数值,
// 单位为秒Expired 必须大于 Timestamp 且 Expired-Timestamp 小于90天
Expired int64 `json:"expired"`
QueryID string `json:"query_id"` //请求 Id用于问题排查
// Temperature 较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定
// 默认 1.0,取值区间为[0.0,2.0],非必要不建议使用,不合理的取值会影响效果
// 建议该参数和 top_p 只设置1个不要同时更改 top_p
Temperature float64 `json:"temperature"`
// TopP 影响输出文本的多样性,取值越大,生成文本的多样性越强
// 默认1.0,取值区间为[0.0, 1.0],非必要不建议使用, 不合理的取值会影响效果
// 建议该参数和 temperature 只设置1个不要同时更改
TopP float64 `json:"top_p"`
// Stream 0同步1流式 默认协议SSE)
// 同步请求超时60s如果内容较长建议使用流式
Stream int `json:"stream"`
// Messages 会话内容, 长度最多为40, 按对话时间从旧到新在数组中排列
// 输入 content 总数最大支持 3000 token。
Messages []Message `json:"messages"`
}
// type Error struct {
// Code int `json:"code"`
// Message string `json:"message"`
// }
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
}
// type Usage struct {
// InputTokens int `json:"input_tokens"`
// OutputTokens int `json:"output_tokens"`
// TotalTokens int `json:"total_tokens"`
// }
type Usage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
TotalTokens int `json:"total_tokens"`
}
// type ResponseChoices struct {
// FinishReason string `json:"finish_reason,omitempty"` // 流式结束标志位,为 stop 则表示尾包
// Messages Message `json:"messages,omitempty"` // 内容,同步模式返回内容,流模式为 null 输出 content 内容总数最多支持 1024token。
// Delta Message `json:"delta,omitempty"` // 内容,流模式返回内容,同步模式为 null 输出 content 内容总数最多支持 1024token。
// }
type ResponseChoices struct {
FinishReason string `json:"finish_reason,omitempty"` // 流式结束标志位,为 stop 则表示尾包
Messages Message `json:"messages,omitempty"` // 内容,同步模式返回内容,流模式为 null 输出 content 内容总数最多支持 1024token。
Delta Message `json:"delta,omitempty"` // 内容,流模式返回内容,同步模式为 null 输出 content 内容总数最多支持 1024token。
}
// type ChatResponse struct {
// Choices []ResponseChoices `json:"choices,omitempty"` // 结果
// Created string `json:"created,omitempty"` // unix 时间戳的字符串
// Id string `json:"id,omitempty"` // 会话 id
// Usage model.Usage `json:"usage,omitempty"` // token 数量
// Error Error `json:"error,omitempty"` // 错误信息 注意:此字段可能返回 null表示取不到有效值
// Note string `json:"note,omitempty"` // 注释
// ReqID string `json:"req_id,omitempty"` // 唯一请求 Id每次请求都会返回。用于反馈接口入参
// }
type ChatResponse struct {
Choices []ResponseChoices `json:"choices,omitempty"` // 结果
Created string `json:"created,omitempty"` // unix 时间戳的字符串
Id string `json:"id,omitempty"` // 会话 id
Usage model.Usage `json:"usage,omitempty"` // token 数量
Error Error `json:"error,omitempty"` // 错误信息 注意:此字段可能返回 null表示取不到有效值
Note string `json:"note,omitempty"` // 注释
ReqID string `json:"req_id,omitempty"` // 唯一请求 Id每次请求都会返回。用于反馈接口入参
}