Skip to content

Commit c25f53e

Browse files
authored
Merge branch 'main' into feature/tls-annotation
2 parents 8bfd938 + 748bcb0 commit c25f53e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+813
-618
lines changed

CODEOWNERS

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
/envoy @gengleilei @johnlanni
33
/istio @SpecialYang @johnlanni
44
/pkg @SpecialYang @johnlanni @CH3CHO
5-
/plugins @johnlanni @WeixinX @CH3CHO
5+
/plugins @johnlanni @CH3CHO @rinfx
6+
/plugins/wasm-go/extensions/ai-proxy @cr7258 @CH3CHO @rinfx
67
/plugins/wasm-rust @007gzs @jizhuozhi
78
/registry @NameHaibinZhang @2456868764 @johnlanni
89
/test @Xunzhuo @2456868764 @CH3CHO

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
</h1>
77
<h4 align="center"> AI Native API Gateway </h4>
88

9+
<div align="center">
10+
911
[![Build Status](https://github.com/alibaba/higress/actions/workflows/build-and-test.yaml/badge.svg?branch=main)](https://github.com/alibaba/higress/actions)
1012
[![license](https://img.shields.io/github/license/alibaba/higress.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
1113

14+
<a href="https://trendshift.io/repositories/10918" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10918" alt="alibaba%2Fhigress | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
15+
</div>
16+
1217
[**官网**](https://higress.cn/) &nbsp; |
1318
&nbsp; [**文档**](https://higress.cn/docs/latest/overview/what-is-higress/) &nbsp; |
1419
&nbsp; [**博客**](https://higress.cn/blog/) &nbsp; |
@@ -17,6 +22,7 @@
1722
&nbsp; [**AI插件**](https://higress.cn/plugin/) &nbsp;
1823

1924

25+
2026
<p>
2127
<a href="README_EN.md"> English <a/>| 中文 | <a href="README_JP.md"> 日本語 <a/>
2228
</p>

plugins/wasm-go/extensions/ai-cache/cache/provider.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cache
22

33
import (
44
"errors"
5+
"strings"
56

67
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
78
"github.com/tidwall/gjson"
@@ -62,7 +63,12 @@ func (c *ProviderConfig) FromJson(json gjson.Result) {
6263
c.serviceName = json.Get("serviceName").String()
6364
c.servicePort = int(json.Get("servicePort").Int())
6465
if !json.Get("servicePort").Exists() {
65-
c.servicePort = 6379
66+
if strings.HasSuffix(c.serviceName, ".static") {
67+
// use default logic port which is 80 for static service
68+
c.servicePort = 80
69+
} else {
70+
c.servicePort = 6379
71+
}
6672
}
6773
c.serviceHost = json.Get("serviceHost").String()
6874
c.username = json.Get("username").String()

plugins/wasm-go/extensions/ai-cache/core.go

+3
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ func processCacheHit(key string, response string, stream bool, ctx wrapper.HttpC
7474

7575
ctx.SetContext(CACHE_KEY_CONTEXT_KEY, nil)
7676

77+
ctx.SetUserAttribute("cache_status", "hit")
78+
ctx.WriteUserAttributeToLogWithKey(wrapper.AILogKey)
79+
7780
if stream {
7881
proxywasm.SendHttpResponseWithDetail(200, "ai-cache.hit", [][2]string{{"content-type", "text/event-stream; charset=utf-8"}}, []byte(fmt.Sprintf(c.StreamResponseTemplate, escapedResponse)), -1)
7982
} else {

plugins/wasm-go/extensions/ai-cache/go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ replace github.com/alibaba/higress/plugins/wasm-go => ../..
88

99
require (
1010
github.com/alibaba/higress/plugins/wasm-go v1.4.2
11-
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f
11+
github.com/google/uuid v1.6.0
12+
github.com/higress-group/proxy-wasm-go-sdk v1.0.0
1213
github.com/tidwall/gjson v1.17.3
1314
github.com/tidwall/resp v0.1.1
1415
// github.com/weaviate/weaviate-go-client/v4 v4.15.1
1516
)
1617

1718
require (
18-
github.com/google/uuid v1.6.0 // indirect
1919
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect
2020
github.com/magefile/mage v1.14.0 // indirect
2121
github.com/stretchr/testify v1.9.0 // indirect

plugins/wasm-go/extensions/ai-cache/go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
33
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
44
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
55
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
6-
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f h1:ZIiIBRvIw62gA5MJhuwp1+2wWbqL9IGElQ499rUsYYg=
7-
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
6+
github.com/higress-group/proxy-wasm-go-sdk v1.0.0 h1:BZRNf4R7jr9hwRivg/E29nkVaKEak5MWjBDhWjuHijU=
7+
github.com/higress-group/proxy-wasm-go-sdk v1.0.0/go.mod h1:iiSyFbo+rAtbtGt/bsefv8GU57h9CCLYGJA74/tF5/0=
88
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
99
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
1010
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

plugins/wasm-go/extensions/ai-cache/main.go

+6
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,15 @@ func onHttpRequestBody(ctx wrapper.HttpContext, c config.PluginConfig, body []by
128128
func onHttpResponseHeaders(ctx wrapper.HttpContext, c config.PluginConfig, log wrapper.Log) types.Action {
129129
skipCache := ctx.GetContext(SKIP_CACHE_HEADER)
130130
if skipCache != nil {
131+
ctx.SetUserAttribute("cache_status", "skip")
132+
ctx.WriteUserAttributeToLogWithKey(wrapper.AILogKey)
131133
ctx.DontReadResponseBody()
132134
return types.ActionContinue
133135
}
136+
if ctx.GetContext(CACHE_KEY_CONTEXT_KEY) != nil {
137+
ctx.SetUserAttribute("cache_status", "miss")
138+
ctx.WriteUserAttributeToLogWithKey(wrapper.AILogKey)
139+
}
134140
contentType, _ := proxywasm.GetHttpResponseHeader("content-type")
135141
if strings.Contains(contentType, "text/event-stream") {
136142
ctx.SetContext(STREAM_CONTEXT_KEY, struct{}{})

plugins/wasm-go/extensions/ai-cache/util.go

+45-42
Original file line numberDiff line numberDiff line change
@@ -101,55 +101,58 @@ func processStreamLastChunk(ctx wrapper.HttpContext, c config.PluginConfig, chun
101101
}
102102

103103
func processSSEMessage(ctx wrapper.HttpContext, c config.PluginConfig, sseMessage string, log wrapper.Log) (string, error) {
104-
subMessages := strings.Split(sseMessage, "\n")
105-
var message string
106-
for _, msg := range subMessages {
107-
if strings.HasPrefix(msg, "data:") {
108-
message = msg
109-
break
104+
content := ""
105+
for _, chunk := range strings.Split(sseMessage, "\n\n") {
106+
log.Infof("chunk _ : %s", chunk)
107+
subMessages := strings.Split(chunk, "\n")
108+
var message string
109+
for _, msg := range subMessages {
110+
if strings.HasPrefix(msg, "data:") {
111+
message = msg
112+
break
113+
}
114+
}
115+
if len(message) < 6 {
116+
return content, fmt.Errorf("[processSSEMessage] invalid message: %s", message)
110117
}
111-
}
112-
if len(message) < 6 {
113-
return "", fmt.Errorf("[processSSEMessage] invalid message: %s", message)
114-
}
115118

116-
// skip the prefix "data:"
117-
bodyJson := message[5:]
119+
// skip the prefix "data:"
120+
bodyJson := message[5:]
118121

119-
if strings.TrimSpace(bodyJson) == "[DONE]" {
120-
return "", nil
121-
}
122+
if strings.TrimSpace(bodyJson) == "[DONE]" {
123+
return content, nil
124+
}
122125

123-
// Extract values from JSON fields
124-
responseBody := gjson.Get(bodyJson, c.CacheStreamValueFrom)
125-
toolCalls := gjson.Get(bodyJson, c.CacheToolCallsFrom)
126+
// Extract values from JSON fields
127+
responseBody := gjson.Get(bodyJson, c.CacheStreamValueFrom)
128+
toolCalls := gjson.Get(bodyJson, c.CacheToolCallsFrom)
126129

127-
if toolCalls.Exists() {
128-
// TODO: Temporarily store the tool_calls value in the context for processing
129-
ctx.SetContext(TOOL_CALLS_CONTEXT_KEY, toolCalls.String())
130-
}
131-
132-
// Check if the ResponseBody field exists
133-
if !responseBody.Exists() {
134-
if ctx.GetContext(CACHE_CONTENT_CONTEXT_KEY) != nil {
135-
log.Debugf("[processSSEMessage] unable to extract content from message; cache content is not nil: %s", message)
136-
return "", nil
130+
if toolCalls.Exists() {
131+
// TODO: Temporarily store the tool_calls value in the context for processing
132+
ctx.SetContext(TOOL_CALLS_CONTEXT_KEY, toolCalls.String())
137133
}
138-
return "", fmt.Errorf("[processSSEMessage] unable to extract content from message; cache content is nil: %s", message)
139-
} else {
140-
tempContentI := ctx.GetContext(CACHE_CONTENT_CONTEXT_KEY)
141134

142-
// If there is no content in the cache, initialize and set the content
143-
if tempContentI == nil {
144-
content := responseBody.String()
145-
ctx.SetContext(CACHE_CONTENT_CONTEXT_KEY, content)
146-
return content, nil
147-
}
135+
// Check if the ResponseBody field exists
136+
if !responseBody.Exists() {
137+
if ctx.GetContext(CACHE_CONTENT_CONTEXT_KEY) != nil {
138+
log.Debugf("[processSSEMessage] unable to extract content from message; cache content is not nil: %s", message)
139+
return content, nil
140+
}
141+
return content, fmt.Errorf("[processSSEMessage] unable to extract content from message; cache content is nil: %s", message)
142+
} else {
143+
tempContentI := ctx.GetContext(CACHE_CONTENT_CONTEXT_KEY)
148144

149-
// Update the content in the cache
150-
appendMsg := responseBody.String()
151-
content := tempContentI.(string) + appendMsg
152-
ctx.SetContext(CACHE_CONTENT_CONTEXT_KEY, content)
153-
return content, nil
145+
// If there is no content in the cache, initialize and set the content
146+
if tempContentI == nil {
147+
content = responseBody.String()
148+
ctx.SetContext(CACHE_CONTENT_CONTEXT_KEY, content)
149+
} else {
150+
// Update the content in the cache
151+
appendMsg := responseBody.String()
152+
content = tempContentI.(string) + appendMsg
153+
ctx.SetContext(CACHE_CONTENT_CONTEXT_KEY, content)
154+
}
155+
}
154156
}
157+
return content, nil
155158
}

plugins/wasm-go/extensions/ai-history/go.sum

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
33
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
44
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
55
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
6-
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f h1:ZIiIBRvIw62gA5MJhuwp1+2wWbqL9IGElQ499rUsYYg=
7-
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240711023527-ba358c48772f/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo=
6+
github.com/higress-group/proxy-wasm-go-sdk v1.0.0 h1:BZRNf4R7jr9hwRivg/E29nkVaKEak5MWjBDhWjuHijU=
87
github.com/higress-group/proxy-wasm-go-sdk v1.0.0/go.mod h1:iiSyFbo+rAtbtGt/bsefv8GU57h9CCLYGJA74/tF5/0=
98
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
109
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
1110
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1211
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
13-
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
14-
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
12+
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
1513
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
1614
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
1715
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=

plugins/wasm-go/extensions/ai-history/main.go

+35-35
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ func onHttpRequestBody(ctx wrapper.HttpContext, config PluginConfig, body []byte
194194
ctx.SetContext(StreamContextKey, struct{}{})
195195
}
196196
identityKey := ctx.GetStringContext(IdentityKey, "")
197+
question := TrimQuote(bodyJson.Get(config.QuestionFrom.RequestBody).String())
198+
if question == "" {
199+
log.Debug("parse question from request body failed")
200+
return types.ActionContinue
201+
}
202+
ctx.SetContext(QuestionContextKey, question)
197203
err := config.redisClient.Get(config.CacheKeyPrefix+identityKey, func(response resp.Value) {
198204
if err := response.Error(); err != nil {
199205
log.Errorf("redis get failed, err:%v", err)
@@ -230,13 +236,6 @@ func onHttpRequestBody(ctx wrapper.HttpContext, config PluginConfig, body []byte
230236
_ = proxywasm.SendHttpResponseWithDetail(200, "OK", [][2]string{{"content-type", "application/json; charset=utf-8"}}, res, -1)
231237
return
232238
}
233-
question := TrimQuote(bodyJson.Get(config.QuestionFrom.RequestBody).String())
234-
if question == "" {
235-
log.Debug("parse question from request body failed")
236-
_ = proxywasm.ResumeHttpRequest()
237-
return
238-
}
239-
ctx.SetContext(QuestionContextKey, question)
240239
fillHistoryCnt := getIntQueryParameter("fill_history_cnt", path, config.FillHistoryCnt) * 2
241240
currJson := bodyJson.Get("messages").String()
242241
var currMessage []ChatHistory
@@ -317,38 +316,39 @@ func getIntQueryParameter(name string, path string, defaultValue int) int {
317316
}
318317

319318
func processSSEMessage(ctx wrapper.HttpContext, config PluginConfig, sseMessage string, log wrapper.Log) string {
320-
subMessages := strings.Split(sseMessage, "\n")
321-
var message string
322-
for _, msg := range subMessages {
323-
if strings.HasPrefix(msg, "data:") {
324-
message = msg
325-
break
319+
content := ""
320+
for _, chunk := range strings.Split(sseMessage, "\n\n") {
321+
subMessages := strings.Split(chunk, "\n")
322+
var message string
323+
for _, msg := range subMessages {
324+
if strings.HasPrefix(msg, "data:") {
325+
message = msg
326+
break
327+
}
326328
}
327-
}
328-
if len(message) < 6 {
329-
log.Errorf("invalid message:%s", message)
330-
return ""
331-
}
332-
// skip the prefix "data:"
333-
bodyJson := message[5:]
334-
if gjson.Get(bodyJson, config.AnswerStreamValueFrom.ResponseBody).Exists() {
335-
tempContentI := ctx.GetContext(AnswerContentContextKey)
336-
if tempContentI == nil {
337-
content := TrimQuote(gjson.Get(bodyJson, config.AnswerStreamValueFrom.ResponseBody).Raw)
338-
ctx.SetContext(AnswerContentContextKey, content)
329+
if len(message) < 6 {
330+
log.Errorf("invalid message:%s", message)
339331
return content
340332
}
341-
append := TrimQuote(gjson.Get(bodyJson, config.AnswerStreamValueFrom.ResponseBody).Raw)
342-
content := tempContentI.(string) + append
343-
ctx.SetContext(AnswerContentContextKey, content)
344-
return content
345-
} else if gjson.Get(bodyJson, "choices.0.delta.content.tool_calls").Exists() {
346-
// TODO: compatible with other providers
347-
ctx.SetContext(ToolCallsContextKey, struct{}{})
348-
return ""
333+
// skip the prefix "data:"
334+
bodyJson := message[5:]
335+
if gjson.Get(bodyJson, config.AnswerStreamValueFrom.ResponseBody).Exists() {
336+
tempContentI := ctx.GetContext(AnswerContentContextKey)
337+
if tempContentI == nil {
338+
content = TrimQuote(gjson.Get(bodyJson, config.AnswerStreamValueFrom.ResponseBody).Raw)
339+
ctx.SetContext(AnswerContentContextKey, content)
340+
} else {
341+
append := TrimQuote(gjson.Get(bodyJson, config.AnswerStreamValueFrom.ResponseBody).Raw)
342+
content = tempContentI.(string) + append
343+
ctx.SetContext(AnswerContentContextKey, content)
344+
}
345+
} else if gjson.Get(bodyJson, "choices.0.delta.content.tool_calls").Exists() {
346+
// TODO: compatible with other providers
347+
ctx.SetContext(ToolCallsContextKey, struct{}{})
348+
}
349+
log.Debugf("unknown message:%s", bodyJson)
349350
}
350-
log.Debugf("unknown message:%s", bodyJson)
351-
return ""
351+
return content
352352
}
353353

354354
func onHttpResponseHeaders(ctx wrapper.HttpContext, config PluginConfig, log wrapper.Log) types.Action {

plugins/wasm-go/extensions/ai-proxy/README.md

+19-13
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,10 @@ Mistral 所对应的 `type` 为 `mistral`。它并无特有的配置字段。
174174

175175
MiniMax所对应的 `type``minimax`。它特有的配置字段如下:
176176

177-
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
178-
| ---------------- | -------- | ------------------------------------------------------------ | ------ | ------------------------------------------------------------ |
179-
| `minimaxGroupId` | string | 当使用`abab6.5-chat`, `abab6.5s-chat`, `abab5.5s-chat`, `abab5.5-chat`四种模型时必填 | - | 当使用`abab6.5-chat`, `abab6.5s-chat`, `abab5.5s-chat`, `abab5.5-chat`四种模型时会使用ChatCompletion Pro,需要设置groupID |
177+
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
178+
| ---------------- | -------- | ------------------------------ | ------ |----------------------------------------------------------------|
179+
| `minimaxApiType` | string | v2 和 pro 中选填一项 | v2 | v2 代表 ChatCompletion v2 API,pro 代表 ChatCompletion Pro API |
180+
| `minimaxGroupId` | string | `minimaxApiType` 为 pro 时必填 | - | `minimaxApiType` 为 pro 时使用 ChatCompletion Pro API,需要设置 groupID |
180181

181182
#### Anthropic Claude
182183

@@ -1000,17 +1001,16 @@ provider:
10001001
apiTokens:
10011002
- "YOUR_MINIMAX_API_TOKEN"
10021003
modelMapping:
1003-
"gpt-3": "abab6.5g-chat"
1004-
"gpt-4": "abab6.5-chat"
1005-
"*": "abab6.5g-chat"
1006-
minimaxGroupId: "YOUR_MINIMAX_GROUP_ID"
1004+
"gpt-3": "abab6.5s-chat"
1005+
"gpt-4": "abab6.5g-chat"
1006+
"*": "abab6.5t-chat"
10071007
```
10081008
10091009
**请求示例**
10101010
10111011
```json
10121012
{
1013-
"model": "gpt-4-turbo",
1013+
"model": "gpt-3",
10141014
"messages": [
10151015
{
10161016
"role": "user",
@@ -1025,27 +1025,33 @@ provider:
10251025

10261026
```json
10271027
{
1028-
"id": "02b2251f8c6c09d68c1743f07c72afd7",
1028+
"id": "03ac4fcfe1c6cc9c6a60f9d12046e2b4",
10291029
"choices": [
10301030
{
10311031
"finish_reason": "stop",
10321032
"index": 0,
10331033
"message": {
1034-
"content": "你好!我是MM智能助理,一款由MiniMax自研的大型语言模型。我可以帮助你解答问题,提供信息,进行对话等。有什么可以帮助你的吗?",
1035-
"role": "assistant"
1034+
"content": "你好,我是一个由MiniMax公司研发的大型语言模型,名为MM智能助理。我可以帮助回答问题、提供信息、进行对话和执行多种语言处理任务。如果你有任何问题或需要帮助,请随时告诉我!",
1035+
"role": "assistant",
1036+
"name": "MM智能助理",
1037+
"audio_content": ""
10361038
}
10371039
}
10381040
],
1039-
"created": 1717760544,
1041+
"created": 1734155471,
10401042
"model": "abab6.5s-chat",
10411043
"object": "chat.completion",
10421044
"usage": {
1043-
"total_tokens": 106
1045+
"total_tokens": 116,
1046+
"total_characters": 0,
1047+
"prompt_tokens": 70,
1048+
"completion_tokens": 46
10441049
},
10451050
"input_sensitive": false,
10461051
"output_sensitive": false,
10471052
"input_sensitive_type": 0,
10481053
"output_sensitive_type": 0,
1054+
"output_sensitive_int": 0,
10491055
"base_resp": {
10501056
"status_code": 0,
10511057
"status_msg": ""

0 commit comments

Comments
 (0)