diff --git a/relay/channel/ollama/adaptor.go b/relay/channel/ollama/adaptor.go
index 8997889..e1225ee 100644
--- a/relay/channel/ollama/adaptor.go
+++ b/relay/channel/ollama/adaptor.go
@@ -52,7 +52,7 @@ func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, request
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (usage *dto.Usage, err *dto.OpenAIErrorWithStatusCode) {
if info.IsStream {
var responseText string
- err, responseText, _ = openai.OpenaiStreamHandler(c, resp, info.RelayMode)
+ err, responseText, _ = openai.OpenaiStreamHandler(c, resp, info)
usage, _ = service.ResponseText2Usage(responseText, info.UpstreamModelName, info.PromptTokens)
} else {
if info.RelayMode == relayconstant.RelayModeEmbeddings {
diff --git a/relay/channel/openai/adaptor.go b/relay/channel/openai/adaptor.go
index a0a5b07..58f5ab5 100644
--- a/relay/channel/openai/adaptor.go
+++ b/relay/channel/openai/adaptor.go
@@ -82,7 +82,7 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom
if info.IsStream {
var responseText string
var toolCount int
- err, responseText, toolCount = OpenaiStreamHandler(c, resp, info.RelayMode)
+ err, responseText, toolCount = OpenaiStreamHandler(c, resp, info)
usage, _ = service.ResponseText2Usage(responseText, info.UpstreamModelName, info.PromptTokens)
usage.CompletionTokens += toolCount * 7
} else {
diff --git a/relay/channel/openai/relay-openai.go b/relay/channel/openai/relay-openai.go
index a41f645..8733cce 100644
--- a/relay/channel/openai/relay-openai.go
+++ b/relay/channel/openai/relay-openai.go
@@ -9,6 +9,7 @@ import (
"net/http"
"one-api/common"
"one-api/dto"
+ relaycommon "one-api/relay/common"
relayconstant "one-api/relay/constant"
"one-api/service"
"strings"
@@ -16,7 +17,7 @@ import (
"time"
)
-func OpenaiStreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*dto.OpenAIErrorWithStatusCode, string, int) {
+func OpenaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, string, int) {
//checkSensitive := constant.ShouldCheckCompletionSensitive()
var responseTextBuilder strings.Builder
toolCount := 0
@@ -57,7 +58,7 @@ func OpenaiStreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*d
}
}
streamResp := "[" + strings.Join(streamItems, ",") + "]"
- switch relayMode {
+ switch info.RelayMode {
case relayconstant.RelayModeChatCompletions:
var streamResponses []dto.ChatCompletionsStreamResponseSimple
err := json.Unmarshal(common.StringToByteSlice(streamResp), &streamResponses)
@@ -126,9 +127,14 @@ func OpenaiStreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*d
common.SafeSendBool(stopChan, true)
}()
service.SetEventStreamHeaders(c)
+ isFirst := true
c.Stream(func(w io.Writer) bool {
select {
case data := <-dataChan:
+ if isFirst {
+ isFirst = false
+ info.FirstResponseTime = time.Now()
+ }
if strings.HasPrefix(data, "data: [DONE]") {
data = data[:12]
}
diff --git a/relay/channel/perplexity/adaptor.go b/relay/channel/perplexity/adaptor.go
index 00d7710..ef87df8 100644
--- a/relay/channel/perplexity/adaptor.go
+++ b/relay/channel/perplexity/adaptor.go
@@ -46,7 +46,7 @@ func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, request
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (usage *dto.Usage, err *dto.OpenAIErrorWithStatusCode) {
if info.IsStream {
var responseText string
- err, responseText, _ = openai.OpenaiStreamHandler(c, resp, info.RelayMode)
+ err, responseText, _ = openai.OpenaiStreamHandler(c, resp, info)
usage, _ = service.ResponseText2Usage(responseText, info.UpstreamModelName, info.PromptTokens)
} else {
err, usage = openai.OpenaiHandler(c, resp, info.PromptTokens, info.UpstreamModelName)
diff --git a/relay/channel/zhipu_4v/adaptor.go b/relay/channel/zhipu_4v/adaptor.go
index fe89ff4..040cf38 100644
--- a/relay/channel/zhipu_4v/adaptor.go
+++ b/relay/channel/zhipu_4v/adaptor.go
@@ -48,7 +48,7 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom
if info.IsStream {
var responseText string
var toolCount int
- err, responseText, toolCount = openai.OpenaiStreamHandler(c, resp, info.RelayMode)
+ err, responseText, toolCount = openai.OpenaiStreamHandler(c, resp, info)
usage, _ = service.ResponseText2Usage(responseText, info.UpstreamModelName, info.PromptTokens)
usage.CompletionTokens += toolCount * 7
} else {
diff --git a/relay/common/relay_info.go b/relay/common/relay_info.go
index f93d36a..2a6872e 100644
--- a/relay/common/relay_info.go
+++ b/relay/common/relay_info.go
@@ -16,6 +16,7 @@ type RelayInfo struct {
Group string
TokenUnlimited bool
StartTime time.Time
+ FirstResponseTime time.Time
ApiType int
IsStream bool
RelayMode int
diff --git a/relay/relay-text.go b/relay/relay-text.go
index 02dcaaa..8673286 100644
--- a/relay/relay-text.go
+++ b/relay/relay-text.go
@@ -332,14 +332,7 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, textRe
logModel = "gpt-4-gizmo-*"
logContent += fmt.Sprintf(",模型 %s", textRequest.Model)
}
- other := make(map[string]interface{})
- other["model_ratio"] = modelRatio
- other["group_ratio"] = groupRatio
- other["completion_ratio"] = completionRatio
- other["model_price"] = modelPrice
- adminInfo := make(map[string]interface{})
- adminInfo["use_channel"] = ctx.GetStringSlice("use_channel")
- other["admin_info"] = adminInfo
+ other := service.GenerateTextOtherInfo(ctx, relayInfo, modelRatio, groupRatio, completionRatio, modelPrice)
model.RecordConsumeLog(ctx, relayInfo.UserId, relayInfo.ChannelId, promptTokens, completionTokens, logModel, tokenName, quota, logContent, relayInfo.TokenId, userQuota, int(useTimeSeconds), relayInfo.IsStream, other)
//if quota != 0 {
diff --git a/service/log.go b/service/log.go
new file mode 100644
index 0000000..506effb
--- /dev/null
+++ b/service/log.go
@@ -0,0 +1,19 @@
+package service
+
+import (
+ "github.com/gin-gonic/gin"
+ relaycommon "one-api/relay/common"
+)
+
+func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, modelRatio, groupRatio, completionRatio, modelPrice float64) map[string]interface{} {
+ other := make(map[string]interface{})
+ other["model_ratio"] = modelRatio
+ other["group_ratio"] = groupRatio
+ other["completion_ratio"] = completionRatio
+ other["model_price"] = modelPrice
+ other["frt"] = float64(relayInfo.FirstResponseTime.UnixMilli() - relayInfo.StartTime.UnixMilli())
+ adminInfo := make(map[string]interface{})
+ adminInfo["use_channel"] = ctx.GetStringSlice("use_channel")
+ other["admin_info"] = adminInfo
+ return other
+}
diff --git a/web/src/components/LogsTable.js b/web/src/components/LogsTable.js
index ba4df1b..4bbacf0 100644
--- a/web/src/components/LogsTable.js
+++ b/web/src/components/LogsTable.js
@@ -29,6 +29,7 @@ import {
stringToColor,
} from '../helpers/render';
import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph';
+import {getLogOther} from "../helpers/other.js";
const { Header } = Layout;
@@ -141,6 +142,33 @@ function renderUseTime(type) {
}
}
+function renderFirstUseTime(type) {
+ let time = parseFloat(type) / 1000.0;
+ time = time.toFixed(1)
+ if (time < 3) {
+ return (
+