openai_sse_data.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package service
  2. import (
  3. "strings"
  4. "github.com/tidwall/gjson"
  5. )
  6. type openAISSEDataAccumulator struct {
  7. lines []string
  8. }
  9. func (a *openAISSEDataAccumulator) AddLine(line string, fn func([]byte)) {
  10. if fn == nil {
  11. return
  12. }
  13. trimmedLine := strings.TrimRight(line, "\r\n")
  14. if data, ok := extractOpenAISSEDataLine(trimmedLine); ok {
  15. a.lines = append(a.lines, data)
  16. return
  17. }
  18. if strings.TrimSpace(trimmedLine) == "" {
  19. a.Flush(fn)
  20. }
  21. }
  22. func (a *openAISSEDataAccumulator) Flush(fn func([]byte)) {
  23. if fn == nil || len(a.lines) == 0 {
  24. return
  25. }
  26. emitOpenAISSEDataPayloads(a.lines, fn)
  27. a.lines = a.lines[:0]
  28. }
  29. func forEachOpenAISSEDataPayload(body string, fn func([]byte)) {
  30. if fn == nil || strings.TrimSpace(body) == "" {
  31. return
  32. }
  33. var acc openAISSEDataAccumulator
  34. for _, line := range strings.Split(body, "\n") {
  35. acc.AddLine(line, fn)
  36. }
  37. acc.Flush(fn)
  38. }
  39. func forEachOpenAISSEFrame(body string, fn func(string, []byte)) {
  40. if fn == nil || strings.TrimSpace(body) == "" {
  41. return
  42. }
  43. var parser openAICompatSSEFrameParser
  44. emit := func(frame openAICompatSSEFrame, ok bool) {
  45. if !ok {
  46. return
  47. }
  48. emitData := func(value string) {
  49. value = strings.TrimSpace(value)
  50. if value == "" || value == "[DONE]" {
  51. return
  52. }
  53. data := []byte(value)
  54. fn(effectiveOpenAISSEEventType(data, frame.EventType), data)
  55. }
  56. if gjson.Valid(frame.Data) {
  57. emitData(frame.Data)
  58. return
  59. }
  60. for _, value := range strings.Split(frame.Data, "\n") {
  61. emitData(value)
  62. }
  63. }
  64. for _, line := range strings.Split(body, "\n") {
  65. emit(parser.AddLine(strings.TrimRight(line, "\r")))
  66. }
  67. emit(parser.Finish())
  68. }
  69. func emitOpenAISSEDataPayloads(lines []string, fn func([]byte)) {
  70. if fn == nil || len(lines) == 0 {
  71. return
  72. }
  73. if len(lines) == 1 {
  74. emitOpenAISSEDataPayload(lines[0], fn)
  75. return
  76. }
  77. joined := strings.Join(lines, "\n")
  78. if gjson.Valid(joined) {
  79. emitOpenAISSEDataPayload(joined, fn)
  80. return
  81. }
  82. for _, line := range lines {
  83. emitOpenAISSEDataPayload(line, fn)
  84. }
  85. }
  86. func emitOpenAISSEDataPayload(data string, fn func([]byte)) {
  87. data = strings.TrimSpace(data)
  88. if data == "" || data == "[DONE]" {
  89. return
  90. }
  91. fn([]byte(data))
  92. }