Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

264 wiersze
6.9 KiB

  1. package helper
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "github.com/QuantumNous/new-api/common"
  7. "github.com/QuantumNous/new-api/dto"
  8. "github.com/QuantumNous/new-api/logger"
  9. "github.com/QuantumNous/new-api/types"
  10. "github.com/gin-gonic/gin"
  11. "github.com/gorilla/websocket"
  12. )
  13. const (
  14. streamBodyWrittenKey = "stream_body_written"
  15. streamDataWrittenKey = "stream_data_written"
  16. )
  17. func MarkStreamBodyWritten(c *gin.Context) {
  18. if c == nil {
  19. return
  20. }
  21. c.Set(streamBodyWrittenKey, true)
  22. }
  23. func StreamBodyWritten(c *gin.Context) bool {
  24. if c == nil {
  25. return false
  26. }
  27. return c.GetBool(streamBodyWrittenKey)
  28. }
  29. func MarkStreamDataWritten(c *gin.Context) {
  30. if c == nil {
  31. return
  32. }
  33. MarkStreamBodyWritten(c)
  34. c.Set(streamDataWrittenKey, true)
  35. }
  36. func StreamDataWritten(c *gin.Context) bool {
  37. if c == nil {
  38. return false
  39. }
  40. return c.GetBool(streamDataWrittenKey)
  41. }
  42. func FlushWriter(c *gin.Context) (err error) {
  43. defer func() {
  44. if r := recover(); r != nil {
  45. err = fmt.Errorf("flush panic recovered: %v", r)
  46. }
  47. }()
  48. if c == nil || c.Writer == nil {
  49. return nil
  50. }
  51. if c.Request != nil && c.Request.Context().Err() != nil {
  52. return fmt.Errorf("request context done: %w", c.Request.Context().Err())
  53. }
  54. flusher, ok := c.Writer.(http.Flusher)
  55. if !ok {
  56. return errors.New("streaming error: flusher not found")
  57. }
  58. flusher.Flush()
  59. return nil
  60. }
  61. func SetEventStreamHeaders(c *gin.Context) {
  62. // 检查是否已经设置过头部
  63. if _, exists := c.Get("event_stream_headers_set"); exists {
  64. return
  65. }
  66. // 设置标志,表示头部已经设置过
  67. c.Set("event_stream_headers_set", true)
  68. c.Writer.Header().Set("Content-Type", "text/event-stream")
  69. c.Writer.Header().Set("Cache-Control", "no-cache")
  70. c.Writer.Header().Set("Connection", "keep-alive")
  71. c.Writer.Header().Set("Transfer-Encoding", "chunked")
  72. c.Writer.Header().Set("X-Accel-Buffering", "no")
  73. }
  74. func ClearEventStreamHeadersIfNotWritten(c *gin.Context) {
  75. if c == nil || c.Writer == nil || StreamBodyWritten(c) {
  76. return
  77. }
  78. c.Set("event_stream_headers_set", false)
  79. header := c.Writer.Header()
  80. header.Del("Content-Type")
  81. header.Del("Cache-Control")
  82. header.Del("Connection")
  83. header.Del("Transfer-Encoding")
  84. header.Del("X-Accel-Buffering")
  85. }
  86. func ClaudeData(c *gin.Context, resp dto.ClaudeResponse) error {
  87. jsonData, err := common.Marshal(resp)
  88. if err != nil {
  89. common.SysError("error marshalling stream response: " + err.Error())
  90. } else {
  91. c.Render(-1, common.CustomEvent{Data: fmt.Sprintf("event: %s\n", resp.Type)})
  92. c.Render(-1, common.CustomEvent{Data: "data: " + string(jsonData)})
  93. MarkStreamDataWritten(c)
  94. }
  95. _ = FlushWriter(c)
  96. return nil
  97. }
  98. func ClaudeChunkData(c *gin.Context, resp dto.ClaudeResponse, data string) {
  99. c.Render(-1, common.CustomEvent{Data: fmt.Sprintf("event: %s\n", resp.Type)})
  100. c.Render(-1, common.CustomEvent{Data: fmt.Sprintf("data: %s\n", data)})
  101. MarkStreamDataWritten(c)
  102. _ = FlushWriter(c)
  103. }
  104. func ResponseChunkData(c *gin.Context, resp dto.ResponsesStreamResponse, data string) {
  105. c.Render(-1, common.CustomEvent{Data: fmt.Sprintf("event: %s\n", resp.Type)})
  106. c.Render(-1, common.CustomEvent{Data: fmt.Sprintf("data: %s", data)})
  107. MarkStreamDataWritten(c)
  108. _ = FlushWriter(c)
  109. }
  110. func StringData(c *gin.Context, str string) error {
  111. if c == nil || c.Writer == nil {
  112. return errors.New("context or writer is nil")
  113. }
  114. if c.Request != nil && c.Request.Context().Err() != nil {
  115. return fmt.Errorf("request context done: %w", c.Request.Context().Err())
  116. }
  117. c.Render(-1, common.CustomEvent{Data: "data: " + str})
  118. MarkStreamDataWritten(c)
  119. return FlushWriter(c)
  120. }
  121. func PingData(c *gin.Context) error {
  122. if c == nil || c.Writer == nil {
  123. return errors.New("context or writer is nil")
  124. }
  125. if c.Request != nil && c.Request.Context().Err() != nil {
  126. return fmt.Errorf("request context done: %w", c.Request.Context().Err())
  127. }
  128. if _, err := c.Writer.Write([]byte(": PING\n\n")); err != nil {
  129. return fmt.Errorf("write ping data failed: %w", err)
  130. }
  131. MarkStreamBodyWritten(c)
  132. return FlushWriter(c)
  133. }
  134. func ObjectData(c *gin.Context, object interface{}) error {
  135. if object == nil {
  136. return errors.New("object is nil")
  137. }
  138. jsonData, err := common.Marshal(object)
  139. if err != nil {
  140. return fmt.Errorf("error marshalling object: %w", err)
  141. }
  142. return StringData(c, string(jsonData))
  143. }
  144. func Done(c *gin.Context) {
  145. _ = StringData(c, "[DONE]")
  146. }
  147. func WssString(c *gin.Context, ws *websocket.Conn, str string) error {
  148. if ws == nil {
  149. logger.LogError(c, "websocket connection is nil")
  150. return errors.New("websocket connection is nil")
  151. }
  152. //common.LogInfo(c, fmt.Sprintf("sending message: %s", str))
  153. return ws.WriteMessage(1, []byte(str))
  154. }
  155. func WssObject(c *gin.Context, ws *websocket.Conn, object interface{}) error {
  156. jsonData, err := common.Marshal(object)
  157. if err != nil {
  158. return fmt.Errorf("error marshalling object: %w", err)
  159. }
  160. if ws == nil {
  161. logger.LogError(c, "websocket connection is nil")
  162. return errors.New("websocket connection is nil")
  163. }
  164. //common.LogInfo(c, fmt.Sprintf("sending message: %s", jsonData))
  165. return ws.WriteMessage(1, jsonData)
  166. }
  167. func WssError(c *gin.Context, ws *websocket.Conn, openaiError types.OpenAIError) {
  168. if ws == nil {
  169. return
  170. }
  171. errorObj := &dto.RealtimeEvent{
  172. Type: "error",
  173. EventId: GetLocalRealtimeID(c),
  174. Error: &openaiError,
  175. }
  176. _ = WssObject(c, ws, errorObj)
  177. }
  178. func GetResponseID(c *gin.Context) string {
  179. logID := c.GetString(common.RequestIdKey)
  180. return fmt.Sprintf("chatcmpl-%s", logID)
  181. }
  182. func GetLocalRealtimeID(c *gin.Context) string {
  183. logID := c.GetString(common.RequestIdKey)
  184. return fmt.Sprintf("evt_%s", logID)
  185. }
  186. func GenerateStartEmptyResponse(id string, createAt int64, model string, systemFingerprint *string) *dto.ChatCompletionsStreamResponse {
  187. return &dto.ChatCompletionsStreamResponse{
  188. Id: id,
  189. Object: "chat.completion.chunk",
  190. Created: createAt,
  191. Model: model,
  192. SystemFingerprint: systemFingerprint,
  193. Choices: []dto.ChatCompletionsStreamResponseChoice{
  194. {
  195. Delta: dto.ChatCompletionsStreamResponseChoiceDelta{
  196. Role: "assistant",
  197. Content: common.GetPointer(""),
  198. },
  199. },
  200. },
  201. }
  202. }
  203. func GenerateStopResponse(id string, createAt int64, model string, finishReason string) *dto.ChatCompletionsStreamResponse {
  204. return &dto.ChatCompletionsStreamResponse{
  205. Id: id,
  206. Object: "chat.completion.chunk",
  207. Created: createAt,
  208. Model: model,
  209. SystemFingerprint: nil,
  210. Choices: []dto.ChatCompletionsStreamResponseChoice{
  211. {
  212. FinishReason: &finishReason,
  213. },
  214. },
  215. }
  216. }
  217. func GenerateFinalUsageResponse(id string, createAt int64, model string, usage dto.Usage) *dto.ChatCompletionsStreamResponse {
  218. return &dto.ChatCompletionsStreamResponse{
  219. Id: id,
  220. Object: "chat.completion.chunk",
  221. Created: createAt,
  222. Model: model,
  223. SystemFingerprint: nil,
  224. Choices: make([]dto.ChatCompletionsStreamResponseChoice, 0),
  225. Usage: &usage,
  226. }
  227. }