2024-01-14 11:21:03 +00:00
|
|
|
package openai
|
2023-07-22 09:48:45 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2024-06-30 08:09:16 +00:00
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
|
2024-07-09 14:43:59 +00:00
|
|
|
"github.com/songquanpeng/one-api/common/render"
|
|
|
|
|
2023-07-22 09:48:45 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
2024-01-28 11:38:58 +00:00
|
|
|
"github.com/songquanpeng/one-api/common"
|
2024-03-30 02:43:26 +00:00
|
|
|
"github.com/songquanpeng/one-api/common/conv"
|
2024-01-28 11:38:58 +00:00
|
|
|
"github.com/songquanpeng/one-api/common/logger"
|
2024-02-17 16:15:31 +00:00
|
|
|
"github.com/songquanpeng/one-api/relay/model"
|
2024-04-05 16:44:33 +00:00
|
|
|
"github.com/songquanpeng/one-api/relay/relaymode"
|
2023-07-22 09:48:45 +00:00
|
|
|
)
|
|
|
|
|
2024-04-21 08:22:28 +00:00
|
|
|
const (
|
|
|
|
dataPrefix = "data: "
|
|
|
|
done = "[DONE]"
|
|
|
|
dataPrefixLength = len(dataPrefix)
|
|
|
|
)
|
|
|
|
|
2024-03-01 19:05:25 +00:00
|
|
|
func StreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*model.ErrorWithStatusCode, string, *model.Usage) {
|
2023-07-22 09:48:45 +00:00
|
|
|
responseText := ""
|
|
|
|
scanner := bufio.NewScanner(resp.Body)
|
2024-06-30 10:36:33 +00:00
|
|
|
scanner.Split(bufio.ScanLines)
|
|
|
|
var usage *model.Usage
|
|
|
|
|
|
|
|
common.SetEventStreamHeaders(c)
|
|
|
|
|
2024-07-09 14:43:59 +00:00
|
|
|
doneRendered := false
|
2024-06-30 10:36:33 +00:00
|
|
|
for scanner.Scan() {
|
|
|
|
data := scanner.Text()
|
|
|
|
if len(data) < dataPrefixLength { // ignore blank line or wrong format
|
|
|
|
continue
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
if data[:dataPrefixLength] != dataPrefix && data[:dataPrefixLength] != done {
|
|
|
|
continue
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
if strings.HasPrefix(data[dataPrefixLength:], done) {
|
|
|
|
render.StringData(c, data)
|
2024-07-09 14:43:59 +00:00
|
|
|
doneRendered = true
|
2024-06-30 10:36:33 +00:00
|
|
|
continue
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
switch relayMode {
|
|
|
|
case relaymode.ChatCompletions:
|
|
|
|
var streamResponse ChatCompletionsStreamResponse
|
|
|
|
err := json.Unmarshal([]byte(data[dataPrefixLength:]), &streamResponse)
|
|
|
|
if err != nil {
|
|
|
|
logger.SysError("error unmarshalling stream response: " + err.Error())
|
|
|
|
render.StringData(c, data) // if error happened, pass the data to client
|
|
|
|
continue // just ignore the error
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2024-09-06 07:11:23 +00:00
|
|
|
if len(streamResponse.Choices) == 0 && streamResponse.Usage == nil {
|
|
|
|
// but for empty choice and no usage, we should not pass it to client, this is for azure
|
2024-06-30 10:36:33 +00:00
|
|
|
continue // just ignore empty choice
|
2023-07-30 04:03:06 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
render.StringData(c, data)
|
|
|
|
for _, choice := range streamResponse.Choices {
|
|
|
|
responseText += conv.AsString(choice.Delta.Content)
|
2024-04-21 08:22:28 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
if streamResponse.Usage != nil {
|
|
|
|
usage = streamResponse.Usage
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
case relaymode.Completions:
|
|
|
|
render.StringData(c, data)
|
|
|
|
var streamResponse CompletionsStreamResponse
|
|
|
|
err := json.Unmarshal([]byte(data[dataPrefixLength:]), &streamResponse)
|
|
|
|
if err != nil {
|
|
|
|
logger.SysError("error unmarshalling stream response: " + err.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, choice := range streamResponse.Choices {
|
|
|
|
responseText += choice.Text
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
|
|
logger.SysError("error reading stream: " + err.Error())
|
|
|
|
}
|
|
|
|
|
2024-07-09 14:43:59 +00:00
|
|
|
if !doneRendered {
|
|
|
|
render.Done(c)
|
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
|
2023-07-22 09:48:45 +00:00
|
|
|
err := resp.Body.Close()
|
|
|
|
if err != nil {
|
2024-03-01 19:05:25 +00:00
|
|
|
return ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), "", nil
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2024-06-30 10:36:33 +00:00
|
|
|
|
2024-03-01 19:05:25 +00:00
|
|
|
return nil, responseText, usage
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
|
|
|
|
2024-02-17 16:15:31 +00:00
|
|
|
func Handler(c *gin.Context, resp *http.Response, promptTokens int, modelName string) (*model.ErrorWithStatusCode, *model.Usage) {
|
2024-01-14 11:21:03 +00:00
|
|
|
var textResponse SlimTextResponse
|
2023-11-24 12:42:29 +00:00
|
|
|
responseBody, err := io.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
2024-01-14 11:21:03 +00:00
|
|
|
return ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2023-11-24 12:42:29 +00:00
|
|
|
err = resp.Body.Close()
|
|
|
|
if err != nil {
|
2024-01-14 11:21:03 +00:00
|
|
|
return ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
2023-11-24 12:42:29 +00:00
|
|
|
}
|
|
|
|
err = json.Unmarshal(responseBody, &textResponse)
|
|
|
|
if err != nil {
|
2024-01-14 11:21:03 +00:00
|
|
|
return ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
|
2023-11-24 12:42:29 +00:00
|
|
|
}
|
|
|
|
if textResponse.Error.Type != "" {
|
2024-02-17 16:15:31 +00:00
|
|
|
return &model.ErrorWithStatusCode{
|
2024-01-14 11:21:03 +00:00
|
|
|
Error: textResponse.Error,
|
|
|
|
StatusCode: resp.StatusCode,
|
2023-11-24 12:42:29 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
// Reset response body
|
|
|
|
resp.Body = io.NopCloser(bytes.NewBuffer(responseBody))
|
|
|
|
|
2023-07-22 09:48:45 +00:00
|
|
|
// We shouldn't set the header before we parse the response body, because the parse part may fail.
|
|
|
|
// And then we will have to send an error response, but in this case, the header has already been set.
|
2024-01-14 11:21:03 +00:00
|
|
|
// So the HTTPClient will be confused by the response.
|
2023-07-22 09:48:45 +00:00
|
|
|
// For example, Postman will report error, and we cannot check the response at all.
|
|
|
|
for k, v := range resp.Header {
|
|
|
|
c.Writer.Header().Set(k, v[0])
|
|
|
|
}
|
|
|
|
c.Writer.WriteHeader(resp.StatusCode)
|
2023-11-24 12:42:29 +00:00
|
|
|
_, err = io.Copy(c.Writer, resp.Body)
|
2023-07-22 09:48:45 +00:00
|
|
|
if err != nil {
|
2024-01-14 11:21:03 +00:00
|
|
|
return ErrorWrapper(err, "copy_response_body_failed", http.StatusInternalServerError), nil
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
|
|
|
err = resp.Body.Close()
|
|
|
|
if err != nil {
|
2024-01-14 11:21:03 +00:00
|
|
|
return ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
2023-07-22 09:48:45 +00:00
|
|
|
}
|
2023-08-06 09:40:31 +00:00
|
|
|
|
2024-06-30 08:09:16 +00:00
|
|
|
if textResponse.Usage.TotalTokens == 0 || (textResponse.Usage.PromptTokens == 0 && textResponse.Usage.CompletionTokens == 0) {
|
2023-08-06 09:40:31 +00:00
|
|
|
completionTokens := 0
|
|
|
|
for _, choice := range textResponse.Choices {
|
2024-02-17 16:15:31 +00:00
|
|
|
completionTokens += CountTokenText(choice.Message.StringContent(), modelName)
|
2023-08-06 09:40:31 +00:00
|
|
|
}
|
2024-02-17 16:15:31 +00:00
|
|
|
textResponse.Usage = model.Usage{
|
2023-08-06 09:40:31 +00:00
|
|
|
PromptTokens: promptTokens,
|
|
|
|
CompletionTokens: completionTokens,
|
|
|
|
TotalTokens: promptTokens + completionTokens,
|
|
|
|
}
|
|
|
|
}
|
2023-07-22 09:48:45 +00:00
|
|
|
return nil, &textResponse.Usage
|
|
|
|
}
|