text.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package ali
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "github.com/gin-gonic/gin"
  6. "io"
  7. "net/http"
  8. "one-api/common"
  9. "one-api/dto"
  10. "one-api/service"
  11. "strings"
  12. )
  13. // https://help.aliyun.com/document_detail/613695.html?spm=a2c4g.2399480.0.0.1adb778fAdzP9w#341800c0f8w0r
  14. const EnableSearchModelSuffix = "-internet"
  15. func requestOpenAI2Ali(request dto.GeneralOpenAIRequest) *dto.GeneralOpenAIRequest {
  16. if request.TopP >= 1 {
  17. request.TopP = 0.999
  18. } else if request.TopP <= 0 {
  19. request.TopP = 0.001
  20. }
  21. return &request
  22. }
  23. func embeddingRequestOpenAI2Ali(request dto.EmbeddingRequest) *AliEmbeddingRequest {
  24. if request.Model == "" {
  25. request.Model = "text-embedding-v1"
  26. }
  27. return &AliEmbeddingRequest{
  28. Model: request.Model,
  29. Input: struct {
  30. Texts []string `json:"texts"`
  31. }{
  32. Texts: request.ParseInput(),
  33. },
  34. }
  35. }
  36. func aliEmbeddingHandler(c *gin.Context, resp *http.Response) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
  37. var aliResponse AliEmbeddingResponse
  38. err := json.NewDecoder(resp.Body).Decode(&aliResponse)
  39. if err != nil {
  40. return service.OpenAIErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
  41. }
  42. err = resp.Body.Close()
  43. if err != nil {
  44. return service.OpenAIErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
  45. }
  46. if aliResponse.Code != "" {
  47. return &dto.OpenAIErrorWithStatusCode{
  48. Error: dto.OpenAIError{
  49. Message: aliResponse.Message,
  50. Type: aliResponse.Code,
  51. Param: aliResponse.RequestId,
  52. Code: aliResponse.Code,
  53. },
  54. StatusCode: resp.StatusCode,
  55. }, nil
  56. }
  57. fullTextResponse := embeddingResponseAli2OpenAI(&aliResponse)
  58. jsonResponse, err := json.Marshal(fullTextResponse)
  59. if err != nil {
  60. return service.OpenAIErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
  61. }
  62. c.Writer.Header().Set("Content-Type", "application/json")
  63. c.Writer.WriteHeader(resp.StatusCode)
  64. _, err = c.Writer.Write(jsonResponse)
  65. return nil, &fullTextResponse.Usage
  66. }
  67. func embeddingResponseAli2OpenAI(response *AliEmbeddingResponse) *dto.OpenAIEmbeddingResponse {
  68. openAIEmbeddingResponse := dto.OpenAIEmbeddingResponse{
  69. Object: "list",
  70. Data: make([]dto.OpenAIEmbeddingResponseItem, 0, len(response.Output.Embeddings)),
  71. Model: "text-embedding-v1",
  72. Usage: dto.Usage{TotalTokens: response.Usage.TotalTokens},
  73. }
  74. for _, item := range response.Output.Embeddings {
  75. openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, dto.OpenAIEmbeddingResponseItem{
  76. Object: `embedding`,
  77. Index: item.TextIndex,
  78. Embedding: item.Embedding,
  79. })
  80. }
  81. return &openAIEmbeddingResponse
  82. }
  83. func responseAli2OpenAI(response *AliResponse) *dto.OpenAITextResponse {
  84. content, _ := json.Marshal(response.Output.Text)
  85. choice := dto.OpenAITextResponseChoice{
  86. Index: 0,
  87. Message: dto.Message{
  88. Role: "assistant",
  89. Content: content,
  90. },
  91. FinishReason: response.Output.FinishReason,
  92. }
  93. fullTextResponse := dto.OpenAITextResponse{
  94. Id: response.RequestId,
  95. Object: "chat.completion",
  96. Created: common.GetTimestamp(),
  97. Choices: []dto.OpenAITextResponseChoice{choice},
  98. Usage: dto.Usage{
  99. PromptTokens: response.Usage.InputTokens,
  100. CompletionTokens: response.Usage.OutputTokens,
  101. TotalTokens: response.Usage.InputTokens + response.Usage.OutputTokens,
  102. },
  103. }
  104. return &fullTextResponse
  105. }
  106. func streamResponseAli2OpenAI(aliResponse *AliResponse) *dto.ChatCompletionsStreamResponse {
  107. var choice dto.ChatCompletionsStreamResponseChoice
  108. choice.Delta.SetContentString(aliResponse.Output.Text)
  109. if aliResponse.Output.FinishReason != "null" {
  110. finishReason := aliResponse.Output.FinishReason
  111. choice.FinishReason = &finishReason
  112. }
  113. response := dto.ChatCompletionsStreamResponse{
  114. Id: aliResponse.RequestId,
  115. Object: "chat.completion.chunk",
  116. Created: common.GetTimestamp(),
  117. Model: "ernie-bot",
  118. Choices: []dto.ChatCompletionsStreamResponseChoice{choice},
  119. }
  120. return &response
  121. }
  122. func aliStreamHandler(c *gin.Context, resp *http.Response) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
  123. var usage dto.Usage
  124. scanner := bufio.NewScanner(resp.Body)
  125. scanner.Split(bufio.ScanLines)
  126. dataChan := make(chan string)
  127. stopChan := make(chan bool)
  128. go func() {
  129. for scanner.Scan() {
  130. data := scanner.Text()
  131. if len(data) < 5 { // ignore blank line or wrong format
  132. continue
  133. }
  134. if data[:5] != "data:" {
  135. continue
  136. }
  137. data = data[5:]
  138. dataChan <- data
  139. }
  140. stopChan <- true
  141. }()
  142. service.SetEventStreamHeaders(c)
  143. lastResponseText := ""
  144. c.Stream(func(w io.Writer) bool {
  145. select {
  146. case data := <-dataChan:
  147. var aliResponse AliResponse
  148. err := json.Unmarshal([]byte(data), &aliResponse)
  149. if err != nil {
  150. common.SysError("error unmarshalling stream response: " + err.Error())
  151. return true
  152. }
  153. if aliResponse.Usage.OutputTokens != 0 {
  154. usage.PromptTokens = aliResponse.Usage.InputTokens
  155. usage.CompletionTokens = aliResponse.Usage.OutputTokens
  156. usage.TotalTokens = aliResponse.Usage.InputTokens + aliResponse.Usage.OutputTokens
  157. }
  158. response := streamResponseAli2OpenAI(&aliResponse)
  159. response.Choices[0].Delta.SetContentString(strings.TrimPrefix(response.Choices[0].Delta.GetContentString(), lastResponseText))
  160. lastResponseText = aliResponse.Output.Text
  161. jsonResponse, err := json.Marshal(response)
  162. if err != nil {
  163. common.SysError("error marshalling stream response: " + err.Error())
  164. return true
  165. }
  166. c.Render(-1, common.CustomEvent{Data: "data: " + string(jsonResponse)})
  167. return true
  168. case <-stopChan:
  169. c.Render(-1, common.CustomEvent{Data: "data: [DONE]"})
  170. return false
  171. }
  172. })
  173. err := resp.Body.Close()
  174. if err != nil {
  175. return service.OpenAIErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
  176. }
  177. return nil, &usage
  178. }
  179. func aliHandler(c *gin.Context, resp *http.Response) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
  180. var aliResponse AliResponse
  181. responseBody, err := io.ReadAll(resp.Body)
  182. if err != nil {
  183. return service.OpenAIErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
  184. }
  185. err = resp.Body.Close()
  186. if err != nil {
  187. return service.OpenAIErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
  188. }
  189. err = json.Unmarshal(responseBody, &aliResponse)
  190. if err != nil {
  191. return service.OpenAIErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
  192. }
  193. if aliResponse.Code != "" {
  194. return &dto.OpenAIErrorWithStatusCode{
  195. Error: dto.OpenAIError{
  196. Message: aliResponse.Message,
  197. Type: aliResponse.Code,
  198. Param: aliResponse.RequestId,
  199. Code: aliResponse.Code,
  200. },
  201. StatusCode: resp.StatusCode,
  202. }, nil
  203. }
  204. fullTextResponse := responseAli2OpenAI(&aliResponse)
  205. jsonResponse, err := json.Marshal(fullTextResponse)
  206. if err != nil {
  207. return service.OpenAIErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
  208. }
  209. c.Writer.Header().Set("Content-Type", "application/json")
  210. c.Writer.WriteHeader(resp.StatusCode)
  211. _, err = c.Writer.Write(jsonResponse)
  212. return nil, &fullTextResponse.Usage
  213. }