mirror of
https://github.com/alibaba/higress.git
synced 2026-06-09 12:47:28 +08:00
feat: Unify the SSE processing logic (#1800)
This commit is contained in:
@@ -188,89 +188,32 @@ func (m *qwenProvider) onEmbeddingsRequestBody(ctx wrapper.HttpContext, body []b
|
||||
return json.Marshal(qwenRequest)
|
||||
}
|
||||
|
||||
func (m *qwenProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name ApiName, chunk []byte, isLastChunk bool, log wrapper.Log) ([]byte, error) {
|
||||
func (m *qwenProvider) OnStreamingEvent(ctx wrapper.HttpContext, name ApiName, event StreamEvent, log wrapper.Log) ([]StreamEvent, error) {
|
||||
if m.config.qwenEnableCompatible || name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
|
||||
receivedBody := chunk
|
||||
if bufferedStreamingBody, has := ctx.GetContext(ctxKeyStreamingBody).([]byte); has {
|
||||
receivedBody = append(bufferedStreamingBody, chunk...)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
incrementalStreaming := ctx.GetBoolContext(ctxKeyIncrementalStreaming, false)
|
||||
|
||||
eventStartIndex, lineStartIndex, valueStartIndex := -1, -1, -1
|
||||
|
||||
defer func() {
|
||||
if eventStartIndex >= 0 && eventStartIndex < len(receivedBody) {
|
||||
// Just in case the received chunk is not a complete event.
|
||||
ctx.SetContext(ctxKeyStreamingBody, receivedBody[eventStartIndex:])
|
||||
} else {
|
||||
ctx.SetContext(ctxKeyStreamingBody, nil)
|
||||
}
|
||||
}()
|
||||
|
||||
// Sample Qwen event response:
|
||||
//
|
||||
// event:result
|
||||
// :HTTP_STATUS/200
|
||||
// data:{"output":{"choices":[{"message":{"content":"你好!","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":116,"input_tokens":114,"output_tokens":2},"request_id":"71689cfc-1f42-9949-86e8-9563b7f832b1"}
|
||||
//
|
||||
// event:error
|
||||
// :HTTP_STATUS/400
|
||||
// data:{"code":"InvalidParameter","message":"Preprocessor error","request_id":"0cbe6006-faec-9854-bf8b-c906d75c3bd8"}
|
||||
//
|
||||
|
||||
var responseBuilder strings.Builder
|
||||
currentKey := ""
|
||||
currentEvent := &streamEvent{}
|
||||
i, length := 0, len(receivedBody)
|
||||
for i = 0; i < length; i++ {
|
||||
ch := receivedBody[i]
|
||||
if ch != '\n' {
|
||||
if lineStartIndex == -1 {
|
||||
if eventStartIndex == -1 {
|
||||
eventStartIndex = i
|
||||
}
|
||||
lineStartIndex = i
|
||||
valueStartIndex = -1
|
||||
}
|
||||
if valueStartIndex == -1 {
|
||||
if ch == ':' {
|
||||
valueStartIndex = i + 1
|
||||
currentKey = string(receivedBody[lineStartIndex:valueStartIndex])
|
||||
}
|
||||
} else if valueStartIndex == i && ch == ' ' {
|
||||
// Skip leading spaces in data.
|
||||
valueStartIndex = i + 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if lineStartIndex != -1 {
|
||||
value := string(receivedBody[valueStartIndex:i])
|
||||
currentEvent.setValue(currentKey, value)
|
||||
} else {
|
||||
// Extra new line. The current event is complete.
|
||||
log.Debugf("processing event: %v", currentEvent)
|
||||
if err := m.convertStreamEvent(ctx, &responseBuilder, currentEvent, incrementalStreaming, log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Reset event parsing state.
|
||||
eventStartIndex = -1
|
||||
currentEvent = &streamEvent{}
|
||||
}
|
||||
|
||||
// Reset line parsing state.
|
||||
lineStartIndex = -1
|
||||
valueStartIndex = -1
|
||||
currentKey = ""
|
||||
qwenResponse := &qwenTextGenResponse{}
|
||||
if err := json.Unmarshal([]byte(event.Data), qwenResponse); err != nil {
|
||||
log.Errorf("unable to unmarshal Qwen response: %v", err)
|
||||
return nil, fmt.Errorf("unable to unmarshal Qwen response: %v", err)
|
||||
}
|
||||
|
||||
modifiedResponseChunk := responseBuilder.String()
|
||||
log.Debugf("=== modified response chunk: %s", modifiedResponseChunk)
|
||||
return []byte(modifiedResponseChunk), nil
|
||||
var outputEvents []StreamEvent
|
||||
responses := m.buildChatCompletionStreamingResponse(ctx, qwenResponse, incrementalStreaming, log)
|
||||
for _, response := range responses {
|
||||
responseBody, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
log.Errorf("unable to marshal response: %v", err)
|
||||
return nil, fmt.Errorf("unable to marshal response: %v", err)
|
||||
}
|
||||
modifiedEvent := event
|
||||
modifiedEvent.Data = string(responseBody)
|
||||
outputEvents = append(outputEvents, modifiedEvent)
|
||||
}
|
||||
return outputEvents, nil
|
||||
}
|
||||
|
||||
func (m *qwenProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
@@ -481,39 +424,6 @@ func (m *qwenProvider) buildChatCompletionStreamingResponse(ctx wrapper.HttpCont
|
||||
return responses
|
||||
}
|
||||
|
||||
func (m *qwenProvider) convertStreamEvent(ctx wrapper.HttpContext, responseBuilder *strings.Builder, event *streamEvent, incrementalStreaming bool, log wrapper.Log) error {
|
||||
if event.Data == streamEndDataValue {
|
||||
m.appendStreamEvent(responseBuilder, event)
|
||||
return nil
|
||||
}
|
||||
|
||||
if event.Event != eventResult || event.HttpStatus != httpStatus200 {
|
||||
// Something goes wrong. Just pass through the event.
|
||||
m.appendStreamEvent(responseBuilder, event)
|
||||
return nil
|
||||
}
|
||||
|
||||
qwenResponse := &qwenTextGenResponse{}
|
||||
if err := json.Unmarshal([]byte(event.Data), qwenResponse); err != nil {
|
||||
log.Errorf("unable to unmarshal Qwen response: %v", err)
|
||||
return fmt.Errorf("unable to unmarshal Qwen response: %v", err)
|
||||
}
|
||||
|
||||
responses := m.buildChatCompletionStreamingResponse(ctx, qwenResponse, incrementalStreaming, log)
|
||||
for _, response := range responses {
|
||||
responseBody, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
log.Errorf("unable to marshal response: %v", err)
|
||||
return fmt.Errorf("unable to marshal response: %v", err)
|
||||
}
|
||||
modifiedEvent := &*event
|
||||
modifiedEvent.Data = string(responseBody)
|
||||
m.appendStreamEvent(responseBuilder, modifiedEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *qwenProvider) insertHttpContextMessage(body []byte, content string, onlyOneSystemBeforeFile bool) ([]byte, error) {
|
||||
request := &qwenTextGenRequest{}
|
||||
if err := json.Unmarshal(body, request); err != nil {
|
||||
@@ -558,7 +468,7 @@ func (m *qwenProvider) insertHttpContextMessage(body []byte, content string, onl
|
||||
return json.Marshal(request)
|
||||
}
|
||||
|
||||
func (m *qwenProvider) appendStreamEvent(responseBuilder *strings.Builder, event *streamEvent) {
|
||||
func (m *qwenProvider) appendStreamEvent(responseBuilder *strings.Builder, event *StreamEvent) {
|
||||
responseBuilder.WriteString(streamDataItemKey)
|
||||
responseBuilder.WriteString(event.Data)
|
||||
responseBuilder.WriteString("\n\n")
|
||||
|
||||
Reference in New Issue
Block a user