mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-10-28 08:35:33 +08:00
feat(dashboard): show cache usage alongside total tokens (#7773)
* feat(dashboard): show cache usage alongside total tokens * fix(dashboard): align cache stat descriptions and fix typecheck
This commit is contained in:
1 parent
32e587406c
commit
603a5ceb55
14 files changed
+147
-68
No files matched your search
+19
-10
@@ -386,17 +386,26 @@ func RecordConsumeLog(c *gin.Context, userId int, params RecordConsumeLogParams)
|
||||
logger.LogError(c, common.LogText("failed to record log: %s", err.Error()))
|
||||
}
|
||||
if common.DataExportEnabled {
|
||||
var cacheReadTokens, cacheCreationTokens int
|
||||
if other != nil {
|
||||
cacheReadTokens, _ = other.public["cache_tokens"].(int)
|
||||
// The settlement path already normalizes the cache creation total.
|
||||
// Do not add the 5m/1h breakdown again or infer tokens from prices.
|
||||
cacheCreationTokens, _ = other.public["cache_write_tokens"].(int)
|
||||
}
|
||||
LogQuotaData(QuotaDataLogParams{
|
||||
UserID: userId,
|
||||
Username: username,
|
||||
ModelName: params.ModelName,
|
||||
Quota: params.Quota,
|
||||
CreatedAt: createdAt,
|
||||
TokenUsed: params.PromptTokens + params.CompletionTokens,
|
||||
UseGroup: params.Group,
|
||||
TokenID: params.TokenId,
|
||||
ChannelID: params.ChannelId,
|
||||
NodeName: common.NodeName,
|
||||
UserID: userId,
|
||||
Username: username,
|
||||
ModelName: params.ModelName,
|
||||
Quota: params.Quota,
|
||||
CreatedAt: createdAt,
|
||||
TokenUsed: params.PromptTokens + params.CompletionTokens,
|
||||
CacheReadTokens: int64(cacheReadTokens),
|
||||
CacheCreationTokens: int64(cacheCreationTokens),
|
||||
UseGroup: params.Group,
|
||||
TokenID: params.TokenId,
|
||||
ChannelID: params.ChannelId,
|
||||
NodeName: common.NodeName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+50
-40
@@ -11,31 +11,35 @@ import (
|
||||
|
||||
// QuotaData 柱状图数据
|
||||
type QuotaData struct {
|
||||
Id int `json:"id"`
|
||||
UserID int `json:"user_id" gorm:"index"`
|
||||
Username string `json:"username" gorm:"index:idx_qdt_model_user_name,priority:2;size:64;default:''"`
|
||||
ModelName string `json:"model_name" gorm:"index:idx_qdt_model_user_name,priority:1;size:64;default:''"`
|
||||
CreatedAt int64 `json:"created_at" gorm:"bigint;index:idx_qdt_created_at,priority:2"`
|
||||
UseGroup string `json:"use_group" gorm:"index;size:64;default:''"`
|
||||
TokenID int `json:"token_id" gorm:"index;default:0"`
|
||||
ChannelID int `json:"channel_id" gorm:"index;default:0"`
|
||||
NodeName string `json:"node_name" gorm:"index;size:64;default:''"`
|
||||
TokenUsed int `json:"token_used" gorm:"default:0"`
|
||||
Count int `json:"count" gorm:"default:0"`
|
||||
Quota int `json:"quota" gorm:"default:0"`
|
||||
Id int `json:"id"`
|
||||
UserID int `json:"user_id" gorm:"index"`
|
||||
Username string `json:"username" gorm:"index:idx_qdt_model_user_name,priority:2;size:64;default:''"`
|
||||
ModelName string `json:"model_name" gorm:"index:idx_qdt_model_user_name,priority:1;size:64;default:''"`
|
||||
CreatedAt int64 `json:"created_at" gorm:"bigint;index:idx_qdt_created_at,priority:2"`
|
||||
UseGroup string `json:"use_group" gorm:"index;size:64;default:''"`
|
||||
TokenID int `json:"token_id" gorm:"index;default:0"`
|
||||
ChannelID int `json:"channel_id" gorm:"index;default:0"`
|
||||
NodeName string `json:"node_name" gorm:"index;size:64;default:''"`
|
||||
TokenUsed int `json:"token_used" gorm:"default:0"`
|
||||
Count int `json:"count" gorm:"default:0"`
|
||||
Quota int `json:"quota" gorm:"default:0"`
|
||||
CacheReadTokens int64 `json:"cache_read_tokens" gorm:"default:0"`
|
||||
CacheCreationTokens int64 `json:"cache_creation_tokens" gorm:"default:0"`
|
||||
}
|
||||
|
||||
type QuotaDataLogParams struct {
|
||||
UserID int
|
||||
Username string
|
||||
ModelName string
|
||||
Quota int
|
||||
CreatedAt int64
|
||||
TokenUsed int
|
||||
UseGroup string
|
||||
TokenID int
|
||||
ChannelID int
|
||||
NodeName string
|
||||
UserID int
|
||||
Username string
|
||||
ModelName string
|
||||
Quota int
|
||||
CreatedAt int64
|
||||
TokenUsed int
|
||||
CacheReadTokens int64
|
||||
CacheCreationTokens int64
|
||||
UseGroup string
|
||||
TokenID int
|
||||
ChannelID int
|
||||
NodeName string
|
||||
}
|
||||
|
||||
func UpdateQuotaData() {
|
||||
@@ -70,6 +74,8 @@ func logQuotaDataCache(quotaData *QuotaData) {
|
||||
cachedQuotaData.Count += count
|
||||
cachedQuotaData.Quota += quota
|
||||
cachedQuotaData.TokenUsed += tokenUsed
|
||||
cachedQuotaData.CacheReadTokens += quotaData.CacheReadTokens
|
||||
cachedQuotaData.CacheCreationTokens += quotaData.CacheCreationTokens
|
||||
quotaData = cachedQuotaData
|
||||
}
|
||||
CacheQuotaData[key] = quotaData
|
||||
@@ -79,17 +85,19 @@ func LogQuotaData(params QuotaDataLogParams) {
|
||||
// 只精确到小时
|
||||
createdAt := params.CreatedAt - (params.CreatedAt % 3600)
|
||||
quotaData := &QuotaData{
|
||||
UserID: params.UserID,
|
||||
Username: params.Username,
|
||||
ModelName: params.ModelName,
|
||||
CreatedAt: createdAt,
|
||||
UseGroup: params.UseGroup,
|
||||
TokenID: params.TokenID,
|
||||
ChannelID: params.ChannelID,
|
||||
NodeName: params.NodeName,
|
||||
Count: 1,
|
||||
Quota: params.Quota,
|
||||
TokenUsed: params.TokenUsed,
|
||||
UserID: params.UserID,
|
||||
Username: params.Username,
|
||||
ModelName: params.ModelName,
|
||||
CreatedAt: createdAt,
|
||||
UseGroup: params.UseGroup,
|
||||
TokenID: params.TokenID,
|
||||
ChannelID: params.ChannelID,
|
||||
NodeName: params.NodeName,
|
||||
Count: 1,
|
||||
Quota: params.Quota,
|
||||
TokenUsed: params.TokenUsed,
|
||||
CacheReadTokens: max(0, params.CacheReadTokens),
|
||||
CacheCreationTokens: max(0, params.CacheCreationTokens),
|
||||
}
|
||||
|
||||
CacheQuotaDataLock.Lock()
|
||||
@@ -129,9 +137,11 @@ func increaseQuotaData(quotaData *QuotaData) {
|
||||
Where("user_id = ? and username = ? and model_name = ? and created_at = ? and use_group = ? and token_id = ? and channel_id = ? and node_name = ?",
|
||||
quotaData.UserID, quotaData.Username, quotaData.ModelName, quotaData.CreatedAt, quotaData.UseGroup, quotaData.TokenID, quotaData.ChannelID, quotaData.NodeName).
|
||||
Updates(map[string]any{
|
||||
"count": gorm.Expr("count + ?", quotaData.Count),
|
||||
"quota": gorm.Expr("quota + ?", quotaData.Quota),
|
||||
"token_used": gorm.Expr("token_used + ?", quotaData.TokenUsed),
|
||||
"count": gorm.Expr("count + ?", quotaData.Count),
|
||||
"quota": gorm.Expr("quota + ?", quotaData.Quota),
|
||||
"token_used": gorm.Expr("token_used + ?", quotaData.TokenUsed),
|
||||
"cache_read_tokens": gorm.Expr("cache_read_tokens + ?", quotaData.CacheReadTokens),
|
||||
"cache_creation_tokens": gorm.Expr("cache_creation_tokens + ?", quotaData.CacheCreationTokens),
|
||||
}).Error
|
||||
if err != nil {
|
||||
common.SysLog(common.LogText("increaseQuotaData error: %s", err))
|
||||
@@ -142,7 +152,7 @@ func GetQuotaDataByUsername(username string, startTime int64, endTime int64) (qu
|
||||
var quotaDatas []*QuotaData
|
||||
// 从quota_data表中查询数据
|
||||
err = DB.Table("quota_data").
|
||||
Select("user_id, username, model_name, created_at, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used").
|
||||
Select("user_id, username, model_name, created_at, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used, sum(cache_read_tokens) as cache_read_tokens, sum(cache_creation_tokens) as cache_creation_tokens").
|
||||
Where("username = ? and created_at >= ? and created_at <= ?", username, startTime, endTime).
|
||||
Group("user_id, username, model_name, created_at").
|
||||
Find("aDatas).Error
|
||||
@@ -153,7 +163,7 @@ func GetQuotaDataByUserId(userId int, startTime int64, endTime int64) (quotaData
|
||||
var quotaDatas []*QuotaData
|
||||
// 从quota_data表中查询数据
|
||||
err = DB.Table("quota_data").
|
||||
Select("user_id, username, model_name, created_at, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used").
|
||||
Select("user_id, username, model_name, created_at, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used, sum(cache_read_tokens) as cache_read_tokens, sum(cache_creation_tokens) as cache_creation_tokens").
|
||||
Where("user_id = ? and created_at >= ? and created_at <= ?", userId, startTime, endTime).
|
||||
Group("user_id, username, model_name, created_at").
|
||||
Find("aDatas).Error
|
||||
@@ -163,7 +173,7 @@ func GetQuotaDataByUserId(userId int, startTime int64, endTime int64) (quotaData
|
||||
func GetQuotaDataGroupByUser(startTime int64, endTime int64) (quotaData []*QuotaData, err error) {
|
||||
var quotaDatas []*QuotaData
|
||||
err = DB.Table("quota_data").
|
||||
Select("username, created_at, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used").
|
||||
Select("username, created_at, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used, sum(cache_read_tokens) as cache_read_tokens, sum(cache_creation_tokens) as cache_creation_tokens").
|
||||
Where("created_at >= ? and created_at <= ?", startTime, endTime).
|
||||
Group("username, created_at").
|
||||
Find("aDatas).Error
|
||||
@@ -178,6 +188,6 @@ func GetAllQuotaDates(startTime int64, endTime int64, username string) (quotaDat
|
||||
// 从quota_data表中查询数据
|
||||
// only select model_name, sum(count) as count, sum(quota) as quota, model_name, created_at from quota_data group by model_name, created_at;
|
||||
//err = DB.Table("quota_data").Where("created_at >= ? and created_at <= ?", startTime, endTime).Find("aDatas).Error
|
||||
err = DB.Table("quota_data").Select("model_name, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used, created_at").Where("created_at >= ? and created_at <= ?", startTime, endTime).Group("model_name, created_at").Find("aDatas).Error
|
||||
err = DB.Table("quota_data").Select("model_name, sum(count) as count, sum(quota) as quota, sum(token_used) as token_used, sum(cache_read_tokens) as cache_read_tokens, sum(cache_creation_tokens) as cache_creation_tokens, created_at").Where("created_at >= ? and created_at <= ?", startTime, endTime).Group("model_name, created_at").Find("aDatas).Error
|
||||
return quotaDatas, err
|
||||
}
|
||||
@@ -43,7 +43,7 @@ interface LogStatCardsProps {
|
||||
onDataUpdate?: (data: QuotaDataItem[], loading: boolean) => void
|
||||
}
|
||||
|
||||
const MAX_INLINE_STAT_CHARS = 9
|
||||
const MAX_INLINE_STAT_CHARS = 7
|
||||
|
||||
function formatStatNumber(value: number, locale: Intl.LocalesArgument) {
|
||||
const fullValue = formatNumber(value, locale)
|
||||
@@ -63,11 +63,9 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
const statCardsConfig = useModelStatCardsConfig()
|
||||
const user = useAuthStore((state) => state.auth.user)
|
||||
const isAdmin = !!(user?.role && user.role >= 10)
|
||||
const [stats, setStats] = useState<{
|
||||
totalQuota: number
|
||||
totalCount: number
|
||||
totalTokens: number
|
||||
} | null>(null)
|
||||
const [stats, setStats] = useState<ReturnType<
|
||||
typeof calculateDashboardStats
|
||||
> | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState(false)
|
||||
|
||||
@@ -119,6 +117,8 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
rpm: stats?.totalCount ?? 0,
|
||||
quota: stats?.totalQuota ?? 0,
|
||||
tpm: stats?.totalTokens ?? 0,
|
||||
cacheRead: stats?.totalCacheReadTokens ?? 0,
|
||||
cacheCreation: stats?.totalCacheCreationTokens ?? 0,
|
||||
}
|
||||
|
||||
const items = statCardsConfig.map((config) => {
|
||||
@@ -133,6 +133,7 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
: formatStatNumber(rawValue, locale)
|
||||
|
||||
return {
|
||||
key: config.key,
|
||||
title: config.title,
|
||||
value: formatted.displayValue,
|
||||
fullValue: formatted.fullValue,
|
||||
@@ -144,7 +145,7 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
|
||||
return (
|
||||
<div className='overflow-hidden rounded-lg border'>
|
||||
<div className='divide-border/60 grid min-w-0 grid-cols-2 divide-x sm:grid-cols-3 lg:grid-cols-5'>
|
||||
<div className='divide-border/60 grid min-w-0 grid-cols-2 divide-x sm:grid-cols-3 lg:grid-cols-7'>
|
||||
{items.map((it, idx) => {
|
||||
const Icon = it.icon
|
||||
let valueContent
|
||||
@@ -184,9 +185,12 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
key={it.title}
|
||||
key={it.key}
|
||||
role='group'
|
||||
aria-label={it.title}
|
||||
aria-busy={loading}
|
||||
className={cn(
|
||||
'min-w-0 px-2.5 py-1.5 sm:px-5 sm:py-4',
|
||||
'min-w-0 px-2.5 py-1.5 sm:px-3 sm:py-4 xl:px-4',
|
||||
idx === items.length - 1 &&
|
||||
items.length % 2 !== 0 &&
|
||||
'col-span-2 sm:col-span-1'
|
||||
@@ -200,7 +204,10 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
>
|
||||
<Icon />
|
||||
</IconBadge>
|
||||
<div className='text-muted-foreground truncate text-[11px] leading-4 font-medium tracking-wide uppercase sm:text-xs sm:tracking-wider'>
|
||||
<div
|
||||
className='text-muted-foreground truncate text-[11px] leading-4 font-medium tracking-wide uppercase sm:text-xs sm:tracking-wider'
|
||||
title={it.title}
|
||||
>
|
||||
{it.title}
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,6 +217,11 @@ export function LogStatCards(props: LogStatCardsProps) {
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{/*<p className='text-muted-foreground border-t px-3 py-2 text-xs'>*/}
|
||||
{/* {t(*/}
|
||||
{/* 'Cache usage is recorded only after the upgrade; historical data is not backfilled.'*/}
|
||||
{/* )}*/}
|
||||
{/*</p>*/}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
Hash,
|
||||
Coins,
|
||||
Layers,
|
||||
Download,
|
||||
Upload,
|
||||
Gauge,
|
||||
Zap,
|
||||
Flame,
|
||||
@@ -69,6 +71,22 @@ export function useModelStatCardsConfig(): StatCardConfig[] {
|
||||
iconTone: 'chart-4',
|
||||
getValue: (stat) => stat?.tpm ?? 0,
|
||||
},
|
||||
{
|
||||
key: 'cacheRead',
|
||||
title: t('Cache Read'),
|
||||
description: t('Statistical tokens'),
|
||||
icon: Download,
|
||||
iconTone: 'chart-3',
|
||||
getValue: (stat) => stat?.cacheRead ?? 0,
|
||||
},
|
||||
{
|
||||
key: 'cacheCreation',
|
||||
title: t('Cache Write'),
|
||||
description: t('Statistical tokens'),
|
||||
icon: Upload,
|
||||
iconTone: 'chart-5',
|
||||
getValue: (stat) => stat?.cacheCreation ?? 0,
|
||||
},
|
||||
{
|
||||
key: 'avgRpm',
|
||||
title: t('Average RPM'),
|
||||
|
||||
@@ -64,6 +64,8 @@ const LOG_STAT_CARD_FALLBACK_KEYS = [
|
||||
'count',
|
||||
'quota',
|
||||
'tokens',
|
||||
'cache-read',
|
||||
'cache-creation',
|
||||
'average-rpm',
|
||||
'average-tpm',
|
||||
] as const
|
||||
@@ -116,12 +118,12 @@ const LazyFlowCharts = lazy(() =>
|
||||
function LogStatCardsFallback() {
|
||||
return (
|
||||
<div className='overflow-hidden rounded-lg border'>
|
||||
<div className='divide-border/60 grid grid-cols-2 divide-x sm:grid-cols-3 lg:grid-cols-5'>
|
||||
<div className='divide-border/60 grid min-w-0 grid-cols-2 divide-x sm:grid-cols-3 lg:grid-cols-7'>
|
||||
{LOG_STAT_CARD_FALLBACK_KEYS.map((key, index) => (
|
||||
<div
|
||||
key={key}
|
||||
className={cn(
|
||||
'px-2.5 py-1.5 sm:px-5 sm:py-4',
|
||||
'min-w-0 px-2.5 py-1.5 sm:px-3 sm:py-4 xl:px-4',
|
||||
index === LOG_STAT_CARD_FALLBACK_KEYS.length - 1 &&
|
||||
'col-span-2 sm:col-span-1'
|
||||
)}
|
||||
@@ -135,6 +137,9 @@ function LogStatCardsFallback() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className='border-t px-3 py-2'>
|
||||
<Skeleton className='h-4 w-full max-w-md' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -37,11 +37,27 @@ export function safeDivide(
|
||||
*/
|
||||
export function calculateDashboardStats(data: QuotaDataItem[]) {
|
||||
return data.reduce(
|
||||
(acc, item) => ({
|
||||
totalQuota: acc.totalQuota + (Number(item.quota) || 0),
|
||||
totalCount: acc.totalCount + (Number(item.count) || 0),
|
||||
totalTokens: acc.totalTokens + (Number(item.token_used) || 0),
|
||||
}),
|
||||
{ totalQuota: 0, totalCount: 0, totalTokens: 0 }
|
||||
(acc, item) => {
|
||||
const cacheRead = item.cache_read_tokens ?? 0
|
||||
const cacheCreation = item.cache_creation_tokens ?? 0
|
||||
return {
|
||||
totalQuota: acc.totalQuota + (Number(item.quota) || 0),
|
||||
totalCount: acc.totalCount + (Number(item.count) || 0),
|
||||
totalTokens: acc.totalTokens + (Number(item.token_used) || 0),
|
||||
totalCacheReadTokens:
|
||||
acc.totalCacheReadTokens +
|
||||
(Number.isFinite(cacheRead) ? Math.max(0, cacheRead) : 0),
|
||||
totalCacheCreationTokens:
|
||||
acc.totalCacheCreationTokens +
|
||||
(Number.isFinite(cacheCreation) ? Math.max(0, cacheCreation) : 0),
|
||||
}
|
||||
},
|
||||
{
|
||||
totalQuota: 0,
|
||||
totalCount: 0,
|
||||
totalTokens: 0,
|
||||
totalCacheReadTokens: 0,
|
||||
totalCacheCreationTokens: 0,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -28,6 +28,8 @@ export interface QuotaDataItem {
|
||||
username?: string
|
||||
model_name?: string
|
||||
created_at: number
|
||||
cache_read_tokens?: number
|
||||
cache_creation_tokens?: number
|
||||
token_used?: number
|
||||
count?: number
|
||||
quota?: number
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "Model assignments",
|
||||
"model billing support": "model billing support",
|
||||
"Model Call Analytics": "Model Call Analytics",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "Cache usage is recorded only after the upgrade; historical data is not backfilled.",
|
||||
"Model context usage": "Model context usage",
|
||||
"Model deleted": "Model deleted",
|
||||
"Model deleted successfully": "Model deleted successfully",
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "Attribution des modèles",
|
||||
"model billing support": "prise en charge de la facturation des modèles",
|
||||
"Model Call Analytics": "Analyse des appels de modèles",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "L’utilisation du cache est enregistrée uniquement après la mise à niveau ; les données historiques ne sont pas complétées.",
|
||||
"Model context usage": "Utilisation du contexte du modèle",
|
||||
"Model deleted": "Modèle supprimé",
|
||||
"Model deleted successfully": "Modèle supprimé avec succès",
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "モデルの割り当て",
|
||||
"model billing support": "モデル課金対応",
|
||||
"Model Call Analytics": "モデル呼び出し分析",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "キャッシュ使用量はアップグレード後から記録され、過去のデータは補完されません。",
|
||||
"Model context usage": "モデルのコンテキスト使用量",
|
||||
"Model deleted": "モデルが削除されました",
|
||||
"Model deleted successfully": "モデルが正常に削除されました",
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "Привязка моделей",
|
||||
"model billing support": "поддержка биллинга моделей",
|
||||
"Model Call Analytics": "Аналитика вызовов моделей",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "Использование кэша учитывается только после обновления; исторические данные не заполняются.",
|
||||
"Model context usage": "Использование контекста модели",
|
||||
"Model deleted": "Модель удалена",
|
||||
"Model deleted successfully": "Модель успешно удалена",
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "Gán mô hình",
|
||||
"model billing support": "hỗ trợ tính phí mô hình",
|
||||
"Model Call Analytics": "Phân tích lượt gọi mô hình",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "Mức sử dụng bộ nhớ đệm chỉ được ghi nhận sau khi nâng cấp; dữ liệu lịch sử không được bổ sung.",
|
||||
"Model context usage": "Sử dụng ngữ cảnh mô hình",
|
||||
"Model deleted": "Đã xóa mô hình",
|
||||
"Model deleted successfully": "Model đã được xóa thành công",
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "模型歸屬",
|
||||
"model billing support": "模型收費支援",
|
||||
"Model Call Analytics": "模型呼叫分析",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "快取用量僅從升級後開始記錄,歷史資料不回填。",
|
||||
"Model context usage": "模型上下文用量",
|
||||
"Model deleted": "模型已刪除",
|
||||
"Model deleted successfully": "模型刪除成功",
|
||||
|
||||
@@ -3719,6 +3719,7 @@
|
||||
"Model assignments": "模型归属",
|
||||
"model billing support": "模型计费支持",
|
||||
"Model Call Analytics": "模型调用分析",
|
||||
"Cache usage is recorded only after the upgrade; historical data is not backfilled.": "缓存用量仅从升级后开始记录,历史数据不回填。",
|
||||
"Model context usage": "模型上下文用量",
|
||||
"Model deleted": "模型已删除",
|
||||
"Model deleted successfully": "模型删除成功",
|
||||
|
||||
Reference in new issue
Block a user