Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
32805849
authored
Jun 05, 2026
by
xujiantop-crypto
Committed by
GitHub
Jun 05, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: reuse stream scanner buffer in channel handlers (#5225)
parent
01c2128e
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
38 additions
and
12 deletions
+38
-12
relay/channel/cloudflare/relay_cloudflare.go
+1
-1
relay/channel/cohere/relay-cohere.go
+4
-2
relay/channel/coze/relay-coze.go
+1
-1
relay/channel/ollama/relay-ollama.go
+2
-2
relay/channel/ollama/stream.go
+1
-2
relay/channel/tencent/relay-tencent.go
+1
-1
relay/channel/zhipu/relay-zhipu.go
+4
-1
relay/helper/stream_scanner.go
+7
-2
relay/helper/stream_scanner_test.go
+17
-0
No files found.
relay/channel/cloudflare/relay_cloudflare.go
View file @
32805849
...
...
@@ -30,7 +30,7 @@ func convertCf2CompletionsRequest(textRequest dto.GeneralOpenAIRequest) *CfReque
}
func
cfStreamHandler
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
http
.
Response
)
(
*
types
.
NewAPIError
,
*
dto
.
Usage
)
{
scanner
:=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
resp
.
Body
)
scanner
.
Split
(
bufio
.
ScanLines
)
helper
.
SetEventStreamHeaders
(
c
)
...
...
relay/channel/cohere/relay-cohere.go
View file @
32805849
package
cohere
import
(
"bufio"
"encoding/json"
"io"
"net/http"
...
...
@@ -86,7 +85,7 @@ func cohereStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http
createdTime
:=
common
.
GetTimestamp
()
usage
:=
&
dto
.
Usage
{}
responseText
:=
""
scanner
:=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
resp
.
Body
)
scanner
.
Split
(
func
(
data
[]
byte
,
atEOF
bool
)
(
advance
int
,
token
[]
byte
,
err
error
)
{
if
atEOF
&&
len
(
data
)
==
0
{
return
0
,
nil
,
nil
...
...
@@ -106,6 +105,9 @@ func cohereStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http
data
:=
scanner
.
Text
()
dataChan
<-
data
}
if
err
:=
scanner
.
Err
();
err
!=
nil
{
common
.
SysLog
(
"error reading stream: "
+
err
.
Error
())
}
stopChan
<-
true
}()
helper
.
SetEventStreamHeaders
(
c
)
...
...
relay/channel/coze/relay-coze.go
View file @
32805849
...
...
@@ -98,7 +98,7 @@ func cozeChatHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Res
}
func
cozeChatStreamHandler
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
http
.
Response
)
(
*
dto
.
Usage
,
*
types
.
NewAPIError
)
{
scanner
:=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
resp
.
Body
)
scanner
.
Split
(
bufio
.
ScanLines
)
helper
.
SetEventStreamHeaders
(
c
)
id
:=
helper
.
GetResponseID
(
c
)
...
...
relay/channel/ollama/relay-ollama.go
View file @
32805849
package
ollama
import
(
"bufio"
"encoding/json"
"fmt"
"io"
...
...
@@ -12,6 +11,7 @@ import (
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/dto"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
"github.com/QuantumNous/new-api/relay/helper"
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/types"
...
...
@@ -397,7 +397,7 @@ func PullOllamaModelStream(baseURL, apiKey, modelName string, progressCallback f
}
// 读取流式响应
scanner
:=
bufio
.
New
Scanner
(
response
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
response
.
Body
)
successful
:=
false
for
scanner
.
Scan
()
{
line
:=
scanner
.
Text
()
...
...
relay/channel/ollama/stream.go
View file @
32805849
package
ollama
import
(
"bufio"
"encoding/json"
"fmt"
"io"
...
...
@@ -70,7 +69,7 @@ func ollamaStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http
defer
service
.
CloseResponseBodyGracefully
(
resp
)
helper
.
SetEventStreamHeaders
(
c
)
scanner
:=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
resp
.
Body
)
usage
:=
&
dto
.
Usage
{}
var
model
=
info
.
UpstreamModelName
var
responseId
=
common
.
GetUUID
()
...
...
relay/channel/tencent/relay-tencent.go
View file @
32805849
...
...
@@ -92,7 +92,7 @@ func streamResponseTencent2OpenAI(TencentResponse *TencentChatResponse) *dto.Cha
func
tencentStreamHandler
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
http
.
Response
)
(
*
dto
.
Usage
,
*
types
.
NewAPIError
)
{
var
responseText
string
scanner
:=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
resp
.
Body
)
scanner
.
Split
(
bufio
.
ScanLines
)
helper
.
SetEventStreamHeaders
(
c
)
...
...
relay/channel/zhipu/relay-zhipu.go
View file @
32805849
...
...
@@ -157,7 +157,7 @@ func streamMetaResponseZhipu2OpenAI(zhipuResponse *ZhipuStreamMetaResponse) (*dt
func
zhipuStreamHandler
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
http
.
Response
)
(
*
dto
.
Usage
,
*
types
.
NewAPIError
)
{
var
usage
*
dto
.
Usage
scanner
:=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
:=
helper
.
NewStream
Scanner
(
resp
.
Body
)
scanner
.
Split
(
bufio
.
ScanLines
)
dataChan
:=
make
(
chan
string
)
metaChan
:=
make
(
chan
string
)
...
...
@@ -180,6 +180,9 @@ func zhipuStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.
}
}
}
if
err
:=
scanner
.
Err
();
err
!=
nil
{
common
.
SysLog
(
"error reading stream: "
+
err
.
Error
())
}
stopChan
<-
true
}()
helper
.
SetEventStreamHeaders
(
c
)
...
...
relay/helper/stream_scanner.go
View file @
32805849
...
...
@@ -34,6 +34,12 @@ func getScannerBufferSize() int {
return
DefaultMaxScannerBufferSize
}
func
NewStreamScanner
(
reader
io
.
Reader
)
*
bufio
.
Scanner
{
scanner
:=
bufio
.
NewScanner
(
reader
)
scanner
.
Buffer
(
make
([]
byte
,
InitialScannerBufferSize
),
getScannerBufferSize
())
return
scanner
}
func
StreamScannerHandler
(
c
*
gin
.
Context
,
resp
*
http
.
Response
,
info
*
relaycommon
.
RelayInfo
,
dataHandler
func
(
data
string
,
sr
*
StreamResult
))
{
if
resp
==
nil
||
dataHandler
==
nil
{
...
...
@@ -54,7 +60,7 @@ func StreamScannerHandler(c *gin.Context, resp *http.Response, info *relaycommon
var
(
stopChan
=
make
(
chan
bool
,
3
)
// 增加缓冲区避免阻塞
scanner
=
bufio
.
New
Scanner
(
resp
.
Body
)
scanner
=
NewStream
Scanner
(
resp
.
Body
)
ticker
=
time
.
NewTicker
(
streamingTimeout
)
pingTicker
*
time
.
Ticker
writeMutex
sync
.
Mutex
// Mutex to protect concurrent writes
...
...
@@ -104,7 +110,6 @@ func StreamScannerHandler(c *gin.Context, resp *http.Response, info *relaycommon
close
(
stopChan
)
}()
scanner
.
Buffer
(
make
([]
byte
,
InitialScannerBufferSize
),
getScannerBufferSize
())
scanner
.
Split
(
bufio
.
ScanLines
)
SetEventStreamHeaders
(
c
)
...
...
relay/helper/stream_scanner_test.go
View file @
32805849
package
helper
import
(
"bufio"
"fmt"
"io"
"net/http"
...
...
@@ -81,6 +82,22 @@ func TestStreamScannerHandler_NilInputs(t *testing.T) {
StreamScannerHandler
(
c
,
&
http
.
Response
{
Body
:
io
.
NopCloser
(
strings
.
NewReader
(
""
))},
info
,
nil
)
}
func
TestNewStreamScanner_AllowsLargeStreamLine
(
t
*
testing
.
T
)
{
oldBufferMB
:=
constant
.
StreamScannerMaxBufferMB
constant
.
StreamScannerMaxBufferMB
=
1
t
.
Cleanup
(
func
()
{
constant
.
StreamScannerMaxBufferMB
=
oldBufferMB
})
payload
:=
strings
.
Repeat
(
"x"
,
128
<<
10
)
scanner
:=
NewStreamScanner
(
strings
.
NewReader
(
"data: "
+
payload
+
"
\n
"
))
scanner
.
Split
(
bufio
.
ScanLines
)
require
.
True
(
t
,
scanner
.
Scan
())
assert
.
Equal
(
t
,
"data: "
+
payload
,
scanner
.
Text
())
require
.
NoError
(
t
,
scanner
.
Err
())
}
func
TestStreamScannerHandler_EmptyBody
(
t
*
testing
.
T
)
{
t
.
Parallel
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment