feat: endpoint type log
This commit is contained in:
parent
9718568179
commit
b3fc7255ee
@ -8,7 +8,6 @@ const (
|
|||||||
|
|
||||||
ContextKeyOriginalModel ContextKey = "original_model"
|
ContextKeyOriginalModel ContextKey = "original_model"
|
||||||
ContextKeyRequestStartTime ContextKey = "request_start_time"
|
ContextKeyRequestStartTime ContextKey = "request_start_time"
|
||||||
ContextKeyRelayFormat ContextKey = "relay_format"
|
|
||||||
|
|
||||||
/* token related keys */
|
/* token related keys */
|
||||||
ContextKeyTokenUnlimited ContextKey = "token_unlimited_quota"
|
ContextKeyTokenUnlimited ContextKey = "token_unlimited_quota"
|
||||||
|
|||||||
@ -299,9 +299,8 @@ func processChannelError(c *gin.Context, channelError types.ChannelError, err *t
|
|||||||
userGroup := c.GetString("group")
|
userGroup := c.GetString("group")
|
||||||
channelId := c.GetInt("channel_id")
|
channelId := c.GetInt("channel_id")
|
||||||
other := make(map[string]interface{})
|
other := make(map[string]interface{})
|
||||||
relayFormat := common.GetContextKeyString(c, constant.ContextKeyRelayFormat)
|
if c.Request != nil && c.Request.URL != nil {
|
||||||
if relayFormat != "" {
|
other["request_path"] = c.Request.URL.Path
|
||||||
other["relay_format"] = relayFormat
|
|
||||||
}
|
}
|
||||||
other["error_type"] = err.GetErrorType()
|
other["error_type"] = err.GetErrorType()
|
||||||
other["error_code"] = err.GetErrorCode()
|
other["error_code"] = err.GetErrorCode()
|
||||||
|
|||||||
@ -465,10 +465,6 @@ func GenRelayInfo(c *gin.Context, relayFormat types.RelayFormat, request dto.Req
|
|||||||
return nil, errors.New("invalid relay format")
|
return nil, errors.New("invalid relay format")
|
||||||
}
|
}
|
||||||
|
|
||||||
if info != nil {
|
|
||||||
common.SetContextKey(c, constant.ContextKeyRelayFormat, string(info.RelayFormat))
|
|
||||||
}
|
|
||||||
|
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -165,8 +165,8 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
other := make(map[string]interface{})
|
other := make(map[string]interface{})
|
||||||
if info.RelayFormat != "" {
|
if c != nil && c.Request != nil && c.Request.URL != nil {
|
||||||
other["relay_format"] = string(info.RelayFormat)
|
other["request_path"] = c.Request.URL.Path
|
||||||
}
|
}
|
||||||
other["model_price"] = modelPrice
|
other["model_price"] = modelPrice
|
||||||
other["group_ratio"] = groupRatio
|
other["group_ratio"] = groupRatio
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/QuantumNous/new-api/common"
|
"github.com/QuantumNous/new-api/common"
|
||||||
"github.com/QuantumNous/new-api/constant"
|
"github.com/QuantumNous/new-api/constant"
|
||||||
"github.com/QuantumNous/new-api/dto"
|
"github.com/QuantumNous/new-api/dto"
|
||||||
@ -10,12 +12,28 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func appendRequestPath(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, other map[string]interface{}) {
|
||||||
|
if other == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ctx != nil && ctx.Request != nil && ctx.Request.URL != nil {
|
||||||
|
if path := ctx.Request.URL.Path; path != "" {
|
||||||
|
other["request_path"] = path
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if relayInfo != nil && relayInfo.RequestURLPath != "" {
|
||||||
|
path := relayInfo.RequestURLPath
|
||||||
|
if idx := strings.Index(path, "?"); idx != -1 {
|
||||||
|
path = path[:idx]
|
||||||
|
}
|
||||||
|
other["request_path"] = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, modelRatio, groupRatio, completionRatio float64,
|
func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, modelRatio, groupRatio, completionRatio float64,
|
||||||
cacheTokens int, cacheRatio float64, modelPrice float64, userGroupRatio float64) map[string]interface{} {
|
cacheTokens int, cacheRatio float64, modelPrice float64, userGroupRatio float64) map[string]interface{} {
|
||||||
other := make(map[string]interface{})
|
other := make(map[string]interface{})
|
||||||
if relayInfo != nil && relayInfo.RelayFormat != "" {
|
|
||||||
other["relay_format"] = string(relayInfo.RelayFormat)
|
|
||||||
}
|
|
||||||
other["model_ratio"] = modelRatio
|
other["model_ratio"] = modelRatio
|
||||||
other["group_ratio"] = groupRatio
|
other["group_ratio"] = groupRatio
|
||||||
other["completion_ratio"] = completionRatio
|
other["completion_ratio"] = completionRatio
|
||||||
@ -45,6 +63,7 @@ func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, m
|
|||||||
adminInfo["multi_key_index"] = common.GetContextKeyInt(ctx, constant.ContextKeyChannelMultiKeyIndex)
|
adminInfo["multi_key_index"] = common.GetContextKeyInt(ctx, constant.ContextKeyChannelMultiKeyIndex)
|
||||||
}
|
}
|
||||||
other["admin_info"] = adminInfo
|
other["admin_info"] = adminInfo
|
||||||
|
appendRequestPath(ctx, relayInfo, other)
|
||||||
return other
|
return other
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,13 +102,11 @@ func GenerateClaudeOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
|
|||||||
|
|
||||||
func GenerateMjOtherInfo(relayInfo *relaycommon.RelayInfo, priceData types.PerCallPriceData) map[string]interface{} {
|
func GenerateMjOtherInfo(relayInfo *relaycommon.RelayInfo, priceData types.PerCallPriceData) map[string]interface{} {
|
||||||
other := make(map[string]interface{})
|
other := make(map[string]interface{})
|
||||||
if relayInfo != nil && relayInfo.RelayFormat != "" {
|
|
||||||
other["relay_format"] = string(relayInfo.RelayFormat)
|
|
||||||
}
|
|
||||||
other["model_price"] = priceData.ModelPrice
|
other["model_price"] = priceData.ModelPrice
|
||||||
other["group_ratio"] = priceData.GroupRatioInfo.GroupRatio
|
other["group_ratio"] = priceData.GroupRatioInfo.GroupRatio
|
||||||
if priceData.GroupRatioInfo.HasSpecialRatio {
|
if priceData.GroupRatioInfo.HasSpecialRatio {
|
||||||
other["user_group_ratio"] = priceData.GroupRatioInfo.GroupSpecialRatio
|
other["user_group_ratio"] = priceData.GroupRatioInfo.GroupSpecialRatio
|
||||||
}
|
}
|
||||||
|
appendRequestPath(nil, relayInfo, other)
|
||||||
return other
|
return other
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,36 +103,98 @@ function renderType(type, t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const relayFormatMeta = {
|
const endpointColorMap = {
|
||||||
openai: { color: 'blue', label: 'OpenAI' },
|
chat: 'blue',
|
||||||
claude: { color: 'purple', label: 'Claude' },
|
completions: 'blue',
|
||||||
gemini: { color: 'orange', label: 'Gemini' },
|
messages: 'purple',
|
||||||
openai_responses: { color: 'violet', label: 'Responses' },
|
responses: 'violet',
|
||||||
openai_audio: { color: 'teal', label: 'Audio' },
|
images: 'pink',
|
||||||
openai_image: { color: 'pink', label: 'Image' },
|
image: 'pink',
|
||||||
openai_realtime: { color: 'indigo', label: 'Realtime' },
|
embeddings: 'green',
|
||||||
rerank: { color: 'cyan', label: 'Rerank' },
|
embedding: 'green',
|
||||||
embedding: { color: 'green', label: 'Embedding' },
|
audio: 'teal',
|
||||||
task: { color: 'amber', label: 'Task' },
|
speech: 'teal',
|
||||||
mj_proxy: { color: 'red', label: 'Midjourney' },
|
translations: 'teal',
|
||||||
|
transcriptions: 'teal',
|
||||||
|
rerank: 'cyan',
|
||||||
|
moderations: 'red',
|
||||||
|
models: 'orange',
|
||||||
|
engines: 'orange',
|
||||||
|
mj: 'red',
|
||||||
|
submit: 'red',
|
||||||
|
suno: 'amber',
|
||||||
|
realtime: 'indigo',
|
||||||
|
notifications: 'violet',
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderRelayFormat(relayFormat) {
|
function formatPathSegment(segment) {
|
||||||
if (!relayFormat) {
|
if (!segment) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const normalized = segment.replace(/^:/, '').replace(/[_-]/g, ' ');
|
||||||
|
return normalized
|
||||||
|
.split(' ')
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveEndpointMeta(path) {
|
||||||
|
if (!path) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const meta = relayFormatMeta[relayFormat] || {
|
const cleanPath = path.split('?')[0];
|
||||||
color: 'grey',
|
const segments = cleanPath.split('/').filter(Boolean);
|
||||||
label: relayFormat
|
if (segments.length === 0) {
|
||||||
.replace(/_/g, ' ')
|
return null;
|
||||||
.replace(/\b\w/g, (c) => c.toUpperCase()),
|
}
|
||||||
};
|
let startIndex = 0;
|
||||||
|
if (/^v\d/i.test(segments[0])) {
|
||||||
|
startIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
const primary = segments[startIndex] || segments[segments.length - 1];
|
||||||
|
const tailSegments = segments
|
||||||
|
.slice(startIndex + 1)
|
||||||
|
.filter((segment) => segment && !segment.startsWith(':'));
|
||||||
|
const secondary = tailSegments[tailSegments.length - 1];
|
||||||
|
|
||||||
|
const labelParts = [];
|
||||||
|
const formattedPrimary = formatPathSegment(primary);
|
||||||
|
if (formattedPrimary) {
|
||||||
|
labelParts.push(formattedPrimary);
|
||||||
|
}
|
||||||
|
const formattedSecondary = formatPathSegment(secondary);
|
||||||
|
if (formattedSecondary && formattedSecondary !== formattedPrimary) {
|
||||||
|
labelParts.push(formattedSecondary);
|
||||||
|
}
|
||||||
|
const label = labelParts.join(' · ');
|
||||||
|
|
||||||
|
const color =
|
||||||
|
endpointColorMap[primary] ||
|
||||||
|
(secondary ? endpointColorMap[secondary] : undefined) ||
|
||||||
|
'grey';
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: label || formatPathSegment(primary),
|
||||||
|
color,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderEndpointTag(requestPath) {
|
||||||
|
const meta = deriveEndpointMeta(requestPath);
|
||||||
|
if (!meta) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const tag = (
|
||||||
<Tag color={meta.color} type='light' shape='circle' size='small'>
|
<Tag color={meta.color} type='light' shape='circle' size='small'>
|
||||||
{meta.label}
|
{meta.label}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
|
if (requestPath) {
|
||||||
|
return <Tooltip content={requestPath}>{tag}</Tooltip>;
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderIsStream(bool, t) {
|
function renderIsStream(bool, t) {
|
||||||
@ -403,11 +465,12 @@ export const getLogsColumns = ({
|
|||||||
title: t('类型'),
|
title: t('类型'),
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
const relayFormat = getLogOther(record.other)?.relay_format;
|
const other = getLogOther(record.other) || {};
|
||||||
|
const requestPath = other.request_path;
|
||||||
return (
|
return (
|
||||||
<Space size='small' wrap>
|
<Space size='small' wrap>
|
||||||
{renderType(text, t)}
|
{renderType(text, t)}
|
||||||
{renderRelayFormat(relayFormat)}
|
{renderEndpointTag(requestPath)}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user