diff --git a/Dockerfile b/Dockerfile index b12d35c33a57..df8de82f9f81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,10 @@ +# Build parallelism: reserve RESERVE_CPU_CORES for the host (default 1). Example: +# docker build --build-arg RESERVE_CPU_CORES=2 . +# Default/classic frontend stages may run in parallel; each uses roughly +# floor((nproc - RESERVE) / 2) via GOMAXPROCS so the pair is less likely to +# saturate all CPUs. The final Go compile stage uses (nproc - RESERVE). FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder +ARG RESERVE_CPU_CORES=1 WORKDIR /build COPY web/default/package.json . @@ -6,9 +12,16 @@ COPY web/default/bun.lock . RUN bun install COPY ./web/default . COPY ./VERSION . -RUN DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat VERSION) bun run build +RUN RESERVE="${RESERVE_CPU_CORES:-1}"; \ + TOTAL=$(nproc); \ + if [ "$TOTAL" -gt "$RESERVE" ]; then AVAIL=$((TOTAL - RESERVE)); else AVAIL=1; fi; \ + USE=$((AVAIL / 2)); \ + if [ "$USE" -lt 1 ]; then USE=1; fi; \ + export GOMAXPROCS="$USE"; \ + DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat VERSION) bun run build FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder-classic +ARG RESERVE_CPU_CORES=1 WORKDIR /build COPY web/classic/package.json . @@ -16,11 +29,18 @@ COPY web/classic/bun.lock . RUN bun install COPY ./web/classic . COPY ./VERSION . -RUN VITE_REACT_APP_VERSION=$(cat VERSION) bun run build +RUN RESERVE="${RESERVE_CPU_CORES:-1}"; \ + TOTAL=$(nproc); \ + if [ "$TOTAL" -gt "$RESERVE" ]; then AVAIL=$((TOTAL - RESERVE)); else AVAIL=1; fi; \ + USE=$((AVAIL / 2)); \ + if [ "$USE" -lt 1 ]; then USE=1; fi; \ + export GOMAXPROCS="$USE"; \ + VITE_REACT_APP_VERSION=$(cat VERSION) bun run build FROM golang:1.26.1-alpine@sha256:2389ebfa5b7f43eeafbd6be0c3700cc46690ef842ad962f6c5bd6be49ed82039 AS builder2 ENV GO111MODULE=on CGO_ENABLED=0 +ARG RESERVE_CPU_CORES=1 ARG TARGETOS ARG TARGETARCH ENV GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-amd64} @@ -34,7 +54,11 @@ RUN go mod download COPY . . COPY --from=builder /build/dist ./web/default/dist COPY --from=builder-classic /build/dist ./web/classic/dist -RUN go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api +RUN RESERVE="${RESERVE_CPU_CORES:-1}"; \ + TOTAL=$(nproc); \ + if [ "$TOTAL" -gt "$RESERVE" ]; then USE=$((TOTAL - RESERVE)); else USE=1; fi; \ + export GOMAXPROCS="$USE"; \ + go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api FROM debian:bookworm-slim@sha256:f06537653ac770703bc45b4b113475bd402f451e85223f0f2837acbf89ab020a diff --git a/Dockerfile.dev b/Dockerfile.dev index 6601e3dd7ce5..67597ff7657e 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,9 +1,12 @@ # Backend-only build for frontend development # Skips frontend build, uses a placeholder for //go:embed web/dist +# +# Reserve RESERVE_CPU_CORES CPUs for the host during compile (default 1). FROM golang:1.26.1-alpine AS builder ENV GO111MODULE=on CGO_ENABLED=0 +ARG RESERVE_CPU_CORES=1 ARG TARGETOS ARG TARGETARCH ENV GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-amd64} @@ -20,7 +23,11 @@ RUN mkdir -p web/default/dist web/classic/dist && \ echo 'devuse frontend dev server' > web/default/dist/index.html && \ echo 'devuse frontend dev server' > web/classic/dist/index.html -RUN go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api +RUN RESERVE="${RESERVE_CPU_CORES:-1}"; \ + TOTAL=$(nproc); \ + if [ "$TOTAL" -gt "$RESERVE" ]; then USE=$((TOTAL - RESERVE)); else USE=1; fi; \ + export GOMAXPROCS="$USE"; \ + go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api FROM debian:bookworm-slim diff --git a/VERSION b/VERSION index e69de29bb2d1..8a9ecc2ea99d 100644 --- a/VERSION +++ b/VERSION @@ -0,0 +1 @@ +0.0.1 \ No newline at end of file diff --git a/common/constants.go b/common/constants.go index c4d2511ef357..acc875d24aae 100644 --- a/common/constants.go +++ b/common/constants.go @@ -46,7 +46,7 @@ var DrawingEnabled = true var TaskEnabled = true var DataExportEnabled = true var DataExportInterval = 5 // unit: minute -var DataExportDefaultTime = "hour" // unit: minute +var DataExportDefaultTime = "day" var DefaultCollapseSidebar = false // default value of collapse sidebar // Any options with "Secret", "Token" in its key won't be return by GetOptions diff --git a/controller/channel_consumption.go b/controller/channel_consumption.go new file mode 100644 index 000000000000..9d89cddaa2a5 --- /dev/null +++ b/controller/channel_consumption.go @@ -0,0 +1,109 @@ +package controller + +import ( + "errors" + "net/http" + "strconv" + "strings" + "time" + + "github.com/QuantumNous/new-api/common" + "github.com/QuantumNous/new-api/model" + + "github.com/gin-gonic/gin" +) + +func parseChannelConsumptionTimeRange(c *gin.Context) (startTimestamp, endTimestamp int64, err error) { + startTimestamp, _ = strconv.ParseInt(c.Query("start_timestamp"), 10, 64) + endTimestamp, _ = strconv.ParseInt(c.Query("end_timestamp"), 10, 64) + if startTimestamp == 0 && endTimestamp == 0 { + now := time.Now() + loc := now.Location() + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, loc) + startTimestamp = monthStart.Unix() + endTimestamp = now.Unix() + return startTimestamp, endTimestamp, nil + } + if startTimestamp == 0 || endTimestamp == 0 { + return 0, 0, errors.New("start_timestamp and end_timestamp are required") + } + if endTimestamp < startTimestamp { + return 0, 0, errors.New("end_timestamp must be greater than or equal to start_timestamp") + } + return startTimestamp, endTimestamp, nil +} + +// GetChannelConsumption returns consume quota aggregated for a channel in [start_timestamp, end_timestamp]. +// Optional filters: user_id or username (for per-user consumption on this channel). +func GetChannelConsumption(c *gin.Context) { + channelId, err := strconv.Atoi(c.Param("id")) + if err != nil || channelId <= 0 { + common.ApiError(c, errors.New("invalid channel id")) + return + } + + channel, err := model.GetChannelById(channelId, false) + if err != nil { + common.ApiError(c, err) + return + } + + startTimestamp, endTimestamp, err := parseChannelConsumptionTimeRange(c) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + + userId, _ := strconv.Atoi(c.Query("user_id")) + username := strings.TrimSpace(c.Query("username")) + if userId > 0 { + if _, err := model.GetUserById(userId, false); err != nil { + common.ApiError(c, errors.New("user not found")) + return + } + username = "" + } else if username != "" { + if _, err := model.GetUserByUsername(username); err != nil { + common.ApiError(c, errors.New("user not found")) + return + } + } + + stat, err := model.SumChannelConsumption(channelId, userId, username, startTimestamp, endTimestamp) + if err != nil { + common.ApiError(c, err) + return + } + + resp := gin.H{ + "channel_id": channel.Id, + "channel_name": channel.Name, + "start_timestamp": startTimestamp, + "end_timestamp": endTimestamp, + "quota": stat.Quota, + "request_count": stat.RequestCount, + "prompt_tokens": stat.PromptTokens, + "completion_tokens": stat.CompletionTokens, + "lifetime_used_quota": channel.UsedQuota, + } + if userId > 0 { + resp["user_id"] = userId + if user, uerr := model.GetUserById(userId, false); uerr == nil && user != nil { + resp["username"] = user.Username + } + } else if username != "" { + resp["username"] = username + if user, uerr := model.GetUserByUsername(username); uerr == nil && user != nil { + resp["user_id"] = user.Id + } + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + "data": resp, + }) +} diff --git a/controller/log.go b/controller/log.go index cf3825f16d5c..b38659cd8eec 100644 --- a/controller/log.go +++ b/controller/log.go @@ -1,11 +1,19 @@ package controller import ( + "archive/zip" + "encoding/csv" + "errors" + "fmt" "net/http" + "net/url" "strconv" + "strings" + "time" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/model" + "github.com/QuantumNous/new-api/setting/operation_setting" "github.com/gin-gonic/gin" ) @@ -169,3 +177,341 @@ func DeleteHistoryLogs(c *gin.Context) { }) return } + +func parseAdminUserExportMonthQuery(c *gin.Context) (userId int, year int, month int, loc *time.Location, err error) { + userId, err = strconv.Atoi(c.Query("user_id")) + if err != nil || userId <= 0 { + return 0, 0, 0, nil, errors.New("用户ID无效") + } + year, err = strconv.Atoi(c.Query("year")) + if err != nil { + return 0, 0, 0, nil, errors.New("年份无效") + } + month, err = strconv.Atoi(c.Query("month")) + if err != nil { + return 0, 0, 0, nil, errors.New("月份无效") + } + loc = time.Local + if tz := strings.TrimSpace(c.Query("timezone")); tz != "" { + loc, err = time.LoadLocation(tz) + if err != nil { + return 0, 0, 0, nil, errors.New("时区无效") + } + } + return userId, year, month, loc, nil +} + +func adminUserExportUsername(userId int) string { + user, userErr := model.GetUserById(userId, false) + if userErr == nil && user != nil { + return user.Username + } + username, _ := model.GetUsernameById(userId, true) + return username +} + +func adminUserExportSafeFilenamePart(value string) string { + value = strings.TrimSpace(value) + if value == "" { + return "unknown" + } + value = strings.Map(func(r rune) rune { + if r < 32 || r == 127 || strings.ContainsRune(`/\:*?"<>|`, r) { + return '_' + } + return r + }, value) + if value == "" { + return "unknown" + } + return value +} + +func adminUserExportASCIIHeaderFilename(value string) string { + value = strings.Map(func(r rune) rune { + if r < 32 || r == 127 || r > 126 || strings.ContainsRune(`/\:*?"<>|`, r) { + return '_' + } + return r + }, value) + if strings.Trim(value, "_") == "" { + return "export.csv" + } + return value +} + +func adminUserExportFilename(prefix string, userId int, username string, year, month int) string { + return fmt.Sprintf("%s-user-%d-%s-%04d-%02d.csv", prefix, userId, adminUserExportSafeFilenamePart(username), year, month) +} + +func adminUserExportSetCSVHeaders(c *gin.Context, filename string) { + adminUserExportSetDownloadHeaders(c, "text/csv; charset=utf-8", filename) +} + +func adminUserExportSetZipHeaders(c *gin.Context, filename string) { + adminUserExportSetDownloadHeaders(c, "application/zip", filename) +} + +func adminUserExportSetDownloadHeaders(c *gin.Context, contentType string, filename string) { + asciiFilename := adminUserExportASCIIHeaderFilename(filename) + c.Header("Content-Type", contentType) + c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"; filename*=UTF-8''%s`, asciiFilename, url.PathEscape(filename))) +} + +func adminUserExportAmountUSD(quota int64) float64 { + if common.QuotaPerUnit <= 0 { + return 0 + } + return float64(quota) / common.QuotaPerUnit +} + +func adminUserExportDisplayAmount(quota int64) float64 { + amount := adminUserExportAmountUSD(quota) + switch operation_setting.GetQuotaDisplayType() { + case operation_setting.QuotaDisplayTypeCNY: + return amount * operation_setting.USDExchangeRate + case operation_setting.QuotaDisplayTypeCustom: + return amount * operation_setting.GetUsdToCurrencyRate(operation_setting.USDExchangeRate) + case operation_setting.QuotaDisplayTypeTokens: + return float64(quota) + default: + return amount + } +} + +func adminUserExportFormatAmount(amount float64) string { + return strconv.FormatFloat(amount, 'f', 6, 64) +} + +func adminUserExportBoolText(v bool) string { + if v { + return "是" + } + return "否" +} + +func adminUserExportDisplayCurrencyName() string { + switch operation_setting.GetQuotaDisplayType() { + case operation_setting.QuotaDisplayTypeCNY: + return "人民币(CNY)" + case operation_setting.QuotaDisplayTypeCustom: + symbol := operation_setting.GetCurrencySymbol() + if symbol == "" { + symbol = "自定义货币" + } + return "自定义货币(" + symbol + ")" + case operation_setting.QuotaDisplayTypeTokens: + return "额度单位/Token" + default: + return "美元(USD)" + } +} + +func adminUserExportLogTypeName(logType int) string { + switch logType { + case model.LogTypeTopup: + return "充值" + case model.LogTypeConsume: + return "消费" + case model.LogTypeManage: + return "管理" + case model.LogTypeSystem: + return "系统" + case model.LogTypeError: + return "错误" + case model.LogTypeRefund: + return "退款" + default: + return "未知" + } +} + +func writeAdminUserMonthlyBillCSV(w *csv.Writer, userId int, username string, year int, month int, loc *time.Location, startSec int64, endSec int64, typeRows []model.AdminUserMonthLogTypeAgg, modelRows []model.AdminUserMonthModelAgg) { + displayCurrencyName := adminUserExportDisplayCurrencyName() + _ = w.Write([]string{"分区", "用户ID", "用户名", "年份", "月份", "时区", "开始时间(Unix秒)", "结束时间(Unix秒)", "当前展示金额类型"}) + _ = w.Write([]string{"导出信息", strconv.Itoa(userId), username, strconv.Itoa(year), strconv.Itoa(month), loc.String(), strconv.FormatInt(startSec, 10), strconv.FormatInt(endSec, 10), displayCurrencyName}) + _ = w.Write([]string{}) + _ = w.Write([]string{"按日志类型汇总", "日志类型编码", "日志类型", "记录数", "额度合计", "折算金额(USD)", "当前展示金额"}) + for _, row := range typeRows { + _ = w.Write([]string{ + "按日志类型汇总", + strconv.Itoa(row.Type), + adminUserExportLogTypeName(row.Type), + strconv.FormatInt(row.Cnt, 10), + strconv.FormatInt(row.QuotaSum, 10), + adminUserExportFormatAmount(adminUserExportAmountUSD(row.QuotaSum)), + adminUserExportFormatAmount(adminUserExportDisplayAmount(row.QuotaSum)), + }) + } + _ = w.Write([]string{}) + _ = w.Write([]string{"按模型消费汇总", "模型名称", "请求数", "消耗额度合计", "消耗金额(USD)", "当前展示消耗金额", "输入Token合计", "输出Token合计"}) + for _, row := range modelRows { + _ = w.Write([]string{ + "按模型消费汇总", + row.ModelName, + strconv.FormatInt(row.Cnt, 10), + strconv.FormatInt(row.QuotaSum, 10), + adminUserExportFormatAmount(adminUserExportAmountUSD(row.QuotaSum)), + adminUserExportFormatAmount(adminUserExportDisplayAmount(row.QuotaSum)), + strconv.FormatInt(row.PromptSum, 10), + strconv.FormatInt(row.CompletionSum, 10), + }) + } + w.Flush() +} + +func writeAdminUserConsumptionDetailsCSV(w *csv.Writer, logs []*model.Log, loc *time.Location) { + header := []string{"日志ID", "消费时间", "用户ID", "用户名", "模型名称", "令牌名称", "输入Token数", "输出Token数", "消耗额度", "消耗金额(USD)", "当前展示消耗金额", "耗时(秒)", "是否流式", "渠道ID", "渠道名称", "分组", "IP", "请求ID", "日志内容", "其他信息"} + _ = w.Write(header) + for _, lg := range logs { + ts := time.Unix(lg.CreatedAt, 0).In(loc).Format(time.RFC3339) + quota := int64(lg.Quota) + _ = w.Write([]string{ + strconv.Itoa(lg.Id), + ts, + strconv.Itoa(lg.UserId), + lg.Username, + lg.ModelName, + lg.TokenName, + strconv.Itoa(lg.PromptTokens), + strconv.Itoa(lg.CompletionTokens), + strconv.Itoa(lg.Quota), + adminUserExportFormatAmount(adminUserExportAmountUSD(quota)), + adminUserExportFormatAmount(adminUserExportDisplayAmount(quota)), + strconv.Itoa(lg.UseTime), + adminUserExportBoolText(lg.IsStream), + strconv.Itoa(lg.ChannelId), + lg.ChannelName, + lg.Group, + lg.Ip, + lg.RequestId, + lg.Content, + lg.Other, + }) + } + w.Flush() +} + +// ExportAdminUserMonthlyBill CSV: 月账单摘要(按日志类型汇总 + 按模型消费汇总)。 +func ExportAdminUserMonthlyBill(c *gin.Context) { + userId, year, month, loc, err := parseAdminUserExportMonthQuery(c) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + startSec, endSec, err := model.AdminUserMonthRangeSeconds(year, month, loc) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + + username := adminUserExportUsername(userId) + + typeRows, err := model.GetUserLogTypeAggregatesForRange(userId, startSec, endSec) + if err != nil { + common.ApiError(c, err) + return + } + modelRows, err := model.GetUserConsumeSummaryByModelForRange(userId, startSec, endSec) + if err != nil { + common.ApiError(c, err) + return + } + + filename := adminUserExportFilename("monthly-bill", userId, username, year, month) + adminUserExportSetCSVHeaders(c, filename) + c.Status(http.StatusOK) + + if _, err = c.Writer.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { + return + } + w := csv.NewWriter(c.Writer) + writeAdminUserMonthlyBillCSV(w, userId, username, year, month, loc, startSec, endSec, typeRows, modelRows) +} + +// ExportAdminUserConsumptionDetails CSV: 指定自然月内该用户的消费(调用)明细。 +func ExportAdminUserConsumptionDetails(c *gin.Context) { + userId, year, month, loc, err := parseAdminUserExportMonthQuery(c) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + startSec, endSec, err := model.AdminUserMonthRangeSeconds(year, month, loc) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + + logs, err := model.GetUserConsumeLogsForAdminExport(userId, startSec, endSec) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + + username := adminUserExportUsername(userId) + filename := adminUserExportFilename("consumption-details", userId, username, year, month) + adminUserExportSetCSVHeaders(c, filename) + c.Status(http.StatusOK) + + if _, err = c.Writer.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { + return + } + w := csv.NewWriter(c.Writer) + writeAdminUserConsumptionDetailsCSV(w, logs, loc) +} + +// ExportAdminUserMonthlyBillAndConsumptionDetails ZIP: 同时导出月账单摘要与消费明细。 +func ExportAdminUserMonthlyBillAndConsumptionDetails(c *gin.Context) { + userId, year, month, loc, err := parseAdminUserExportMonthQuery(c) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + startSec, endSec, err := model.AdminUserMonthRangeSeconds(year, month, loc) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + + username := adminUserExportUsername(userId) + typeRows, err := model.GetUserLogTypeAggregatesForRange(userId, startSec, endSec) + if err != nil { + common.ApiError(c, err) + return + } + modelRows, err := model.GetUserConsumeSummaryByModelForRange(userId, startSec, endSec) + if err != nil { + common.ApiError(c, err) + return + } + logs, err := model.GetUserConsumeLogsForAdminExport(userId, startSec, endSec) + if err != nil { + c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) + return + } + + zipFilename := strings.TrimSuffix(adminUserExportFilename("monthly-bill-and-consumption-details", userId, username, year, month), ".csv") + ".zip" + adminUserExportSetZipHeaders(c, zipFilename) + c.Status(http.StatusOK) + + zipWriter := zip.NewWriter(c.Writer) + defer zipWriter.Close() + + monthlyFilename := adminUserExportFilename("monthly-bill", userId, username, year, month) + monthlyFile, err := zipWriter.Create(monthlyFilename) + if err != nil { + return + } + _, _ = monthlyFile.Write([]byte{0xEF, 0xBB, 0xBF}) + monthlyCSV := csv.NewWriter(monthlyFile) + writeAdminUserMonthlyBillCSV(monthlyCSV, userId, username, year, month, loc, startSec, endSec, typeRows, modelRows) + + detailsFilename := adminUserExportFilename("consumption-details", userId, username, year, month) + detailsFile, err := zipWriter.Create(detailsFilename) + if err != nil { + return + } + _, _ = detailsFile.Write([]byte{0xEF, 0xBB, 0xBF}) + detailsCSV := csv.NewWriter(detailsFile) + writeAdminUserConsumptionDetailsCSV(detailsCSV, logs, loc) +} diff --git a/controller/log_export.go b/controller/log_export.go new file mode 100644 index 000000000000..f4455b0dad0f --- /dev/null +++ b/controller/log_export.go @@ -0,0 +1,161 @@ +package controller + +import ( + "encoding/csv" + "net/http" + "strconv" + "strings" + "time" + + "github.com/QuantumNous/new-api/common" + "github.com/QuantumNous/new-api/model" + + "github.com/gin-gonic/gin" +) + +func parseLogExportFilter(c *gin.Context, userId int, forAdmin bool) model.LogListFilter { + logType, _ := strconv.Atoi(c.Query("type")) + startTimestamp, _ := strconv.ParseInt(c.Query("start_timestamp"), 10, 64) + endTimestamp, _ := strconv.ParseInt(c.Query("end_timestamp"), 10, 64) + channel, _ := strconv.Atoi(c.Query("channel")) + return model.LogListFilter{ + UserId: userId, + LogType: logType, + StartTimestamp: startTimestamp, + EndTimestamp: endTimestamp, + ModelName: c.Query("model_name"), + Username: c.Query("username"), + TokenName: c.Query("token_name"), + ChannelId: channel, + Group: c.Query("group"), + RequestId: c.Query("request_id"), + ForAdmin: forAdmin, + } +} + +func parseLogExportLocation(c *gin.Context) *time.Location { + loc := time.Local + if tz := strings.TrimSpace(c.Query("timezone")); tz != "" { + if parsed, err := time.LoadLocation(tz); err == nil { + loc = parsed + } + } + return loc +} + +// Admin export: all operational fields (matches admin usage-log table + diagnostics). +func writeAdminUsageLogsExportCSV(w *csv.Writer, logs []*model.Log, loc *time.Location) { + header := []string{ + "日志ID", "时间", "日志类型", "用户ID", "用户名", "模型名称", "令牌名称", + "输入Token数", "输出Token数", "额度", "金额(USD)", "花费", + "耗时(秒)", "是否流式", "渠道ID", "渠道名称", "分组", "IP", "请求ID", "日志内容", "其他信息", + } + _ = w.Write(header) + for _, lg := range logs { + ts := time.Unix(lg.CreatedAt, 0).In(loc).Format(time.RFC3339) + quota := int64(lg.Quota) + _ = w.Write([]string{ + strconv.Itoa(lg.Id), + ts, + adminUserExportLogTypeName(lg.Type), + strconv.Itoa(lg.UserId), + lg.Username, + lg.ModelName, + lg.TokenName, + strconv.Itoa(lg.PromptTokens), + strconv.Itoa(lg.CompletionTokens), + strconv.Itoa(lg.Quota), + adminUserExportFormatAmount(adminUserExportAmountUSD(quota)), + adminUserExportFormatAmount(adminUserExportDisplayAmount(quota)), + strconv.Itoa(lg.UseTime), + adminUserExportBoolText(lg.IsStream), + strconv.Itoa(lg.ChannelId), + lg.ChannelName, + lg.Group, + lg.Ip, + lg.RequestId, + lg.Content, + lg.Other, + }) + } + w.Flush() +} + +// User export: only fields visible on the non-admin usage-log page (both themes). +// Excludes channel, user identity, log id, raw other JSON, USD-only column, admin diagnostics. +func writeUserUsageLogsExportCSV(w *csv.Writer, logs []*model.Log, loc *time.Location) { + header := []string{ + "时间", "日志类型", "令牌名称", "分组", "模型名称", + "输入Token数", "输出Token数", "额度", "花费", + "耗时(秒)", "是否流式", "IP", "请求ID", "日志内容", + } + _ = w.Write(header) + for _, lg := range logs { + ts := time.Unix(lg.CreatedAt, 0).In(loc).Format(time.RFC3339) + quota := int64(lg.Quota) + ip := "" + if (lg.Type == model.LogTypeConsume || lg.Type == model.LogTypeError) && lg.Ip != "" { + ip = lg.Ip + } + _ = w.Write([]string{ + ts, + adminUserExportLogTypeName(lg.Type), + lg.TokenName, + lg.Group, + lg.ModelName, + strconv.Itoa(lg.PromptTokens), + strconv.Itoa(lg.CompletionTokens), + strconv.Itoa(lg.Quota), + adminUserExportFormatAmount(adminUserExportDisplayAmount(quota)), + strconv.Itoa(lg.UseTime), + adminUserExportBoolText(lg.IsStream), + ip, + lg.RequestId, + lg.Content, + }) + } + w.Flush() +} + +func respondUsageLogsExport(c *gin.Context, filter model.LogListFilter) { + logs, _, err := model.GetLogsForExport(filter, 0) + if err != nil { + if strings.Contains(err.Error(), "导出上限") { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + common.ApiError(c, err) + return + } + + loc := parseLogExportLocation(c) + filename := "usage-logs-" + time.Now().In(loc).Format("20060102-150405") + ".csv" + adminUserExportSetCSVHeaders(c, filename) + c.Status(http.StatusOK) + + if _, err = c.Writer.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { + return + } + w := csv.NewWriter(c.Writer) + if filter.ForAdmin { + writeAdminUsageLogsExportCSV(w, logs, loc) + } else { + writeUserUsageLogsExportCSV(w, logs, loc) + } +} + +// ExportAllLogs exports filtered usage logs as CSV (admin). +func ExportAllLogs(c *gin.Context) { + filter := parseLogExportFilter(c, 0, true) + respondUsageLogsExport(c, filter) +} + +// ExportUserLogs exports filtered usage logs as CSV for the current user. +func ExportUserLogs(c *gin.Context) { + userId := c.GetInt("id") + filter := parseLogExportFilter(c, userId, false) + respondUsageLogsExport(c, filter) +} diff --git a/controller/log_export_test.go b/controller/log_export_test.go new file mode 100644 index 000000000000..94f17efcd84a --- /dev/null +++ b/controller/log_export_test.go @@ -0,0 +1,60 @@ +package controller + +import ( + "bytes" + "encoding/csv" + "strings" + "testing" + "time" + + "github.com/QuantumNous/new-api/model" +) + +func TestWriteUserUsageLogsExportCSV_omitsAdminFields(t *testing.T) { + var buf bytes.Buffer + w := csv.NewWriter(&buf) + logs := []*model.Log{ + { + Id: 99, + UserId: 1, + Username: "alice", + Type: model.LogTypeConsume, + CreatedAt: 1700000000, + TokenName: "tok", + Group: "default", + ModelName: "gpt-4", + PromptTokens: 10, + CompletionTokens: 20, + Quota: 100, + UseTime: 3, + IsStream: true, + ChannelId: 5, + ChannelName: "secret-channel", + Ip: "1.2.3.4", + RequestId: "req-1", + Content: "ok", + Other: "{}", + }, + } + writeUserUsageLogsExportCSV(w, logs, time.UTC) + w.Flush() + + rows, err := csv.NewReader(strings.NewReader(buf.String())).ReadAll() + if err != nil { + t.Fatal(err) + } + if len(rows) != 2 { + t.Fatalf("want header+1 row, got %d", len(rows)) + } + header := strings.Join(rows[0], ",") + if strings.Contains(header, "渠道") || strings.Contains(header, "用户") || strings.Contains(header, "其他信息") { + t.Fatalf("user header must not contain admin columns: %v", rows[0]) + } + row := strings.Join(rows[1], ",") + if strings.Contains(row, "secret-channel") || strings.Contains(row, "alice") { + t.Fatalf("user row leaked admin-only data: %s", row) + } + if !strings.Contains(row, "tok") || !strings.Contains(row, "gpt-4") { + t.Fatalf("user row missing visible fields: %s", row) + } +} diff --git a/controller/pricing.go b/controller/pricing.go index 8252327244c4..814de856f180 100644 --- a/controller/pricing.go +++ b/controller/pricing.go @@ -4,6 +4,7 @@ import ( "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/model" "github.com/QuantumNous/new-api/service" + "github.com/QuantumNous/new-api/setting" "github.com/QuantumNous/new-api/setting/ratio_setting" "github.com/gin-gonic/gin" @@ -33,6 +34,28 @@ func filterPricingByUsableGroups(pricing []model.Pricing, usableGroup map[string return filtered } +// visitorPricingUsableGroups builds usable_group for unauthenticated visitors browsing the catalog. +// Logged-in users still get group-filtered pricing; visitors see the full list but need group labels +// for filters — prefer configured ratio groups, else derive from pricing enable_groups. +func visitorPricingUsableGroups(pricing []model.Pricing) map[string]string { + out := make(map[string]string) + for g := range ratio_setting.GetGroupRatioCopy() { + out[g] = setting.GetUsableGroupDescription(g) + } + if len(out) > 0 { + return out + } + for _, p := range pricing { + for _, g := range p.EnableGroup { + if g == "" || g == "all" { + continue + } + out[g] = setting.GetUsableGroupDescription(g) + } + } + return out +} + func GetPricing(c *gin.Context) { pricing := model.GetPricing() userId, exists := c.Get("id") @@ -42,9 +65,11 @@ func GetPricing(c *gin.Context) { groupRatio[s] = f } var group string + authenticated := false if exists { user, err := model.GetUserCache(userId.(int)) if err == nil { + authenticated = true group = user.Group for g := range groupRatio { ratio, ok := ratio_setting.GetGroupGroupRatio(group, g) @@ -56,7 +81,11 @@ func GetPricing(c *gin.Context) { } usableGroup = service.GetUserUsableGroups(group) - pricing = filterPricingByUsableGroups(pricing, usableGroup) + if authenticated { + pricing = filterPricingByUsableGroups(pricing, usableGroup) + } else { + usableGroup = visitorPricingUsableGroups(pricing) + } // check groupRatio contains usableGroup for group := range ratio_setting.GetGroupRatioCopy() { if _, ok := usableGroup[group]; !ok { diff --git a/docker-compose.local-build.yml b/docker-compose.local-build.yml new file mode 100644 index 000000000000..6e1d07f5d8d6 --- /dev/null +++ b/docker-compose.local-build.yml @@ -0,0 +1,12 @@ +# 与 docker-compose.yml 合并使用,从本地 Dockerfile 构建 new-api 镜像。 +# 启动示例: +# docker compose -f docker-compose.yml -f docker-compose.local-build.yml up -d --build +# +# 详见 docs/docker-local-build-deploy.md + +services: + new-api: + build: + context: . + dockerfile: Dockerfile + image: new-api:local diff --git a/model/log.go b/model/log.go index 9203ff28be13..509244d1616d 100644 --- a/model/log.go +++ b/model/log.go @@ -336,6 +336,14 @@ func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName return nil, 0, err } + if err = fillLogChannelNames(logs); err != nil { + return logs, total, err + } + + return logs, total, err +} + +func fillLogChannelNames(logs []*Log) error { channelIds := types.NewSet[int]() for _, log := range logs { if log.ChannelId != 0 { @@ -343,40 +351,197 @@ func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName } } - if channelIds.Len() > 0 { - var channels []struct { - Id int `gorm:"column:id"` - Name string `gorm:"column:name"` - } - if common.MemoryCacheEnabled { - // Cache get channel - for _, channelId := range channelIds.Items() { - if cacheChannel, err := CacheGetChannel(channelId); err == nil { - channels = append(channels, struct { - Id int `gorm:"column:id"` - Name string `gorm:"column:name"` - }{ - Id: channelId, - Name: cacheChannel.Name, - }) - } + if channelIds.Len() == 0 { + return nil + } + var channels []struct { + Id int `gorm:"column:id"` + Name string `gorm:"column:name"` + } + if common.MemoryCacheEnabled { + for _, channelId := range channelIds.Items() { + if cacheChannel, err := CacheGetChannel(channelId); err == nil { + channels = append(channels, struct { + Id int `gorm:"column:id"` + Name string `gorm:"column:name"` + }{ + Id: channelId, + Name: cacheChannel.Name, + }) } + } + } else { + if err := DB.Table("channels").Select("id, name").Where("id IN ?", channelIds.Items()).Find(&channels).Error; err != nil { + return err + } + } + channelMap := make(map[int]string, len(channels)) + for _, channel := range channels { + channelMap[channel.Id] = channel.Name + } + for i := range logs { + logs[i].ChannelName = channelMap[logs[i].ChannelId] + } + return nil +} + +const adminUserLogExportMaxRows = 100000 + +// LogListFilter describes list/export query filters for usage logs. +type LogListFilter struct { + UserId int + LogType int + StartTimestamp int64 + EndTimestamp int64 + ModelName string + Username string + TokenName string + ChannelId int + Group string + RequestId string + ForAdmin bool +} + +func applyLogListFilters(tx *gorm.DB, f LogListFilter) (*gorm.DB, error) { + if f.UserId > 0 { + if f.LogType == LogTypeUnknown { + tx = tx.Where("logs.user_id = ?", f.UserId) } else { - // Bulk query channels from DB - if err = DB.Table("channels").Select("id, name").Where("id IN ?", channelIds.Items()).Find(&channels).Error; err != nil { - return logs, total, err - } + tx = tx.Where("logs.user_id = ? AND logs.type = ?", f.UserId, f.LogType) } - channelMap := make(map[int]string, len(channels)) - for _, channel := range channels { - channelMap[channel.Id] = channel.Name + } else if f.LogType != LogTypeUnknown { + tx = tx.Where("logs.type = ?", f.LogType) + } + + if f.ModelName != "" { + if f.ForAdmin { + tx = tx.Where("logs.model_name LIKE ?", f.ModelName) + } else { + modelNamePattern, err := sanitizeLikePattern(f.ModelName) + if err != nil { + return nil, err + } + tx = tx.Where("logs.model_name LIKE ? ESCAPE '!'", modelNamePattern) } - for i := range logs { - logs[i].ChannelName = channelMap[logs[i].ChannelId] + } + if f.Username != "" { + tx = tx.Where("logs.username = ?", f.Username) + } + if f.TokenName != "" { + tx = tx.Where("logs.token_name = ?", f.TokenName) + } + if f.RequestId != "" { + tx = tx.Where("logs.request_id = ?", f.RequestId) + } + if f.StartTimestamp != 0 { + tx = tx.Where("logs.created_at >= ?", f.StartTimestamp) + } + if f.EndTimestamp != 0 { + tx = tx.Where("logs.created_at <= ?", f.EndTimestamp) + } + if f.ChannelId != 0 { + tx = tx.Where("logs.channel_id = ?", f.ChannelId) + } + if f.Group != "" { + tx = tx.Where("logs."+logGroupCol+" = ?", f.Group) + } + return tx, nil +} + +// GetLogsForExport returns logs matching filters up to maxRows (ordered by id desc). +func GetLogsForExport(f LogListFilter, maxRows int) (logs []*Log, total int64, err error) { + if maxRows <= 0 { + maxRows = adminUserLogExportMaxRows + } + tx := LOG_DB.Model(&Log{}) + tx, err = applyLogListFilters(tx, f) + if err != nil { + return nil, 0, err + } + if err = tx.Count(&total).Error; err != nil { + common.SysError("failed to count logs for export: " + err.Error()) + return nil, 0, errors.New("查询日志失败") + } + if total > int64(maxRows) { + return nil, total, fmt.Errorf("记录数超过导出上限 %d 条,请缩小筛选范围", maxRows) + } + err = tx.Order("logs.id desc").Limit(maxRows).Find(&logs).Error + if err != nil { + common.SysError("failed to query logs for export: " + err.Error()) + return nil, total, errors.New("查询日志失败") + } + if f.ForAdmin { + if err = fillLogChannelNames(logs); err != nil { + return nil, total, err } } + return logs, total, nil +} + +// AdminUserMonthRangeSeconds returns inclusive unix seconds for the calendar month in loc. +func AdminUserMonthRangeSeconds(year, month int, loc *time.Location) (startSec, endSec int64, err error) { + if loc == nil { + loc = time.UTC + } + if year < 1970 || year > 9999 || month < 1 || month > 12 { + return 0, 0, errors.New("invalid year or month") + } + start := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, loc) + end := start.AddDate(0, 1, 0).Add(-time.Nanosecond) + return start.Unix(), end.Unix(), nil +} - return logs, total, err +// GetUserConsumeLogsForAdminExport returns consume logs in [startTimestamp, endTimestamp] ordered by id ascending. +func GetUserConsumeLogsForAdminExport(userId int, startTimestamp, endTimestamp int64) (logs []*Log, err error) { + tx := LOG_DB.Where("logs.user_id = ? AND logs.type = ?", userId, LogTypeConsume). + Where("logs.created_at >= ? AND logs.created_at <= ?", startTimestamp, endTimestamp) + var total int64 + if err = tx.Model(&Log{}).Count(&total).Error; err != nil { + return nil, err + } + if total > adminUserLogExportMaxRows { + return nil, fmt.Errorf("记录数超过导出上限 %d 条,请缩小时间范围", adminUserLogExportMaxRows) + } + err = tx.Order("logs.id asc").Find(&logs).Error + if err != nil { + return nil, err + } + if err = fillLogChannelNames(logs); err != nil { + return nil, err + } + return logs, nil +} + +type AdminUserMonthLogTypeAgg struct { + Type int `json:"type" gorm:"column:type"` + Cnt int64 `json:"cnt" gorm:"column:cnt"` + QuotaSum int64 `json:"quota_sum" gorm:"column:quota_sum"` +} + +func GetUserLogTypeAggregatesForRange(userId int, startTimestamp, endTimestamp int64) (rows []AdminUserMonthLogTypeAgg, err error) { + err = LOG_DB.Model(&Log{}). + Select("type, COUNT(*) AS cnt, COALESCE(SUM(quota), 0) AS quota_sum"). + Where("user_id = ? AND created_at >= ? AND created_at <= ?", userId, startTimestamp, endTimestamp). + Group("type"). + Scan(&rows).Error + return rows, err +} + +type AdminUserMonthModelAgg struct { + ModelName string `json:"model_name" gorm:"column:model_name"` + Cnt int64 `json:"cnt" gorm:"column:cnt"` + QuotaSum int64 `json:"quota_sum" gorm:"column:quota_sum"` + PromptSum int64 `json:"prompt_sum" gorm:"column:prompt_sum"` + CompletionSum int64 `json:"completion_sum" gorm:"column:completion_sum"` +} + +func GetUserConsumeSummaryByModelForRange(userId int, startTimestamp, endTimestamp int64) (rows []AdminUserMonthModelAgg, err error) { + err = LOG_DB.Model(&Log{}). + Select("model_name, COUNT(*) AS cnt, COALESCE(SUM(quota), 0) AS quota_sum, COALESCE(SUM(prompt_tokens), 0) AS prompt_sum, COALESCE(SUM(completion_tokens), 0) AS completion_sum"). + Where("user_id = ? AND type = ? AND created_at >= ? AND created_at <= ?", userId, LogTypeConsume, startTimestamp, endTimestamp). + Group("model_name"). + Scan(&rows).Error + return rows, err } const logSearchCountLimit = 10000 @@ -432,6 +597,54 @@ type Stat struct { Tpm int `json:"tpm"` } +// ConsumptionAggregate summarizes consume logs for a channel (optionally scoped to one user). +type ConsumptionAggregate struct { + Quota int64 `json:"quota"` + RequestCount int64 `json:"request_count"` + PromptTokens int64 `json:"prompt_tokens"` + CompletionTokens int64 `json:"completion_tokens"` +} + +const maxConsumptionRangeSeconds = 366 * 24 * 3600 + +func SumChannelConsumption(channelId int, userId int, username string, startTimestamp, endTimestamp int64) (ConsumptionAggregate, error) { + var agg ConsumptionAggregate + if channelId <= 0 { + return agg, errors.New("invalid channel id") + } + if startTimestamp <= 0 || endTimestamp <= 0 { + return agg, errors.New("invalid time range") + } + if endTimestamp < startTimestamp { + return agg, errors.New("end_timestamp must be greater than or equal to start_timestamp") + } + if endTimestamp-startTimestamp > maxConsumptionRangeSeconds { + return agg, fmt.Errorf("time range cannot exceed %d days", maxConsumptionRangeSeconds/(24*3600)) + } + + tx := LOG_DB.Model(&Log{}). + Where("type = ?", LogTypeConsume). + Where("channel_id = ?", channelId) + if userId > 0 { + tx = tx.Where("user_id = ?", userId) + } else if username != "" { + tx = tx.Where("username = ?", username) + } + tx = tx.Where("created_at >= ?", startTimestamp).Where("created_at <= ?", endTimestamp) + + err := tx.Select( + "COALESCE(SUM(quota), 0) AS quota", + "COUNT(*) AS request_count", + "COALESCE(SUM(prompt_tokens), 0) AS prompt_tokens", + "COALESCE(SUM(completion_tokens), 0) AS completion_tokens", + ).Scan(&agg).Error + if err != nil { + common.SysError("failed to sum channel consumption: " + err.Error()) + return agg, errors.New("查询渠道消费统计失败") + } + return agg, nil +} + func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int, group string) (stat Stat, err error) { tx := LOG_DB.Table("logs").Select("sum(quota) quota") diff --git a/model/log_consumption_test.go b/model/log_consumption_test.go new file mode 100644 index 000000000000..d7e146ac914f --- /dev/null +++ b/model/log_consumption_test.go @@ -0,0 +1,83 @@ +package model + +import ( + "fmt" + "strings" + "testing" + + "github.com/QuantumNous/new-api/common" + "github.com/glebarez/sqlite" + "gorm.io/gorm" +) + +func openLogConsumptionTestDB(t *testing.T) *gorm.DB { + t.Helper() + common.UsingSQLite = true + common.UsingMySQL = false + common.UsingPostgreSQL = false + + dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", strings.ReplaceAll(t.Name(), "/", "_")) + db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("open sqlite: %v", err) + } + if err := db.AutoMigrate(&Log{}); err != nil { + t.Fatalf("migrate logs: %v", err) + } + LOG_DB = db + t.Cleanup(func() { + sqlDB, err := db.DB() + if err == nil { + _ = sqlDB.Close() + } + }) + return db +} + +func TestSumChannelConsumption(t *testing.T) { + openLogConsumptionTestDB(t) + + base := int64(1_700_000_000) + logs := []Log{ + {UserId: 1, Username: "alice", Type: LogTypeConsume, ChannelId: 10, Quota: 100, PromptTokens: 10, CompletionTokens: 20, CreatedAt: base}, + {UserId: 1, Username: "alice", Type: LogTypeConsume, ChannelId: 10, Quota: 50, PromptTokens: 5, CompletionTokens: 5, CreatedAt: base + 100}, + {UserId: 2, Username: "bob", Type: LogTypeConsume, ChannelId: 10, Quota: 200, PromptTokens: 30, CompletionTokens: 40, CreatedAt: base + 200}, + {UserId: 2, Username: "bob", Type: LogTypeConsume, ChannelId: 11, Quota: 999, PromptTokens: 1, CompletionTokens: 1, CreatedAt: base + 200}, + {UserId: 1, Username: "alice", Type: LogTypeTopup, ChannelId: 10, Quota: 500, CreatedAt: base + 300}, + {UserId: 1, Username: "alice", Type: LogTypeConsume, ChannelId: 10, Quota: 300, PromptTokens: 1, CompletionTokens: 1, CreatedAt: base + 400*24*3600}, + } + if err := LOG_DB.Create(&logs).Error; err != nil { + t.Fatalf("seed logs: %v", err) + } + + start := base + end := base + 24*3600 + + all, err := SumChannelConsumption(10, 0, "", start, end) + if err != nil { + t.Fatalf("sum channel: %v", err) + } + if all.Quota != 350 || all.RequestCount != 3 || all.PromptTokens != 45 || all.CompletionTokens != 65 { + t.Fatalf("unexpected channel aggregate: %+v", all) + } + + alice, err := SumChannelConsumption(10, 1, "", start, end) + if err != nil { + t.Fatalf("sum user channel: %v", err) + } + if alice.Quota != 150 || alice.RequestCount != 2 { + t.Fatalf("unexpected user aggregate: %+v", alice) + } + + byName, err := SumChannelConsumption(10, 0, "bob", start, end) + if err != nil { + t.Fatalf("sum by username: %v", err) + } + if byName.Quota != 200 { + t.Fatalf("unexpected username aggregate: %+v", byName) + } + + if _, err := SumChannelConsumption(10, 0, "", end+1, start); err == nil { + t.Fatal("expected invalid range error") + } +} diff --git a/model/log_export_test.go b/model/log_export_test.go new file mode 100644 index 000000000000..26ef7d6abb7e --- /dev/null +++ b/model/log_export_test.go @@ -0,0 +1,65 @@ +package model + +import ( + "fmt" + "strings" + "testing" + + "github.com/QuantumNous/new-api/common" + "github.com/glebarez/sqlite" + "gorm.io/gorm" +) + +func openLogExportTestDB(t *testing.T) *gorm.DB { + t.Helper() + common.UsingSQLite = true + dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", strings.ReplaceAll(t.Name(), "/", "_")) + db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("open sqlite: %v", err) + } + if err := db.AutoMigrate(&Log{}); err != nil { + t.Fatalf("migrate: %v", err) + } + LOG_DB = db + return db +} + +func TestGetLogsForExport(t *testing.T) { + openLogExportTestDB(t) + base := int64(1_700_000_000) + seed := []Log{ + {UserId: 1, Username: "alice", Type: LogTypeConsume, ModelName: "gpt-4", Quota: 10, CreatedAt: base}, + {UserId: 2, Username: "bob", Type: LogTypeConsume, ModelName: "gpt-4", Quota: 20, CreatedAt: base + 100}, + {UserId: 1, Username: "alice", Type: LogTypeTopup, Quota: 100, CreatedAt: base + 200}, + } + if err := LOG_DB.Create(&seed).Error; err != nil { + t.Fatal(err) + } + + logs, total, err := GetLogsForExport(LogListFilter{ + LogType: LogTypeConsume, + StartTimestamp: base, + EndTimestamp: base + 1000, + ForAdmin: true, + }, 0) + if err != nil { + t.Fatal(err) + } + if total != 2 || len(logs) != 2 { + t.Fatalf("want 2 consume logs, got total=%d len=%d", total, len(logs)) + } + + _, total, err = GetLogsForExport(LogListFilter{ + UserId: 1, + LogType: LogTypeUnknown, + StartTimestamp: base, + EndTimestamp: base + 1000, + }, 0) + if err != nil { + t.Fatal(err) + } + if total != 2 { + t.Fatalf("want 2 logs for user 1, got %d", total) + } +} diff --git a/model/user.go b/model/user.go index b632ef9afad6..1976b2bd82b6 100644 --- a/model/user.go +++ b/model/user.go @@ -305,6 +305,16 @@ func GetUserById(id int, selectAll bool) (*User, error) { return &user, err } +func GetUserByUsername(username string) (*User, error) { + username = strings.TrimSpace(username) + if username == "" { + return nil, errors.New("username is empty") + } + user := &User{} + err := DB.Omit("password").Where("username = ?", username).First(user).Error + return user, err +} + func GetUserIdByAffCode(affCode string) (int, error) { if affCode == "" { return 0, errors.New("affCode 为空!") diff --git a/relay/channel/api_request.go b/relay/channel/api_request.go index 8dfb61d40093..d38c951e5744 100644 --- a/relay/channel/api_request.go +++ b/relay/channel/api_request.go @@ -274,19 +274,37 @@ func ResolveHeaderOverride(info *common.RelayInfo, c *gin.Context) (map[string]s return processHeaderOverride(info, c) } -func applyHeaderOverrideToRequest(req *http.Request, headerOverride map[string]string) { +func ApplyResolvedHeaderOverrides(dst *http.Header, info *common.RelayInfo, headerOverride map[string]string) { + if dst == nil { + return + } + for key, value := range headerOverride { + dst.Set(key, value) + } + removeRuntimeDeletedHeaders(dst, info) +} + +func applyHeaderOverrideToRequest(req *http.Request, info *common.RelayInfo, headerOverride map[string]string) { if req == nil { return } + ApplyResolvedHeaderOverrides(&req.Header, info, headerOverride) for key, value := range headerOverride { - req.Header.Set(key, value) - // set Host in req if strings.EqualFold(key, "Host") { req.Host = value } } } +func removeRuntimeDeletedHeaders(headers *http.Header, info *common.RelayInfo) { + if headers == nil || info == nil || !info.UseRuntimeHeadersOverride { + return + } + for _, key := range info.RuntimeHeadersDeleted { + headers.Del(key) + } +} + func DoApiRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBody io.Reader) (*http.Response, error) { fullRequestURL, err := a.GetRequestURL(info) if err != nil { @@ -310,7 +328,7 @@ func DoApiRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBody if err != nil { return nil, err } - applyHeaderOverrideToRequest(req, headerOverride) + applyHeaderOverrideToRequest(req, info, headerOverride) resp, err := doRequest(c, req, info) if err != nil { return nil, fmt.Errorf("do request failed: %w", err) @@ -343,7 +361,7 @@ func DoFormRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBod if err != nil { return nil, err } - applyHeaderOverrideToRequest(req, headerOverride) + applyHeaderOverrideToRequest(req, info, headerOverride) resp, err := doRequest(c, req, info) if err != nil { return nil, fmt.Errorf("do request failed: %w", err) @@ -367,9 +385,7 @@ func DoWssRequest(a Adaptor, c *gin.Context, info *common.RelayInfo, requestBody if err != nil { return nil, err } - for key, value := range headerOverride { - targetHeader.Set(key, value) - } + ApplyResolvedHeaderOverrides(&targetHeader, info, headerOverride) targetHeader.Set("Content-Type", c.Request.Header.Get("Content-Type")) targetConn, _, err := websocket.DefaultDialer.Dial(fullRequestURL, targetHeader) if err != nil { diff --git a/relay/channel/api_request_test.go b/relay/channel/api_request_test.go index f697f8555692..9f7c5c6a1bc6 100644 --- a/relay/channel/api_request_test.go +++ b/relay/channel/api_request_test.go @@ -186,8 +186,28 @@ func TestProcessHeaderOverride_PassHeadersTemplateSetsRuntimeHeaders(t *testing. require.False(t, exists) upstreamReq := httptest.NewRequest(http.MethodPost, "https://example.com/v1/responses", nil) - applyHeaderOverrideToRequest(upstreamReq, headers) + applyHeaderOverrideToRequest(upstreamReq, info, headers) require.Equal(t, "Codex CLI", upstreamReq.Header.Get("Originator")) require.Equal(t, "sess-123", upstreamReq.Header.Get("Session_id")) require.Empty(t, upstreamReq.Header.Get("X-Codex-Beta-Features")) } + +func TestApplyResolvedHeaderOverrides_RemovesRuntimeDeletedHeaders(t *testing.T) { + t.Parallel() + + headers := http.Header{} + headers.Set("anthropic-beta", "computer-use-2025-01-24") + headers.Set("x-api-key", "secret") + + info := &relaycommon.RelayInfo{ + UseRuntimeHeadersOverride: true, + RuntimeHeadersDeleted: []string{"anthropic-beta"}, + } + + ApplyResolvedHeaderOverrides(&headers, info, map[string]string{ + "x-api-key": "secret", + }) + + require.Empty(t, headers.Get("anthropic-beta")) + require.Equal(t, "secret", headers.Get("x-api-key")) +} diff --git a/relay/channel/aws/constants.go b/relay/channel/aws/constants.go index ff1f377ee8de..d24e02ebf16b 100644 --- a/relay/channel/aws/constants.go +++ b/relay/channel/aws/constants.go @@ -19,6 +19,7 @@ var awsModelIDMap = map[string]string{ "claude-opus-4-5-20251101": "anthropic.claude-opus-4-5-20251101-v1:0", "claude-opus-4-6": "anthropic.claude-opus-4-6-v1", "claude-opus-4-7": "anthropic.claude-opus-4-7", + "claude-opus-4-8": "anthropic.claude-opus-4-8", // Nova models "nova-micro-v1:0": "amazon.nova-micro-v1:0", "nova-lite-v1:0": "amazon.nova-lite-v1:0", @@ -97,6 +98,11 @@ var awsModelCanCrossRegionMap = map[string]map[string]bool{ "ap": true, "eu": true, }, + "anthropic.claude-opus-4-8": { + "us": true, + "ap": true, + "eu": true, + }, "anthropic.claude-haiku-4-5-20251001-v1:0": { "us": true, "ap": true, diff --git a/relay/channel/aws/relay-aws.go b/relay/channel/aws/relay-aws.go index 1f6ff7e69263..1cd25a22b29a 100644 --- a/relay/channel/aws/relay-aws.go +++ b/relay/channel/aws/relay-aws.go @@ -111,9 +111,7 @@ func doAwsClientRequest(c *gin.Context, info *relaycommon.RelayInfo, a *Adaptor, if err != nil { return nil, err } - for key, value := range headerOverride { - requestHeader.Set(key, value) - } + channel.ApplyResolvedHeaderOverrides(&requestHeader, info, headerOverride) if isNovaModel(awsModelId) { var novaReq *NovaRequest diff --git a/relay/channel/aws/relay_aws_test.go b/relay/channel/aws/relay_aws_test.go index 92745ff40929..5a5eefdfcb96 100644 --- a/relay/channel/aws/relay_aws_test.go +++ b/relay/channel/aws/relay_aws_test.go @@ -53,3 +53,82 @@ func TestDoAwsClientRequest_AppliesRuntimeHeaderOverrideToAnthropicBeta(t *testi require.True(t, ok) require.Equal(t, []any{"computer-use-2025-01-24"}, values) } + +func TestDoAwsClientRequest_DeleteHeaderRemovesAnthropicBetaFromBedrockPayload(t *testing.T) { + t.Parallel() + + gin.SetMode(gin.TestMode) + recorder := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(recorder) + ctx.Request = httptest.NewRequest(http.MethodPost, "/v1/messages", nil) + ctx.Request.Header.Set("anthropic-beta", "computer-use-2025-01-24") + + info := &relaycommon.RelayInfo{ + OriginModelName: "claude-3-5-sonnet-20240620", + IsStream: false, + UseRuntimeHeadersOverride: true, + RuntimeHeadersDeleted: []string{"anthropic-beta"}, + ChannelMeta: &relaycommon.ChannelMeta{ + ApiKey: "access-key|secret-key|us-east-1", + UpstreamModelName: "claude-3-5-sonnet-20240620", + }, + } + + requestBody := bytes.NewBufferString(`{"messages":[{"role":"user","content":"hello"}],"max_tokens":128}`) + adaptor := &Adaptor{} + + _, err := doAwsClientRequest(ctx, info, adaptor, requestBody) + require.NoError(t, err) + + awsReq, ok := adaptor.AwsReq.(*bedrockruntime.InvokeModelInput) + require.True(t, ok) + + var payload map[string]any + require.NoError(t, common.Unmarshal(awsReq.Body, &payload)) + _, exists := payload["anthropic_beta"] + require.False(t, exists, "anthropic_beta should be omitted when delete_header removed anthropic-beta") +} + +func TestDoAwsClientRequest_ParamOverrideDeleteHeaderRemovesAnthropicBeta(t *testing.T) { + t.Parallel() + + gin.SetMode(gin.TestMode) + recorder := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(recorder) + ctx.Request = httptest.NewRequest(http.MethodPost, "/v1/messages", nil) + ctx.Request.Header.Set("anthropic-beta", "computer-use-2025-01-24") + + info := &relaycommon.RelayInfo{ + OriginModelName: "claude-3-5-sonnet-20240620", + IsStream: false, + ChannelMeta: &relaycommon.ChannelMeta{ + ApiKey: "access-key|secret-key|us-east-1", + UpstreamModelName: "claude-3-5-sonnet-20240620", + ParamOverride: map[string]any{ + "operations": []any{ + map[string]any{ + "mode": "delete_header", + "path": "anthropic-beta", + }, + }, + }, + }, + } + + requestJSON := []byte(`{"messages":[{"role":"user","content":"hello"}],"max_tokens":128}`) + updatedJSON, err := relaycommon.ApplyParamOverrideWithRelayInfo(requestJSON, info) + require.NoError(t, err) + require.Equal(t, []string{"anthropic-beta"}, info.RuntimeHeadersDeleted) + + adaptor := &Adaptor{} + _, err = doAwsClientRequest(ctx, info, adaptor, bytes.NewReader(updatedJSON)) + require.NoError(t, err) + + awsReq, ok := adaptor.AwsReq.(*bedrockruntime.InvokeModelInput) + require.True(t, ok) + + var payload map[string]any + require.NoError(t, common.Unmarshal(awsReq.Body, &payload)) + _, exists := payload["anthropic_beta"] + require.False(t, exists) +} diff --git a/relay/channel/claude/constants.go b/relay/channel/claude/constants.go index 3c516aefb7db..0e7ba8652a38 100644 --- a/relay/channel/claude/constants.go +++ b/relay/channel/claude/constants.go @@ -33,6 +33,13 @@ var ModelList = []string{ "claude-opus-4-7-medium", "claude-opus-4-7-low", "claude-opus-4-7-thinking", + "claude-opus-4-8", + "claude-opus-4-8-max", + "claude-opus-4-8-xhigh", + "claude-opus-4-8-high", + "claude-opus-4-8-medium", + "claude-opus-4-8-low", + "claude-opus-4-8-thinking", } var ChannelName = "claude" diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index e177e56dab14..5f297e704450 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -154,14 +154,14 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe } if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(textRequest.Model); ok && effortLevel != "" && - (strings.HasPrefix(textRequest.Model, "claude-opus-4-6") || strings.HasPrefix(textRequest.Model, "claude-opus-4-7")) { + (strings.HasPrefix(textRequest.Model, "claude-opus-4-6") || strings.HasPrefix(textRequest.Model, "claude-opus-4-7") || strings.HasPrefix(textRequest.Model, "claude-opus-4-8")) { claudeRequest.Model = baseModel claudeRequest.Thinking = &dto.Thinking{ Type: "adaptive", } claudeRequest.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) - if strings.HasPrefix(baseModel, "claude-opus-4-7") { - // Opus 4.7 rejects non-default temperature/top_p/top_k with 400 + if strings.HasPrefix(baseModel, "claude-opus-4-7") || strings.HasPrefix(baseModel, "claude-opus-4-8") { + // Opus 4.7+ rejects non-default temperature/top_p/top_k with 400 // and defaults display to "omitted"; restore the 4.6 visible summary. claudeRequest.Thinking.Display = "summarized" claudeRequest.Temperature = nil @@ -175,8 +175,8 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe strings.HasSuffix(textRequest.Model, "-thinking") { trimmedModel := strings.TrimSuffix(textRequest.Model, "-thinking") - if strings.HasPrefix(trimmedModel, "claude-opus-4-7") { - // Opus 4.7 rejects thinking.type="enabled"; use adaptive at high effort. + if strings.HasPrefix(trimmedModel, "claude-opus-4-7") || strings.HasPrefix(trimmedModel, "claude-opus-4-8") { + // Opus 4.7+ rejects thinking.type="enabled"; use adaptive at high effort. claudeRequest.Thinking = &dto.Thinking{Type: "adaptive", Display: "summarized"} claudeRequest.OutputConfig = json.RawMessage(`{"effort":"high"}`) claudeRequest.Temperature = nil diff --git a/relay/channel/vertex/adaptor.go b/relay/channel/vertex/adaptor.go index 0d91032d0f35..7f087c21b90c 100644 --- a/relay/channel/vertex/adaptor.go +++ b/relay/channel/vertex/adaptor.go @@ -45,6 +45,7 @@ var claudeModelMap = map[string]string{ "claude-opus-4-5-20251101": "claude-opus-4-5@20251101", "claude-opus-4-6": "claude-opus-4-6", "claude-opus-4-7": "claude-opus-4-7", + "claude-opus-4-8": "claude-opus-4-8", } const anthropicVersion = "vertex-2023-10-16" diff --git a/relay/claude_handler.go b/relay/claude_handler.go index 54f8ced2adf4..83955c379e4c 100644 --- a/relay/claude_handler.go +++ b/relay/claude_handler.go @@ -53,14 +53,14 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ } if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(request.Model); ok && effortLevel != "" && - (strings.HasPrefix(request.Model, "claude-opus-4-6") || strings.HasPrefix(request.Model, "claude-opus-4-7")) { + (strings.HasPrefix(request.Model, "claude-opus-4-6") || strings.HasPrefix(request.Model, "claude-opus-4-7") || strings.HasPrefix(request.Model, "claude-opus-4-8")) { request.Model = baseModel request.Thinking = &dto.Thinking{ Type: "adaptive", } request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) - if strings.HasPrefix(request.Model, "claude-opus-4-7") { - // Opus 4.7 rejects non-default temperature/top_p/top_k with 400 + if strings.HasPrefix(request.Model, "claude-opus-4-7") || strings.HasPrefix(request.Model, "claude-opus-4-8") { + // Opus 4.7+ rejects non-default temperature/top_p/top_k with 400 // and defaults display to "omitted"; restore the 4.6 visible summary. request.Thinking.Display = "summarized" request.Temperature = nil @@ -74,8 +74,8 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ strings.HasSuffix(request.Model, "-thinking") { if request.Thinking == nil { baseModel := strings.TrimSuffix(request.Model, "-thinking") - if strings.HasPrefix(baseModel, "claude-opus-4-7") { - // Opus 4.7 rejects thinking.type="enabled"; use adaptive at high effort. + if strings.HasPrefix(baseModel, "claude-opus-4-7") || strings.HasPrefix(baseModel, "claude-opus-4-8") { + // Opus 4.7+ rejects thinking.type="enabled"; use adaptive at high effort. request.Thinking = &dto.Thinking{Type: "adaptive", Display: "summarized"} request.OutputConfig = json.RawMessage(`{"effort":"high"}`) request.Temperature = nil diff --git a/relay/common/override.go b/relay/common/override.go index 1a28303f06a7..77da2ac8c3fc 100644 --- a/relay/common/override.go +++ b/relay/common/override.go @@ -21,6 +21,7 @@ var negativeIndexRegexp = regexp.MustCompile(`\.(-\d+)`) const ( paramOverrideContextRequestHeaders = "request_headers" paramOverrideContextHeaderOverride = "header_override" + paramOverrideContextHeaderDeleted = "header_deleted" paramOverrideContextAuditRecorder = "__param_override_audit_recorder" ) @@ -186,6 +187,7 @@ func ApplyParamOverrideWithRelayInfo(jsonData []byte, info *RelayInfo) ([]byte, return nil, err } syncRuntimeHeaderOverrideFromContext(info, overrideCtx) + syncRuntimeHeaderDeletedFromContext(info, overrideCtx) if info != nil { if recorder != nil { info.ParamOverrideAudit = recorder.lines @@ -1217,9 +1219,26 @@ func deleteHeaderOverrideInContext(context map[string]interface{}, headerName st } rawHeaders := ensureMapKeyInContext(context, paramOverrideContextHeaderOverride) delete(rawHeaders, headerName) + recordHeaderDeletedInContext(context, headerName) return nil } +func recordHeaderDeletedInContext(context map[string]interface{}, headerName string) { + if context == nil { + return + } + headerName = normalizeHeaderContextKey(headerName) + if headerName == "" { + return + } + raw, _ := context[paramOverrideContextHeaderDeleted].(map[string]struct{}) + if raw == nil { + raw = make(map[string]struct{}) + context[paramOverrideContextHeaderDeleted] = raw + } + raw[headerName] = struct{}{} +} + func parseHeaderPassThroughNames(value interface{}) ([]string, error) { normalizeNames := func(values []string) []string { names := lo.FilterMap(values, func(item string, _ int) (string, bool) { @@ -1491,6 +1510,31 @@ func syncRuntimeHeaderOverrideFromContext(info *RelayInfo, context map[string]in info.UseRuntimeHeadersOverride = true } +func syncRuntimeHeaderDeletedFromContext(info *RelayInfo, context map[string]interface{}) { + if info == nil || context == nil { + return + } + deleted := extractDeletedHeadersFromContext(context) + if len(deleted) == 0 { + return + } + info.RuntimeHeadersDeleted = deleted + info.UseRuntimeHeadersOverride = true +} + +func extractDeletedHeadersFromContext(context map[string]interface{}) []string { + raw, ok := context[paramOverrideContextHeaderDeleted].(map[string]struct{}) + if !ok || len(raw) == 0 { + return nil + } + keys := make([]string, 0, len(raw)) + for key := range raw { + keys = append(keys, key) + } + sort.Strings(keys) + return keys +} + func moveValue(jsonStr, fromPath, toPath string) (string, error) { sourceValue := gjson.Get(jsonStr, fromPath) if !sourceValue.Exists() { diff --git a/relay/common/override_test.go b/relay/common/override_test.go index 6e35cf73e03b..65f097439584 100644 --- a/relay/common/override_test.go +++ b/relay/common/override_test.go @@ -1861,6 +1861,9 @@ func TestApplyParamOverrideWithRelayInfoSyncRuntimeHeaders(t *testing.T) { if _, exists := info.RuntimeHeadersOverride["x-delete-me"]; exists { t.Fatalf("expected x-delete-me header to be deleted") } + if len(info.RuntimeHeadersDeleted) != 1 || info.RuntimeHeadersDeleted[0] != "x-delete-me" { + t.Fatalf("expected x-delete-me to be tracked as deleted, got: %v", info.RuntimeHeadersDeleted) + } } func TestApplyParamOverrideWithRelayInfoMixedLegacyAndOperations(t *testing.T) { diff --git a/relay/common/relay_info.go b/relay/common/relay_info.go index 64d4d4eedfaa..d7f879769fb4 100644 --- a/relay/common/relay_info.go +++ b/relay/common/relay_info.go @@ -150,6 +150,7 @@ type RelayInfo struct { RetryIndex int LastError *types.NewAPIError RuntimeHeadersOverride map[string]interface{} + RuntimeHeadersDeleted []string UseRuntimeHeadersOverride bool ParamOverrideAudit []string diff --git a/router/api-router.go b/router/api-router.go index 83f5e4ae9d92..ee6e5de20ab4 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -237,6 +237,7 @@ func SetApiRouter(router *gin.Engine) { channelRoute.POST("/:id/codex/oauth/complete", controller.CompleteCodexOAuthForChannel) channelRoute.POST("/:id/codex/refresh", controller.RefreshCodexChannelCredential) channelRoute.GET("/:id/codex/usage", controller.GetCodexChannelUsage) + channelRoute.GET("/:id/consumption", controller.GetChannelConsumption) channelRoute.POST("/ollama/pull", controller.OllamaPullModel) channelRoute.POST("/ollama/pull/stream", controller.OllamaPullModelStream) channelRoute.DELETE("/ollama/delete", controller.OllamaDeleteModel) @@ -287,12 +288,17 @@ func SetApiRouter(router *gin.Engine) { } logRoute := apiRouter.Group("/log") logRoute.GET("/", middleware.AdminAuth(), controller.GetAllLogs) + logRoute.GET("/export", middleware.AdminAuth(), controller.ExportAllLogs) + logRoute.GET("/admin/export/monthly_bill", middleware.AdminAuth(), controller.ExportAdminUserMonthlyBill) + logRoute.GET("/admin/export/consumption_details", middleware.AdminAuth(), controller.ExportAdminUserConsumptionDetails) + logRoute.GET("/admin/export/monthly_bill_and_consumption_details", middleware.AdminAuth(), controller.ExportAdminUserMonthlyBillAndConsumptionDetails) logRoute.DELETE("/", middleware.AdminAuth(), controller.DeleteHistoryLogs) logRoute.GET("/stat", middleware.AdminAuth(), controller.GetLogsStat) logRoute.GET("/self/stat", middleware.UserAuth(), controller.GetLogsSelfStat) logRoute.GET("/channel_affinity_usage_cache", middleware.AdminAuth(), controller.GetChannelAffinityUsageCacheStats) logRoute.GET("/search", middleware.AdminAuth(), controller.SearchAllLogs) logRoute.GET("/self", middleware.UserAuth(), controller.GetUserLogs) + logRoute.GET("/self/export", middleware.UserAuth(), controller.ExportUserLogs) logRoute.GET("/self/search", middleware.UserAuth(), middleware.SearchRateLimit(), controller.SearchUserLogs) dataRoute := apiRouter.Group("/data") diff --git a/setting/ratio_setting/cache_ratio.go b/setting/ratio_setting/cache_ratio.go index fe6e3b3262a4..89d0bfc2c51a 100644 --- a/setting/ratio_setting/cache_ratio.go +++ b/setting/ratio_setting/cache_ratio.go @@ -71,6 +71,13 @@ var defaultCacheRatio = map[string]float64{ "claude-opus-4-7-high": 0.1, "claude-opus-4-7-medium": 0.1, "claude-opus-4-7-low": 0.1, + "claude-opus-4-8": 0.1, + "claude-opus-4-8-thinking": 0.1, + "claude-opus-4-8-max": 0.1, + "claude-opus-4-8-xhigh": 0.1, + "claude-opus-4-8-high": 0.1, + "claude-opus-4-8-medium": 0.1, + "claude-opus-4-8-low": 0.1, } var defaultCreateCacheRatio = map[string]float64{ @@ -106,6 +113,13 @@ var defaultCreateCacheRatio = map[string]float64{ "claude-opus-4-7-high": 1.25, "claude-opus-4-7-medium": 1.25, "claude-opus-4-7-low": 1.25, + "claude-opus-4-8": 1.25, + "claude-opus-4-8-thinking": 1.25, + "claude-opus-4-8-max": 1.25, + "claude-opus-4-8-xhigh": 1.25, + "claude-opus-4-8-high": 1.25, + "claude-opus-4-8-medium": 1.25, + "claude-opus-4-8-low": 1.25, } //var defaultCreateCacheRatio = map[string]float64{} diff --git a/setting/ratio_setting/model_ratio.go b/setting/ratio_setting/model_ratio.go index 80702ee42ad2..23fd360e366f 100644 --- a/setting/ratio_setting/model_ratio.go +++ b/setting/ratio_setting/model_ratio.go @@ -152,6 +152,12 @@ var defaultModelRatio = map[string]float64{ "claude-opus-4-7-high": 2.5, "claude-opus-4-7-medium": 2.5, "claude-opus-4-7-low": 2.5, + "claude-opus-4-8": 2.5, + "claude-opus-4-8-max": 2.5, + "claude-opus-4-8-xhigh": 2.5, + "claude-opus-4-8-high": 2.5, + "claude-opus-4-8-medium": 2.5, + "claude-opus-4-8-low": 2.5, "claude-3-opus-20240229": 7.5, // $15 / 1M tokens "claude-opus-4-20250514": 7.5, "claude-opus-4-1-20250805": 7.5, diff --git a/web/classic/bun.lock b/web/classic/bun.lock index da3c1e452a9d..4f109c348221 100644 --- a/web/classic/bun.lock +++ b/web/classic/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "react-template", diff --git a/web/classic/public/home-custom.html b/web/classic/public/home-custom.html new file mode 100644 index 000000000000..ad49aded5831 --- /dev/null +++ b/web/classic/public/home-custom.html @@ -0,0 +1,1031 @@ + + + + + + + + 首页 · New API + + + +
+ +
+ +
+
+
+
+ + 企业级 · OpenAI 兼容 · 多渠道聚合 +
+

+ 企业级 AI 平台 + 面向团队与规模化生产:统一接入、权限与配额、可观测与计费,一站满足严肃业务上线要求。 +

+

+ 一站式 AI 接口聚合
+ 让调用大模型像调用 HTTP 一样简单 +

+

+ 企业级 AI 平台定位:提供快速、便捷的 大模型 API + 调用方案,打造稳定可靠、易于治理 + 的接口平台,一站式集成几乎所有AI大模型,支撑业务持续增长。 +

+
+

+ 更好的价格,更好的稳定性,只需要将模型基址替换为: +

+
+ + /v1/chat/completions + +
+
+ +

已经接入100+ 大模型

+
+ +
+
+

兼容生态与常见上游

+
+ OpenAI + Anthropic Claude + Google Gemini + Azure OpenAI + AWS Bedrock + DeepSeek + 通义·豆包·混元 + Dify · Open WebUI · Lobe Chat +
+
+
+
+ +
+
+
+

我们的优势

+

适配多种业务场景,驱动业务增长。

+
+
+
+ +

统一兼容路由

+

+ 一套 OpenAI 风格 API,对接多种上游渠道与模型别名,降低客户端改造成本。 +

+
+
+ +

密钥与权限

+

用户、分组与令牌管理,配合速率限制与路由策略,便于多团队协作。

+
+
+ +

用量与计费

+

日志、配额与计费表达式,支持按模型与业务维度做精细化结算。

+
+
+ +

可观测性

+

请求追踪与失败重试策略更清晰,便于排查上游抖动与限额问题。

+
+
+ +

服务保障

+

+ 稳定的网关能力与清晰的故障处理流程,配合监控与告警,降低业务中断风险。 +

+
+
+ +

透明计费

+

+ 计价规则与用量明细可追溯,结算逻辑可核对,避免「看不清、对不上」的账单困扰。 +

+
+
+
+
+ +
+
+
+

几分钟完成接入

+

+ 注册账号 → 配置上游渠道与模型 → 创建 API 密钥,即可在现有应用中替换基地址开始调用。 +

+ +
+
+
+
+ + + diff --git a/web/classic/public/logo.png b/web/classic/public/logo.png index 851556f62db5..02937172b371 100644 Binary files a/web/classic/public/logo.png and b/web/classic/public/logo.png differ diff --git a/web/classic/src/App.jsx b/web/classic/src/App.jsx index a5d1ebc00b32..ed842d8e7fb5 100644 --- a/web/classic/src/App.jsx +++ b/web/classic/src/App.jsx @@ -55,6 +55,14 @@ const Dashboard = lazy(() => import('./pages/Dashboard')); const About = lazy(() => import('./pages/About')); const UserAgreement = lazy(() => import('./pages/UserAgreement')); const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy')); +const DocsRedirect = lazy(() => import('./pages/Docs/Redirect')); +const IntegrationHome = lazy(() => import('./pages/Docs/IntegrationHome')); +const IntegrationClaudeCode = lazy(() => import('./pages/Docs/IntegrationClaudeCode')); +const IntegrationCodex = lazy(() => import('./pages/Docs/IntegrationCodex')); +const IntegrationGeminiCli = lazy(() => import('./pages/Docs/IntegrationGeminiCli')); +const IntegrationOpenCode = lazy(() => import('./pages/Docs/IntegrationOpenCode')); +const IntegrationTrace = lazy(() => import('./pages/Docs/IntegrationTrace')); +const IntegrationCodeBuddy = lazy(() => import('./pages/Docs/IntegrationCodeBuddy')); function DynamicOAuth2Callback() { const { provider } = useParams(); @@ -358,6 +366,70 @@ function App() { } /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> + } key={location.pathname}> + + + } + /> { } }; + const getChartTimeRangeSec = () => ({ + start_timestamp: Date.parse(dashboardData.inputs.start_timestamp) / 1000, + end_timestamp: Date.parse(dashboardData.inputs.end_timestamp) / 1000, + }); + const initChart = async () => { await dashboardData.loadQuotaData().then((data) => { if (data && data.length > 0) { - dashboardCharts.updateChartData(data); + dashboardCharts.updateChartData(data, getChartTimeRangeSec()); } }); await loadUserData(); @@ -108,7 +113,7 @@ const Dashboard = () => { const handleRefresh = async () => { const data = await dashboardData.refresh(); if (data && data.length > 0) { - dashboardCharts.updateChartData(data); + dashboardCharts.updateChartData(data, getChartTimeRangeSec()); } await loadUserData(); }; diff --git a/web/classic/src/components/docs/integration/DocCallout.jsx b/web/classic/src/components/docs/integration/DocCallout.jsx new file mode 100644 index 000000000000..3db557ca995b --- /dev/null +++ b/web/classic/src/components/docs/integration/DocCallout.jsx @@ -0,0 +1,47 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Banner, Typography } from '@douyinfe/semi-ui'; + +const DocCallout = ({ variant = 'info', title, children, className = '' }) => { + const type = variant === 'warning' ? 'warning' : 'info'; + + return ( + + {title ? ( + + {title} + + ) : null} + + {children} + + + } + /> + ); +}; + +export default DocCallout; diff --git a/web/classic/src/components/docs/integration/DocCodeBlock.jsx b/web/classic/src/components/docs/integration/DocCodeBlock.jsx new file mode 100644 index 000000000000..2882d2bee15d --- /dev/null +++ b/web/classic/src/components/docs/integration/DocCodeBlock.jsx @@ -0,0 +1,97 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Button, Toast, Typography } from '@douyinfe/semi-ui'; +import { IconCopy } from '@douyinfe/semi-icons'; +import { useTranslation } from 'react-i18next'; +import { copy } from '../../../helpers'; + +const blockStyle = { + position: 'relative', + borderRadius: '8px', + border: '1px solid var(--semi-color-border)', + backgroundColor: 'var(--semi-color-fill-0)', + overflow: 'hidden', +}; + +const filenameStyle = { + padding: '8px 16px', + borderBottom: '1px solid var(--semi-color-border)', + fontFamily: 'Consolas, Monaco, monospace', + fontSize: '12px', + color: 'var(--semi-color-text-2)', + backgroundColor: 'var(--semi-color-fill-1)', +}; + +const preStyle = { + margin: 0, + padding: '16px 48px 16px 16px', + overflowX: 'auto', + fontSize: '13px', + lineHeight: 1.6, + fontFamily: 'Consolas, Monaco, monospace', + color: 'var(--semi-color-text-0)', + whiteSpace: 'pre', +}; + +const DocCodeBlock = ({ code, filename, className = '' }) => { + const { t } = useTranslation(); + + const handleCopy = async () => { + const ok = await copy(code); + if (ok) { + Toast.success(t('已复制')); + } + }; + + return ( +
+ {filename ?
{filename}
: null} +
+ ); +}; + +export const DocInlineCode = ({ children }) => ( + + {children} + +); + +export default DocCodeBlock; diff --git a/web/classic/src/components/docs/integration/DocSection.jsx b/web/classic/src/components/docs/integration/DocSection.jsx new file mode 100644 index 000000000000..0e09843870c7 --- /dev/null +++ b/web/classic/src/components/docs/integration/DocSection.jsx @@ -0,0 +1,85 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Typography } from '@douyinfe/semi-ui'; + +export const DocStepList = ({ steps, className = '' }) => ( +
    + {steps.map((step, index) => ( +
  1. + {step} +
  2. + ))} +
+); + +export const DocSection = ({ title, children, id }) => ( +
+ + {title} + +
{children}
+
+); + +export const DocPageHeader = ({ title, description }) => ( +
+ + {title} + + + {description} + +
+); + +export const DocBulletList = ({ items }) => ( +
    + {items.map((item, index) => ( +
  • + {item} +
  • + ))} +
+); diff --git a/web/classic/src/components/docs/integration/IntegrationHome.jsx b/web/classic/src/components/docs/integration/IntegrationHome.jsx new file mode 100644 index 000000000000..c0a1e9694774 --- /dev/null +++ b/web/classic/src/components/docs/integration/IntegrationHome.jsx @@ -0,0 +1,116 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Card, Typography } from '@douyinfe/semi-ui'; +import { ArrowRight } from 'lucide-react'; +import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import DocCallout from './DocCallout'; +import { DocInlineCode } from './DocCodeBlock'; +import { + FACEAPI_BASE_URL, + FACEAPI_BRAND, + FACEAPI_WEBSITE, + INTEGRATION_NAV_ITEMS, +} from './constants'; + +const IntegrationHome = () => { + const { t } = useTranslation(); + + return ( +
+
+ + {t('FaceCloud Integration Guides')} + + + {t( + 'Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.', + )} + +
+ + + {t('You need a FaceCloud API key. Create one in the dashboard, then replace')}{' '} + sk-xxxx{' '} + {t('in the examples below with your real key. API base URL:')}{' '} + {FACEAPI_BASE_URL} + + +
+ {INTEGRATION_NAV_ITEMS.map((item) => { + const Icon = item.icon; + + return ( + + +
+
+
+ {t(item.titleKey)} +
+ + {t(item.descriptionKey)} + + + {t('View guide')} + + +
+ + ); + })} +
+ + + {t('Powered by')}{' '} + + {FACEAPI_BRAND} + + . {t('For model availability and pricing, visit the pricing page or dashboard.')} + +
+ ); +}; + +export default IntegrationHome; diff --git a/web/classic/src/components/docs/integration/IntegrationLayout.jsx b/web/classic/src/components/docs/integration/IntegrationLayout.jsx new file mode 100644 index 000000000000..59ea5fc23a9b --- /dev/null +++ b/web/classic/src/components/docs/integration/IntegrationLayout.jsx @@ -0,0 +1,168 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React, { useState } from 'react'; +import { Button, SideSheet, Typography } from '@douyinfe/semi-ui'; +import { IconMenu } from '@douyinfe/semi-icons'; +import { Link, useLocation } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { useIsMobile } from '../../../hooks/common/useIsMobile'; +import { + FACEAPI_BRAND, + FACEAPI_WEBSITE, + INTEGRATION_HOME_PATH, + INTEGRATION_NAV_ITEMS, +} from './constants'; + +const navLinkStyle = (active) => ({ + display: 'flex', + alignItems: 'flex-start', + gap: '8px', + padding: '8px 12px', + borderRadius: '6px', + textDecoration: 'none', + fontSize: '14px', + fontWeight: active ? 600 : 400, + color: active ? 'var(--semi-color-primary)' : 'var(--semi-color-text-1)', + backgroundColor: active ? 'var(--semi-color-primary-light-default)' : 'transparent', + marginBottom: '4px', +}); + +const IntegrationSidebar = ({ onNavigate }) => { + const { t } = useTranslation(); + const { pathname } = useLocation(); + + return ( + + ); +}; + +const IntegrationLayout = ({ children }) => { + const { t } = useTranslation(); + const isMobile = useIsMobile(); + const [mobileOpen, setMobileOpen] = useState(false); + + return ( +
+ {isMobile ? ( +
+
+ {FACEAPI_BRAND} + + {t('Integration')} + +
+
+ ) : null} + +
+ {!isMobile ? ( + + ) : null} + +
{children}
+
+
+ ); +}; + +export default IntegrationLayout; diff --git a/web/classic/src/components/docs/integration/constants.js b/web/classic/src/components/docs/integration/constants.js new file mode 100644 index 000000000000..86f53c42b4c4 --- /dev/null +++ b/web/classic/src/components/docs/integration/constants.js @@ -0,0 +1,77 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import { Bot, Code2, Sparkles, Terminal, Workflow, Wrench } from 'lucide-react'; + +export const FACEAPI_BASE_URL = 'https://www.faceapi.ai'; +export const FACEAPI_WEBSITE = 'https://www.faceapi.ai'; +export const FACEAPI_BRAND = 'FaceCloud'; + +export const INTEGRATION_HOME_PATH = '/docs/integration'; + +export const INTEGRATION_NAV_ITEMS = [ + { + id: 'claude-code', + path: '/docs/integration/claude-code', + titleKey: 'Claude Code', + descriptionKey: + 'Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.', + icon: Bot, + }, + { + id: 'codex', + path: '/docs/integration/codex', + titleKey: 'Codex', + descriptionKey: + 'Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.', + icon: Code2, + }, + { + id: 'gemini-cli', + path: '/docs/integration/gemini-cli', + titleKey: 'Gemini CLI', + descriptionKey: + 'Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.', + icon: Sparkles, + }, + { + id: 'open-code', + path: '/docs/integration/open-code', + titleKey: 'OpenCode', + descriptionKey: + 'Add FaceCloud as a custom provider in OpenCode configuration.', + icon: Workflow, + }, + { + id: 'trace', + path: '/docs/integration/trace', + titleKey: 'Trace (Trae IDE)', + descriptionKey: + 'Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.', + icon: Terminal, + }, + { + id: 'code-buddy', + path: '/docs/integration/code-buddy', + titleKey: 'Code Buddy', + descriptionKey: + 'Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.', + icon: Wrench, + }, +]; diff --git a/web/classic/src/components/docs/integration/pages/ClaudeCodePage.jsx b/web/classic/src/components/docs/integration/pages/ClaudeCodePage.jsx new file mode 100644 index 000000000000..4db0fbeac817 --- /dev/null +++ b/web/classic/src/components/docs/integration/pages/ClaudeCodePage.jsx @@ -0,0 +1,104 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import DocCallout from '../DocCallout'; +import DocCodeBlock, { DocInlineCode } from '../DocCodeBlock'; +import { DocPageHeader, DocSection, DocStepList, DocBulletList } from '../DocSection'; +import { FACEAPI_BASE_URL } from '../constants'; + +const CLAUDE_SETTINGS = `{ + "env": { + "ANTHROPIC_BASE_URL": "${FACEAPI_BASE_URL}", + "ANTHROPIC_AUTH_TOKEN": "sk-xxxx", + "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1", + "CLAUDE_CODE_ATTRIBUTION_HEADER": "0" + } +}`; + +const ClaudeCodePage = () => { + const { t } = useTranslation(); + + return ( +
+ + + + {t( + 'Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.', + )} + + + + + + + + +

+ {t('Create or edit')} ~/.claude/settings.json. +

+ , + <> +

{t('Add the following environment variables:')}

+ + , + <> +

+ {t('Replace')} sk-xxxx {t('with your FaceCloud API key.')} +

+ , +

{t('Run claude in a new terminal session to verify the connection.')}

, + ]} + /> +
+ + + + ANTHROPIC_BASE_URL — {t('FaceCloud gateway URL')} + , + <> + ANTHROPIC_AUTH_TOKEN — {t('Your FaceCloud API key')} + , + <> + CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS —{' '} + {t('Disables experimental beta headers for third-party gateways')} + , + <> + CLAUDE_CODE_ATTRIBUTION_HEADER —{' '} + {t('Disables attribution header when using a proxy')} + , + ]} + /> + +
+ ); +}; + +export default ClaudeCodePage; diff --git a/web/classic/src/components/docs/integration/pages/CodeBuddyPage.jsx b/web/classic/src/components/docs/integration/pages/CodeBuddyPage.jsx new file mode 100644 index 000000000000..0963d6a05975 --- /dev/null +++ b/web/classic/src/components/docs/integration/pages/CodeBuddyPage.jsx @@ -0,0 +1,103 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Typography } from '@douyinfe/semi-ui'; +import { useTranslation } from 'react-i18next'; +import DocCallout from '../DocCallout'; +import DocCodeBlock, { DocInlineCode } from '../DocCodeBlock'; +import { DocPageHeader, DocSection, DocStepList, DocBulletList } from '../DocSection'; +import { FACEAPI_BASE_URL } from '../constants'; + +const CODEBUDDY_SHELL = `export CODEBUDDY_API_KEY="sk-xxxx" +export CODEBUDDY_BASE_URL="${FACEAPI_BASE_URL}/v1" +codebuddy --model your-model-name`; + +const CODEBUDDY_SETTINGS = `{ + "env": { + "CODEBUDDY_API_KEY": "sk-xxxx", + "CODEBUDDY_BASE_URL": "${FACEAPI_BASE_URL}/v1" + } +}`; + +const CodeBuddyPage = () => { + const { t } = useTranslation(); + + return ( +
+ + + + {t( + 'CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.', + )} + + + + +

{t('Export the following variables in your terminal or shell profile:')}

+ + , + <> +

+ {t('Replace')} sk-xxxx{' '} + {t('and your-model-name with your API key and desired model.')} +

+ , +

{t('Run codebuddy from the same shell session to use FaceCloud.')}

, + ]} + /> +
+ + + + {t( + 'If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:', + )} + + + + + + + CODEBUDDY_API_KEY — {t('Your FaceCloud API key')} + , + <> + CODEBUDDY_BASE_URL —{' '} + {t('OpenAI-compatible base URL at {{url}}', { + url: `${FACEAPI_BASE_URL}/v1`, + })} + , + ]} + /> + +
+ ); +}; + +export default CodeBuddyPage; diff --git a/web/classic/src/components/docs/integration/pages/CodexPage.jsx b/web/classic/src/components/docs/integration/pages/CodexPage.jsx new file mode 100644 index 000000000000..91e044470e2b --- /dev/null +++ b/web/classic/src/components/docs/integration/pages/CodexPage.jsx @@ -0,0 +1,107 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Typography } from '@douyinfe/semi-ui'; +import { useTranslation } from 'react-i18next'; +import DocCallout from '../DocCallout'; +import DocCodeBlock, { DocInlineCode } from '../DocCodeBlock'; +import { DocPageHeader, DocSection, DocStepList, DocBulletList } from '../DocSection'; +import { FACEAPI_BASE_URL } from '../constants'; + +const CODEX_CONFIG = `model = "o3" +model_provider = "openai-chat-completions" + +[model_providers.openai-chat-completions] +name = "FaceCloud" +base_url = "${FACEAPI_BASE_URL}/v1" +env_key = "FACEAPI_API_KEY" +wire_api = "chat"`; + +const CODEX_ENV = `export FACEAPI_API_KEY="sk-xxxx"`; + +const CodexPage = () => { + const { t } = useTranslation(); + + return ( +
+ + + + {t( + 'Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.', + )} + + + + + + {t('Reload your shell or run source on the file after exporting the variable.')} + + + + + +

+ {t('Create or edit')} ~/.codex/config.toml. +

+ , + <> +

{t('Add the FaceCloud provider configuration:')}

+ + , +

+ {t( + 'Start Codex and select the FaceCloud provider. Adjust model to one available on your account.', + )} +

, + ]} + /> +
+ + + + base_url —{' '} + {t('OpenAI-compatible endpoint at {{url}}', { + url: `${FACEAPI_BASE_URL}/v1`, + })} + , + <> + env_key — {t('Environment variable holding your API key')} + , + <> + wire_api — {t('Use chat completions wire format')} + , + ]} + /> + +
+ ); +}; + +export default CodexPage; diff --git a/web/classic/src/components/docs/integration/pages/GeminiCliPage.jsx b/web/classic/src/components/docs/integration/pages/GeminiCliPage.jsx new file mode 100644 index 000000000000..472ab19a1d80 --- /dev/null +++ b/web/classic/src/components/docs/integration/pages/GeminiCliPage.jsx @@ -0,0 +1,91 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import DocCallout from '../DocCallout'; +import DocCodeBlock, { DocInlineCode } from '../DocCodeBlock'; +import { DocPageHeader, DocSection, DocStepList, DocBulletList } from '../DocSection'; +import { FACEAPI_BASE_URL } from '../constants'; + +const GEMINI_ENV = `GOOGLE_GEMINI_BASE_URL=${FACEAPI_BASE_URL}/gemini +GEMINI_API_KEY=sk-xxxx +GEMINI_MODEL=gemini-2.5-flash`; + +const GeminiCliPage = () => { + const { t } = useTranslation(); + + return ( +
+ + + + {t( + 'Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.', + )} + + + + +

+ {t('Create or edit')} ~/.env {t('in your home directory.')} +

+ , + <> +

{t('Add the following variables:')}

+ + , + <> +

+ {t('Replace')} sk-xxxx{' '} + {t('with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.')} +

+ , +

{t('Run the Gemini CLI and send a test prompt to confirm connectivity.')}

, + ]} + /> +
+ + + + GOOGLE_GEMINI_BASE_URL — {t('FaceCloud Gemini-compatible base URL')} + , + <> + GEMINI_API_KEY — {t('Your FaceCloud API key')} + , + <> + GEMINI_MODEL — {t('Default model name for requests')} + , + ]} + /> + +
+ ); +}; + +export default GeminiCliPage; diff --git a/web/classic/src/components/docs/integration/pages/OpenCodePage.jsx b/web/classic/src/components/docs/integration/pages/OpenCodePage.jsx new file mode 100644 index 000000000000..0905de891175 --- /dev/null +++ b/web/classic/src/components/docs/integration/pages/OpenCodePage.jsx @@ -0,0 +1,94 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Typography } from '@douyinfe/semi-ui'; +import { useTranslation } from 'react-i18next'; +import DocCallout from '../DocCallout'; +import DocCodeBlock, { DocInlineCode } from '../DocCodeBlock'; +import { DocPageHeader, DocSection, DocStepList } from '../DocSection'; +import { FACEAPI_BASE_URL } from '../constants'; + +const OPENCODE_CONFIG = `{ + "providers": { + "facecloud": { + "baseURL": "${FACEAPI_BASE_URL}/v1", + "apiKey": "sk-xxxx" + } + }, + "defaultProvider": "facecloud" +}`; + +const OpenCodePage = () => { + const { t } = useTranslation(); + + return ( +
+ + + + {t( + 'OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.', + )} + + + + +

+ {t('Create the config directory if it does not exist:')}{' '} + ~/.config/opencode/ +

+ , + <> +

{t('Edit opencode.json with the FaceCloud provider:')}

+ + , + <> +

+ {t('Replace')} sk-xxxx {t('with your FaceCloud API key.')} +

+ , +

{t('Launch OpenCode and verify that requests route through FaceCloud.')}

, + ]} + /> +
+ + + + {t( + 'Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.', + )} + + + +
+ ); +}; + +export default OpenCodePage; diff --git a/web/classic/src/components/docs/integration/pages/TracePage.jsx b/web/classic/src/components/docs/integration/pages/TracePage.jsx new file mode 100644 index 000000000000..98eb4452227d --- /dev/null +++ b/web/classic/src/components/docs/integration/pages/TracePage.jsx @@ -0,0 +1,121 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Table, Typography } from '@douyinfe/semi-ui'; +import { useTranslation } from 'react-i18next'; +import DocCallout from '../DocCallout'; +import DocCodeBlock, { DocInlineCode } from '../DocCodeBlock'; +import { DocPageHeader, DocSection, DocStepList } from '../DocSection'; +import { FACEAPI_BASE_URL } from '../constants'; + +const OPENAI_ENDPOINT = `${FACEAPI_BASE_URL}/v1/chat/completions`; +const ANTHROPIC_ENDPOINT = `${FACEAPI_BASE_URL}/v1/messages`; + +const TracePage = () => { + const { t } = useTranslation(); + + const endpointColumns = [ + { + title: t('Provider'), + dataIndex: 'provider', + width: 120, + }, + { + title: t('Full endpoint URL'), + dataIndex: 'url', + render: (url) => ( + + {url} + + ), + }, + ]; + + const endpointData = [ + { key: 'openai', provider: 'OpenAI', url: OPENAI_ENDPOINT }, + { key: 'anthropic', provider: 'Anthropic', url: ANTHROPIC_ENDPOINT }, + ]; + + return ( +
+ + + + {t( + 'Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.', + )} + + + + + {t('Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.')} +

, + <> +

{t('For OpenAI-compatible models, set the request URL to:')}

+ + , + <> +

+ {t('Set the API key to your FaceCloud key (')} sk-xxxx + {t(') and choose a model name available on your account.')} +

+ , + ]} + /> +
+ + + + {t('Add a custom Anthropic provider or Claude model in Trae settings.')} +

, + <> +

{t('Set the messages endpoint to:')}

+ + , +

+ {t('Use Bearer authentication with your FaceCloud API key in the Authorization header.')} +

, + ]} + /> +
+ + + + + + + {t( + 'If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.', + )} + + + ); +}; + +export default TracePage; diff --git a/web/classic/src/components/layout/headerbar/index.jsx b/web/classic/src/components/layout/headerbar/index.jsx index 81b51d7fe486..87d61fd24082 100644 --- a/web/classic/src/components/layout/headerbar/index.jsx +++ b/web/classic/src/components/layout/headerbar/index.jsx @@ -62,7 +62,12 @@ const HeaderBar = ({ onMobileMenuToggle, drawerOpen }) => { getUnreadKeys, } = useNotifications(statusState); - const { mainNavLinks } = useNavigation(t, docsLink, headerNavModules); + const { mainNavLinks } = useNavigation( + t, + docsLink, + headerNavModules, + statusState?.status?.server_address, + ); return (
diff --git a/web/classic/src/components/playground/configStorage.js b/web/classic/src/components/playground/configStorage.js index d201ed6af93e..8d54cfbd00be 100644 --- a/web/classic/src/components/playground/configStorage.js +++ b/web/classic/src/components/playground/configStorage.js @@ -21,6 +21,7 @@ import { STORAGE_KEYS, DEFAULT_CONFIG, } from '../../constants/playground.constants'; +import { normalizeSamplingParameters } from '../../helpers/playgroundParameter'; const MESSAGES_STORAGE_KEY = 'playground_messages'; @@ -75,10 +76,10 @@ export const loadConfig = () => { ? parsedConfig?.inputs?.max_tokens : parsedMaxTokens, }, - parameterEnabled: { + parameterEnabled: normalizeSamplingParameters({ ...DEFAULT_CONFIG.parameterEnabled, ...parsedConfig.parameterEnabled, - }, + }), showDebugPanel: parsedConfig.showDebugPanel || DEFAULT_CONFIG.showDebugPanel, customRequestMode: diff --git a/web/classic/src/components/settings/DashboardSetting.jsx b/web/classic/src/components/settings/DashboardSetting.jsx index 7bf4249437ab..2e483617db43 100644 --- a/web/classic/src/components/settings/DashboardSetting.jsx +++ b/web/classic/src/components/settings/DashboardSetting.jsx @@ -46,7 +46,7 @@ const DashboardSetting = () => { /* 数据看板 */ DataExportEnabled: false, - DataExportDefaultTime: 'hour', + DataExportDefaultTime: 'day', DataExportInterval: 5, }); diff --git a/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx b/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx index 5d748c0f5343..be46f82ba7c2 100644 --- a/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx +++ b/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx @@ -43,6 +43,7 @@ import { CHANNEL_OPTIONS, MODEL_FETCHABLE_CHANNEL_TYPES, } from '../../../constants'; +import { openChannelConsumptionModal } from './modals/ChannelConsumptionModal'; import { parseUpstreamUpdateMeta } from '../../../hooks/channels/upstreamUpdateUtils'; import { IconTreeTriangleDown, @@ -725,6 +726,12 @@ export const getChannelsColumns = ({ }); }, }, + { + node: 'item', + name: t('渠道消费统计'), + type: 'tertiary', + onClick: () => openChannelConsumptionModal({ t, record }), + }, ]; if (upstreamUpdateMeta.supported) { diff --git a/web/classic/src/components/table/channels/modals/ChannelConsumptionModal.jsx b/web/classic/src/components/table/channels/modals/ChannelConsumptionModal.jsx new file mode 100644 index 000000000000..910da8cd86e0 --- /dev/null +++ b/web/classic/src/components/table/channels/modals/ChannelConsumptionModal.jsx @@ -0,0 +1,261 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { + Button, + DatePicker, + Descriptions, + Input, + Modal, + Space, + Spin, + Typography, +} from '@douyinfe/semi-ui'; +import dayjs from 'dayjs'; +import { API, showError } from '../../../../helpers'; +import { renderQuota } from '../../../../helpers/render'; +import { DATE_RANGE_PRESETS } from '../../../../constants/console.constants'; + +const defaultDateRange = () => [ + dayjs().startOf('month').toDate(), + dayjs().endOf('day').toDate(), +]; + +const datePresets = DATE_RANGE_PRESETS.map((preset) => ({ + text: preset.text, + start: preset.start(), + end: preset.end(), +})); + +function ChannelConsumptionContent({ t, record }) { + const [dateRange, setDateRange] = useState(defaultDateRange); + const [userIdInput, setUserIdInput] = useState(''); + const [usernameInput, setUsernameInput] = useState(''); + const [appliedUserId, setAppliedUserId] = useState(null); + const [appliedUsername, setAppliedUsername] = useState(''); + const [loading, setLoading] = useState(false); + const [data, setData] = useState(null); + + const userFilterActive = appliedUserId != null || !!appliedUsername; + + const fetchConsumption = useCallback(async () => { + if (!record?.id) return; + const start = dateRange?.[0]; + const end = dateRange?.[1]; + if (!start || !end) { + showError(t('请选择时间范围')); + return; + } + + const params = { + start_timestamp: Math.floor(new Date(start).getTime() / 1000), + end_timestamp: Math.floor(new Date(end).getTime() / 1000), + }; + if (appliedUserId) { + params.user_id = appliedUserId; + } else if (appliedUsername) { + params.username = appliedUsername; + } + + setLoading(true); + try { + const res = await API.get(`/api/channel/${record.id}/consumption`, { + params, + }); + const { success, message, data: payload } = res.data; + if (!success) { + throw new Error(message || t('加载消费统计失败')); + } + setData(payload); + } catch (error) { + showError(error?.message || String(error)); + setData(null); + } finally { + setLoading(false); + } + }, [appliedUserId, appliedUsername, dateRange, record?.id, t]); + + useEffect(() => { + fetchConsumption(); + }, [fetchConsumption]); + + const applyUserFilter = () => { + const trimmedUsername = usernameInput.trim(); + const parsedUserId = Number.parseInt(userIdInput.trim(), 10); + if (userIdInput.trim()) { + if (!Number.isFinite(parsedUserId) || parsedUserId <= 0) { + showError(t('用户ID无效')); + return; + } + setAppliedUserId(parsedUserId); + setAppliedUsername(''); + } else { + setAppliedUserId(null); + setAppliedUsername(trimmedUsername); + } + }; + + const clearUserFilter = () => { + setUserIdInput(''); + setUsernameInput(''); + setAppliedUserId(null); + setAppliedUsername(''); + }; + + const totalTokens = useMemo(() => { + if (!data) return 0; + return ( + Number(data.prompt_tokens || 0) + Number(data.completion_tokens || 0) + ); + }, [data]); + + return ( +
+ + {record?.name} (#{record?.id}) + + +
+ + {t('时间范围')} + + setDateRange(value)} + presets={datePresets.map((preset) => ({ + text: t(preset.text), + start: preset.start, + end: preset.end, + }))} + /> +
+ +
+ + {t('按用户筛选(可选)')} + + + + + + {userFilterActive ? ( + + ) : null} + + {userFilterActive ? ( + + {appliedUserId != null + ? `${t('用户ID')}: ${appliedUserId}` + : `${t('用户名')}: ${appliedUsername}`} + + ) : null} +
+ + + + + + + {data ? ( + + ) : ( + !loading && ( + {t('暂无数据')} + ) + )} + +
+ ); +} + +export function openChannelConsumptionModal({ t, record }) { + const tt = typeof t === 'function' ? t : (v) => v; + + Modal.info({ + title: tt('渠道消费统计'), + width: 560, + centered: true, + content: , + footer: ( +
+ +
+ ), + }); +} \ No newline at end of file diff --git a/web/classic/src/components/table/usage-logs/UsageLogsFilters.jsx b/web/classic/src/components/table/usage-logs/UsageLogsFilters.jsx index 8d0d837ca53b..8f2bdd292b10 100644 --- a/web/classic/src/components/table/usage-logs/UsageLogsFilters.jsx +++ b/web/classic/src/components/table/usage-logs/UsageLogsFilters.jsx @@ -27,6 +27,8 @@ const LogsFilters = ({ formInitValues, setFormApi, refresh, + exportLogs, + exportingLogs, setShowColumnSelector, formApi, setLogType, @@ -183,6 +185,15 @@ const LogsFilters = ({ > {t('列设置')} + diff --git a/web/classic/src/components/table/users/UsersColumnDefs.jsx b/web/classic/src/components/table/users/UsersColumnDefs.jsx index 2e0d171ae4e5..ca63906b8a8c 100644 --- a/web/classic/src/components/table/users/UsersColumnDefs.jsx +++ b/web/classic/src/components/table/users/UsersColumnDefs.jsx @@ -216,6 +216,7 @@ const renderOperations = ( showResetPasskeyModal, showResetTwoFAModal, showUserSubscriptionsModal, + showUserBillExportModal, t, }, ) => { @@ -224,6 +225,14 @@ const renderOperations = ( } const moreMenu = [ + { + node: 'item', + name: t('导出用量CSV'), + onClick: () => showUserBillExportModal(record), + }, + { + node: 'divider', + }, { node: 'item', name: t('订阅管理'), @@ -316,6 +325,7 @@ export const getUsersColumns = ({ showResetPasskeyModal, showResetTwoFAModal, showUserSubscriptionsModal, + showUserBillExportModal, }) => { return [ { @@ -383,6 +393,7 @@ export const getUsersColumns = ({ showResetPasskeyModal, showResetTwoFAModal, showUserSubscriptionsModal, + showUserBillExportModal, t, }), }, diff --git a/web/classic/src/components/table/users/UsersTable.jsx b/web/classic/src/components/table/users/UsersTable.jsx index e0f8a9cec343..f01f71e71d0c 100644 --- a/web/classic/src/components/table/users/UsersTable.jsx +++ b/web/classic/src/components/table/users/UsersTable.jsx @@ -32,6 +32,7 @@ import DeleteUserModal from './modals/DeleteUserModal'; import ResetPasskeyModal from './modals/ResetPasskeyModal'; import ResetTwoFAModal from './modals/ResetTwoFAModal'; import UserSubscriptionsModal from './modals/UserSubscriptionsModal'; +import UserBillExportModal from './modals/UserBillExportModal'; const UsersTable = (usersData) => { const { @@ -64,6 +65,8 @@ const UsersTable = (usersData) => { const [showResetTwoFAModal, setShowResetTwoFAModal] = useState(false); const [showUserSubscriptionsModal, setShowUserSubscriptionsModal] = useState(false); + const [showUserBillExportModal, setShowUserBillExportModal] = + useState(false); // Modal handlers const showPromoteUserModal = (user) => { @@ -102,6 +105,11 @@ const UsersTable = (usersData) => { setShowUserSubscriptionsModal(true); }; + const showUserBillExportUserModal = (user) => { + setModalUser(user); + setShowUserBillExportModal(true); + }; + // Modal confirm handlers const handlePromoteConfirm = () => { manageUser(modalUser.id, 'promote', modalUser); @@ -141,6 +149,7 @@ const UsersTable = (usersData) => { showResetPasskeyModal: showResetPasskeyUserModal, showResetTwoFAModal: showResetTwoFAUserModal, showUserSubscriptionsModal: showUserSubscriptionsUserModal, + showUserBillExportModal: showUserBillExportUserModal, }); }, [ t, @@ -153,6 +162,7 @@ const UsersTable = (usersData) => { showResetPasskeyUserModal, showResetTwoFAUserModal, showUserSubscriptionsUserModal, + showUserBillExportUserModal, ]); // Handle compact mode by removing fixed positioning @@ -260,6 +270,13 @@ const UsersTable = (usersData) => { t={t} onSuccess={() => refresh?.()} /> + + setShowUserBillExportModal(false)} + user={modalUser} + t={t} + /> ); }; diff --git a/web/classic/src/components/table/users/modals/UserBillExportModal.jsx b/web/classic/src/components/table/users/modals/UserBillExportModal.jsx new file mode 100644 index 000000000000..18a88fdf2e86 --- /dev/null +++ b/web/classic/src/components/table/users/modals/UserBillExportModal.jsx @@ -0,0 +1,164 @@ +/* +Copyright (C) 2025 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React, { useEffect, useState } from 'react'; +import { + Button, + Input, + InputNumber, + Modal, + Select, + Space, + Typography, +} from '@douyinfe/semi-ui'; +import { downloadAdminUserLogExport, showError, showSuccess } from '../../../../helpers'; + +const { Text } = Typography; + +const MONTH_OPTIONS = Array.from({ length: 12 }, (_, i) => ({ + label: String(i + 1), + value: i + 1, +})); + +const UserBillExportModal = ({ visible, onCancel, user, t }) => { + const now = new Date(); + const [year, setYear] = useState(now.getFullYear()); + const [month, setMonth] = useState(now.getMonth() + 1); + const [timezone, setTimezone] = useState(''); + const [loadingBill, setLoadingBill] = useState(false); + const [loadingDetails, setLoadingDetails] = useState(false); + const [loadingAll, setLoadingAll] = useState(false); + + useEffect(() => { + if (!visible) return; + const d = new Date(); + setYear(d.getFullYear()); + setMonth(d.getMonth() + 1); + setTimezone(''); + }, [visible]); + + if (!user) return null; + + const run = async (kind, setBusy) => { + const y = Number(year); + const m = Number(month); + if (!Number.isFinite(y) || y < 1970 || y > 9999) { + showError(t('年份无效')); + return; + } + if (!Number.isFinite(m) || m < 1 || m > 12) { + showError(t('月份无效')); + return; + } + setBusy(true); + try { + await downloadAdminUserLogExport(kind, { + userId: user.id, + year: y, + month: m, + timezone: timezone.trim() || undefined, + }); + showSuccess(t('已开始下载')); + onCancel(); + } catch (e) { + showError(e?.message || t('导出失败')); + } finally { + setBusy(false); + } + }; + + return ( + + + + {t('用量导出说明', { + name: user.username, + id: user.id, + })} + +
+ {t('年份')} + setYear(v ?? new Date().getFullYear())} + /> +
+
+ {t('月份')} + setTimezone(v)} + placeholder={t('例如 Asia/Shanghai')} + /> + + {t('用量导出时区说明')} + +
+ + + + + +
+
+ ); +}; + +export default UserBillExportModal; diff --git a/web/classic/src/constants/playground.constants.js b/web/classic/src/constants/playground.constants.js index 9ba88621cbd1..c20a7d66d81b 100644 --- a/web/classic/src/constants/playground.constants.js +++ b/web/classic/src/constants/playground.constants.js @@ -96,8 +96,8 @@ export const DEFAULT_CONFIG = { imageUrls: [''], }, parameterEnabled: { - temperature: true, - top_p: true, + temperature: false, + top_p: false, max_tokens: false, frequency_penalty: true, presence_penalty: true, diff --git a/web/classic/src/helpers/dashboard.jsx b/web/classic/src/helpers/dashboard.jsx index a7a30bf6719f..ca80aba072a4 100644 --- a/web/classic/src/helpers/dashboard.jsx +++ b/web/classic/src/helpers/dashboard.jsx @@ -39,7 +39,7 @@ import { // ========== 时间相关工具函数 ========== export const getDefaultTime = () => { - return localStorage.getItem(STORAGE_KEYS.DATA_EXPORT_DEFAULT_TIME) || 'hour'; + return localStorage.getItem(STORAGE_KEYS.DATA_EXPORT_DEFAULT_TIME) || 'day'; }; export const getTimeInterval = (timeType, isSeconds = false) => { @@ -49,17 +49,56 @@ export const getTimeInterval = (timeType, isSeconds = false) => { }; export const getInitialTimestamp = () => { + return getInitialDashboardRangeStrings().start_timestamp; +}; + +function dashboardStartOfDay(date) { + const d = new Date(date); + d.setHours(0, 0, 0, 0); + return d; +} + +function dashboardEndOfDay(date) { + const d = new Date(date); + d.setHours(23, 59, 59, 999); + return d; +} + +/** @param {number} numDays inclusive calendar days ending at `fromDate` */ +export const getCalendarDayRangeStrings = (numDays, fromDate = new Date()) => { + const end = dashboardEndOfDay(fromDate); + const startBase = new Date(fromDate); + startBase.setDate(startBase.getDate() - (numDays - 1)); + const start = dashboardStartOfDay(startBase); + return { + start_timestamp: timestamp2string(Math.floor(start.getTime() / 1000)), + end_timestamp: timestamp2string(Math.floor(end.getTime() / 1000)), + }; +}; + +/** Default dashboard filter range: 00:00 start, 23:59:59 end, by saved granularity preset. */ +export const getInitialDashboardRangeStrings = () => { const defaultTime = getDefaultTime(); - const now = new Date().getTime() / 1000; - - switch (defaultTime) { - case 'hour': - return timestamp2string(now - 86400); - case 'week': - return timestamp2string(now - 86400 * 30); - default: - return timestamp2string(now - 86400 * 7); + const numDays = + defaultTime === 'hour' ? 1 : defaultTime === 'week' ? 30 : 7; + return getCalendarDayRangeStrings(numDays); +}; + +export const normalizeDashboardTimestampStrings = ( + start_timestamp, + end_timestamp, +) => { + const startMs = Date.parse(start_timestamp); + const endMs = Date.parse(end_timestamp); + if (Number.isNaN(startMs) || Number.isNaN(endMs)) { + return { start_timestamp, end_timestamp }; } + const start = dashboardStartOfDay(new Date(startMs)); + const end = dashboardEndOfDay(new Date(endMs)); + return { + start_timestamp: timestamp2string(Math.floor(start.getTime() / 1000)), + end_timestamp: timestamp2string(Math.floor(end.getTime() / 1000)), + }; }; // ========== 数据处理工具函数 ========== @@ -328,11 +367,33 @@ export const calculateTrendData = ( }; }; -export const aggregateDataByTimeAndModel = (data, dataExportDefaultTime) => { +/** Local midnight as Unix seconds */ +function toStartOfDaySec(sec) { + const d = new Date(sec * 1000); + d.setHours(0, 0, 0, 0); + return Math.floor(d.getTime() / 1000); +} + +/** Upper bound for axis buckets (matches default-theme dashboard charts). */ +const MAX_CHART_AXIS_BUCKETS = 400; + +export const aggregateDataByTimeAndModel = ( + data, + dataExportDefaultTime, + chartTimeRangeSec, +) => { const aggregatedData = new Map(); - // 检查数据是否跨年 - const showYear = isDataCrossYear(data.map((item) => item.created_at)); + const rangeTs = + chartTimeRangeSec && + typeof chartTimeRangeSec.start_timestamp === 'number' && + typeof chartTimeRangeSec.end_timestamp === 'number' + ? [chartTimeRangeSec.start_timestamp, chartTimeRangeSec.end_timestamp] + : []; + const showYear = isDataCrossYear([ + ...data.map((item) => item.created_at), + ...rangeTs, + ]); data.forEach((item) => { const timeKey = timestamp2string1( @@ -364,19 +425,64 @@ export const generateChartTimePoints = ( aggregatedData, data, dataExportDefaultTime, + chartTimeRangeSec, ) => { - let chartTimePoints = Array.from( + const fromData = Array.from( new Set([...aggregatedData.values()].map((d) => d.time)), ); - if (chartTimePoints.length < DEFAULTS.MAX_TREND_POINTS) { + const mergeAndSort = (a, b) => { + const merged = new Set([...a, ...b]); + return Array.from(merged).sort((x, y) => x.localeCompare(y)); + }; + + const startTs = chartTimeRangeSec?.start_timestamp; + const endTs = chartTimeRangeSec?.end_timestamp; + const hasValidRange = + typeof startTs === 'number' && + typeof endTs === 'number' && + !Number.isNaN(startTs) && + !Number.isNaN(endTs) && + startTs <= endTs; + + if (hasValidRange) { + const interval = getTimeInterval(dataExportDefaultTime, true); + let cursor = + dataExportDefaultTime === 'hour' + ? Math.floor(startTs / 3600) * 3600 + : toStartOfDaySec(startTs); + const generatedTs = []; + let guard = 0; + while (cursor <= endTs && guard < MAX_CHART_AXIS_BUCKETS) { + generatedTs.push(cursor); + cursor += interval; + guard += 1; + } + const showYear = isDataCrossYear([ + ...data.map((item) => item.created_at), + ...generatedTs, + startTs, + endTs, + ]); + const generatedLabels = generatedTs.map((ts) => + timestamp2string1(ts, dataExportDefaultTime, showYear), + ); + if (generatedLabels.length === 0) { + return fromData.sort((x, y) => x.localeCompare(y)); + } + return mergeAndSort(generatedLabels, fromData); + } + + let chartTimePoints = fromData; + + if (chartTimePoints.length < DEFAULTS.MAX_TREND_POINTS && data.length > 0) { const lastTime = Math.max(...data.map((item) => item.created_at)); const interval = getTimeInterval(dataExportDefaultTime, true); // 生成时间点数组,用于检查是否跨年 const generatedTimestamps = Array.from( { length: DEFAULTS.MAX_TREND_POINTS }, - (_, i) => lastTime - (6 - i) * interval, + (_, i) => lastTime - (DEFAULTS.MAX_TREND_POINTS - 1 - i) * interval, ); const showYear = isDataCrossYear(generatedTimestamps); diff --git a/web/classic/src/helpers/docsNavLink.js b/web/classic/src/helpers/docsNavLink.js new file mode 100644 index 000000000000..4474967c3582 --- /dev/null +++ b/web/classic/src/helpers/docsNavLink.js @@ -0,0 +1,76 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +function originFromServerAddress(serverAddress) { + if (!serverAddress || !String(serverAddress).trim()) return undefined; + try { + return new URL(String(serverAddress).trim()).origin; + } catch { + return undefined; + } +} + +/** + * @param {string} docsLink + * @param {string} [serverAddress] + * @returns {{ href: string, external: boolean }} + */ +export function resolveDocsNavLink(docsLink, serverAddress) { + const trimmed = String(docsLink).trim(); + if (!trimmed) { + return { href: '/docs', external: false }; + } + + if (trimmed.startsWith('/') && !trimmed.startsWith('//')) { + return { href: trimmed, external: false }; + } + + let absolute; + try { + if (trimmed.startsWith('//')) { + absolute = new URL(`https:${trimmed}`); + } else if (!/^https?:\/\//i.test(trimmed)) { + const base = + (typeof window !== 'undefined' && window.location.origin) || + originFromServerAddress(serverAddress) || + 'http://localhost'; + const normalizedBase = base.endsWith('/') ? base : `${base}/`; + absolute = new URL(trimmed, normalizedBase); + } else { + absolute = new URL(trimmed); + } + } catch { + return { href: trimmed, external: true }; + } + + const browserOrigin = typeof window !== 'undefined' ? window.location.origin : undefined; + const sameAsBrowser = Boolean(browserOrigin && browserOrigin === absolute.origin); + + const srvOrigin = originFromServerAddress(serverAddress); + const sameAsServer = Boolean(srvOrigin && srvOrigin === absolute.origin); + + if (sameAsBrowser || sameAsServer) { + return { + href: `${absolute.pathname}${absolute.search}${absolute.hash}`, + external: false, + }; + } + + return { href: absolute.href, external: true }; +} diff --git a/web/classic/src/helpers/index.js b/web/classic/src/helpers/index.js index a86c3bca5996..6787e531807e 100644 --- a/web/classic/src/helpers/index.js +++ b/web/classic/src/helpers/index.js @@ -22,6 +22,7 @@ export * from './auth'; export * from './utils'; export * from './base64'; export * from './api'; +export * from './userBillExport'; export * from './render'; export * from './log'; export * from './data'; diff --git a/web/classic/src/helpers/playgroundParameter.js b/web/classic/src/helpers/playgroundParameter.js new file mode 100644 index 000000000000..1b5bb4b13d6e --- /dev/null +++ b/web/classic/src/helpers/playgroundParameter.js @@ -0,0 +1,20 @@ +/** + * Temperature and top_p cannot both be enabled. + */ +export function normalizeSamplingParameters(parameterEnabled) { + if (parameterEnabled.temperature && parameterEnabled.top_p) { + return { ...parameterEnabled, top_p: false }; + } + return parameterEnabled; +} + +export function toggleSamplingParameter(parameterEnabled, paramName) { + const nextValue = !parameterEnabled[paramName]; + const updated = { ...parameterEnabled, [paramName]: nextValue }; + if (nextValue && paramName === 'temperature') { + updated.top_p = false; + } else if (nextValue && paramName === 'top_p') { + updated.temperature = false; + } + return normalizeSamplingParameters(updated); +} diff --git a/web/classic/src/helpers/usageLogsExport.js b/web/classic/src/helpers/usageLogsExport.js new file mode 100644 index 000000000000..90039e107c51 --- /dev/null +++ b/web/classic/src/helpers/usageLogsExport.js @@ -0,0 +1,97 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import { API } from './api'; + +/** + * @param {boolean} isAdminUser + * @param {{ + * logType?: number, + * username?: string, + * token_name?: string, + * model_name?: string, + * start_timestamp: number, + * end_timestamp: number, + * channel?: string|number, + * group?: string, + * request_id?: string, + * }} filters + */ +export async function downloadUsageLogsExport(isAdminUser, filters) { + const path = isAdminUser ? '/api/log/export' : '/api/log/self/export'; + const query = { + type: filters.logType ?? 0, + start_timestamp: filters.start_timestamp, + end_timestamp: filters.end_timestamp, + model_name: filters.model_name || '', + token_name: filters.token_name || '', + group: filters.group || '', + request_id: filters.request_id || '', + }; + if (isAdminUser) { + if (filters.username) query.username = filters.username; + if (filters.channel) query.channel = filters.channel; + } + try { + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + if (tz) query.timezone = tz; + } catch { + /* ignore */ + } + + const res = await API.get(path, { + params: query, + responseType: 'blob', + skipErrorHandler: true, + }); + + const ctype = String(res.headers['content-type'] || ''); + if (ctype.includes('application/json')) { + const text = await res.data.text(); + let msg = text; + try { + const j = JSON.parse(text); + if (j.message) msg = j.message; + } catch { + /* keep text */ + } + throw new Error(msg); + } + + const dispo = String(res.headers['content-disposition'] || ''); + const utf8Match = /filename\*=UTF-8''([^;]+)/i.exec(dispo); + const fallbackMatch = /filename="([^"]+)"/i.exec(dispo); + const filename = + (utf8Match?.[1] ? decodeURIComponent(utf8Match[1]) : undefined) || + fallbackMatch?.[1] || + `usage-logs-${Date.now()}.csv`; + + const url = URL.createObjectURL(res.data); + try { + const a = document.createElement('a'); + a.href = url; + a.download = filename; + a.rel = 'noopener'; + document.body.appendChild(a); + a.click(); + a.remove(); + } finally { + URL.revokeObjectURL(url); + } +} diff --git a/web/classic/src/helpers/userBillExport.js b/web/classic/src/helpers/userBillExport.js new file mode 100644 index 000000000000..4be5cbd2a949 --- /dev/null +++ b/web/classic/src/helpers/userBillExport.js @@ -0,0 +1,78 @@ +/* +Copyright (C) 2025 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import { API } from './api'; + +/** + * @param {'monthly_bill'|'consumption_details'|'monthly_bill_and_consumption_details'} kind + * @param {{ userId: number, year: number, month: number, timezone?: string }} params + */ +export async function downloadAdminUserLogExport(kind, params) { + const pathMap = { + monthly_bill: '/api/log/admin/export/monthly_bill', + consumption_details: '/api/log/admin/export/consumption_details', + monthly_bill_and_consumption_details: + '/api/log/admin/export/monthly_bill_and_consumption_details', + }; + const path = pathMap[kind]; + const query = { + user_id: params.userId, + year: params.year, + month: params.month, + }; + if (params.timezone && String(params.timezone).trim()) { + query.timezone = String(params.timezone).trim(); + } + const res = await API.get(path, { + params: query, + responseType: 'blob', + skipErrorHandler: true, + }); + const ctype = String(res.headers['content-type'] || ''); + if (ctype.includes('application/json')) { + const text = await res.data.text(); + let msg = text; + try { + const j = JSON.parse(text); + if (j.message) msg = j.message; + } catch { + /* keep text */ + } + throw new Error(msg); + } + const dispo = String(res.headers['content-disposition'] || ''); + const utf8Match = /filename\*=UTF-8''([^;]+)/i.exec(dispo); + const fallbackMatch = /filename="([^"]+)"/i.exec(dispo); + const filename = + (utf8Match?.[1] ? decodeURIComponent(utf8Match[1]) : undefined) || + fallbackMatch?.[1] || + `export-${params.userId}-${params.year}-${String(params.month).padStart(2, '0')}.csv`; + const url = URL.createObjectURL(res.data); + try { + const a = document.createElement('a'); + a.href = url; + a.download = filename; + a.rel = 'noopener'; + document.body.appendChild(a); + a.click(); + a.remove(); + } finally { + URL.revokeObjectURL(url); + } +} diff --git a/web/classic/src/hooks/common/useNavigation.js b/web/classic/src/hooks/common/useNavigation.js index f7e61a203a8e..aaff24457a57 100644 --- a/web/classic/src/hooks/common/useNavigation.js +++ b/web/classic/src/hooks/common/useNavigation.js @@ -18,8 +18,9 @@ For commercial licensing, please contact support@quantumnous.com */ import { useMemo } from 'react'; +import { resolveDocsNavLink } from '../../helpers/docsNavLink'; -export const useNavigation = (t, docsLink, headerNavModules) => { +export const useNavigation = (t, docsLink, headerNavModules, serverAddress) => { const mainNavLinks = useMemo(() => { // 默认配置,如果没有传入配置则显示所有模块 const defaultModules = { @@ -33,6 +34,25 @@ export const useNavigation = (t, docsLink, headerNavModules) => { // 使用传入的配置或默认配置 const modules = headerNavModules || defaultModules; + const docsNavEntry = docsLink + ? (() => { + const resolved = resolveDocsNavLink(docsLink, serverAddress); + if (resolved.external) { + return { + text: t('文档'), + itemKey: 'docs', + isExternal: true, + externalLink: resolved.href, + }; + } + return { + text: t('文档'), + itemKey: 'docs', + to: resolved.href, + }; + })() + : null; + const allLinks = [ { text: t('首页'), @@ -49,16 +69,7 @@ export const useNavigation = (t, docsLink, headerNavModules) => { itemKey: 'pricing', to: '/pricing', }, - ...(docsLink - ? [ - { - text: t('文档'), - itemKey: 'docs', - isExternal: true, - externalLink: docsLink, - }, - ] - : []), + ...(docsNavEntry ? [docsNavEntry] : []), { text: t('关于'), itemKey: 'about', @@ -79,7 +90,7 @@ export const useNavigation = (t, docsLink, headerNavModules) => { } return modules[link.itemKey] === true; }); - }, [t, docsLink, headerNavModules]); + }, [t, docsLink, headerNavModules, serverAddress]); return { mainNavLinks, diff --git a/web/classic/src/hooks/dashboard/useDashboardCharts.jsx b/web/classic/src/hooks/dashboard/useDashboardCharts.jsx index ef0d47b0cd25..471ee6c80df3 100644 --- a/web/classic/src/hooks/dashboard/useDashboardCharts.jsx +++ b/web/classic/src/hooks/dashboard/useDashboardCharts.jsx @@ -396,7 +396,7 @@ export const useDashboardCharts = ( }, []); const updateChartData = useCallback( - (data) => { + (data, chartTimeRangeSec) => { const processedData = processRawData( data, dataExportDefaultTime, @@ -430,6 +430,7 @@ export const useDashboardCharts = ( const aggregatedData = aggregateDataByTimeAndModel( data, dataExportDefaultTime, + chartTimeRangeSec, ); const modelTotals = new Map(); @@ -448,6 +449,7 @@ export const useDashboardCharts = ( aggregatedData, data, dataExportDefaultTime, + chartTimeRangeSec, ); let newLineData = []; diff --git a/web/classic/src/hooks/dashboard/useDashboardData.js b/web/classic/src/hooks/dashboard/useDashboardData.js index e9b2cad83e72..83027117c6dd 100644 --- a/web/classic/src/hooks/dashboard/useDashboardData.js +++ b/web/classic/src/hooks/dashboard/useDashboardData.js @@ -20,8 +20,12 @@ For commercial licensing, please contact support@quantumnous.com import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { API, isAdmin, showError, timestamp2string } from '../../helpers'; -import { getDefaultTime, getInitialTimestamp } from '../../helpers/dashboard'; +import { API, isAdmin, showError } from '../../helpers'; +import { + getDefaultTime, + getInitialDashboardRangeStrings, + normalizeDashboardTimestampStrings, +} from '../../helpers/dashboard'; import { TIME_OPTIONS } from '../../constants/dashboard.constants'; import { useIsMobile } from '../common/useIsMobile'; import { useMinimumLoadingTime } from '../common/useMinimumLoadingTime'; @@ -39,14 +43,17 @@ export const useDashboardData = (userState, userDispatch, statusState) => { const showLoading = useMinimumLoadingTime(loading); // ========== 输入状态 ========== - const [inputs, setInputs] = useState({ - username: '', - token_name: '', - model_name: '', - start_timestamp: getInitialTimestamp(), - end_timestamp: timestamp2string(new Date().getTime() / 1000 + 3600), - channel: '', - data_export_default_time: '', + const [inputs, setInputs] = useState(() => { + const range = getInitialDashboardRangeStrings(); + return { + username: '', + token_name: '', + model_name: '', + start_timestamp: range.start_timestamp, + end_timestamp: range.end_timestamp, + channel: '', + data_export_default_time: '', + }; }); const [dataExportDefaultTime, setDataExportDefaultTime] = @@ -160,7 +167,18 @@ export const useDashboardData = (userState, userDispatch, statusState) => { setLoading(true); try { let url = ''; - const { start_timestamp, end_timestamp, username } = inputs; + const rangeNorm = normalizeDashboardTimestampStrings( + inputs.start_timestamp, + inputs.end_timestamp, + ); + const merged = { ...inputs, ...rangeNorm }; + if ( + rangeNorm.start_timestamp !== inputs.start_timestamp || + rangeNorm.end_timestamp !== inputs.end_timestamp + ) { + setInputs((prev) => ({ ...prev, ...rangeNorm })); + } + const { start_timestamp, end_timestamp, username } = merged; let localStartTimestamp = Date.parse(start_timestamp) / 1000; let localEndTimestamp = Date.parse(end_timestamp) / 1000; @@ -216,7 +234,11 @@ export const useDashboardData = (userState, userDispatch, statusState) => { const loadUserQuotaData = useCallback(async () => { if (!isAdminUser) return []; try { - const { start_timestamp, end_timestamp } = inputs; + const rangeNorm = normalizeDashboardTimestampStrings( + inputs.start_timestamp, + inputs.end_timestamp, + ); + const { start_timestamp, end_timestamp } = { ...inputs, ...rangeNorm }; const localStartTimestamp = Date.parse(start_timestamp) / 1000; const localEndTimestamp = Date.parse(end_timestamp) / 1000; const url = `/api/data/users?start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}`; @@ -253,12 +275,16 @@ export const useDashboardData = (userState, userDispatch, statusState) => { const handleSearchConfirm = useCallback( async (updateChartDataCallback) => { const data = await refresh(); + const chartTimeRangeSec = { + start_timestamp: Date.parse(inputs.start_timestamp) / 1000, + end_timestamp: Date.parse(inputs.end_timestamp) / 1000, + }; if (data && data.length > 0 && updateChartDataCallback) { - updateChartDataCallback(data); + updateChartDataCallback(data, chartTimeRangeSec); } setSearchModalVisible(false); }, - [refresh], + [refresh, inputs.start_timestamp, inputs.end_timestamp], ); // ========== Effects ========== diff --git a/web/classic/src/hooks/playground/usePlaygroundState.js b/web/classic/src/hooks/playground/usePlaygroundState.js index 130df90d5073..f6ac356f6378 100644 --- a/web/classic/src/hooks/playground/usePlaygroundState.js +++ b/web/classic/src/hooks/playground/usePlaygroundState.js @@ -33,6 +33,10 @@ import { saveMessages, } from '../../components/playground/configStorage'; import { processIncompleteThinkTags } from '../../helpers'; +import { + normalizeSamplingParameters, + toggleSamplingParameter, +} from '../../helpers/playgroundParameter'; export const usePlaygroundState = () => { const { t } = useTranslation(); @@ -66,8 +70,10 @@ export const usePlaygroundState = () => { const [inputs, setInputs] = useState( savedConfig.inputs || DEFAULT_CONFIG.inputs, ); - const [parameterEnabled, setParameterEnabled] = useState( - savedConfig.parameterEnabled || DEFAULT_CONFIG.parameterEnabled, + const [parameterEnabled, setParameterEnabled] = useState(() => + normalizeSamplingParameters( + savedConfig.parameterEnabled || DEFAULT_CONFIG.parameterEnabled, + ), ); const [showDebugPanel, setShowDebugPanel] = useState( savedConfig.showDebugPanel || DEFAULT_CONFIG.showDebugPanel, @@ -125,10 +131,7 @@ export const usePlaygroundState = () => { }, []); const handleParameterToggle = useCallback((paramName) => { - setParameterEnabled((prev) => ({ - ...prev, - [paramName]: !prev[paramName], - })); + setParameterEnabled((prev) => toggleSamplingParameter(prev, paramName)); }, []); // 消息保存函数 - 改为立即保存,可以接受参数 @@ -177,10 +180,12 @@ export const usePlaygroundState = () => { })); } if (importedConfig.parameterEnabled) { - setParameterEnabled((prev) => ({ - ...prev, - ...importedConfig.parameterEnabled, - })); + setParameterEnabled((prev) => + normalizeSamplingParameters({ + ...prev, + ...importedConfig.parameterEnabled, + }), + ); } if (typeof importedConfig.showDebugPanel === 'boolean') { setShowDebugPanel(importedConfig.showDebugPanel); diff --git a/web/classic/src/hooks/usage-logs/useUsageLogsData.jsx b/web/classic/src/hooks/usage-logs/useUsageLogsData.jsx index 78975dd634f7..57167cbf8f81 100644 --- a/web/classic/src/hooks/usage-logs/useUsageLogsData.jsx +++ b/web/classic/src/hooks/usage-logs/useUsageLogsData.jsx @@ -42,6 +42,7 @@ import { import { ITEMS_PER_PAGE } from '../../constants'; import { useTableCompactMode } from '../common/useTableCompactMode'; import ParamOverrideEntry from '../../components/table/usage-logs/components/ParamOverrideEntry'; +import { downloadUsageLogsExport } from '../../helpers/usageLogsExport'; export const useLogsData = () => { const { t } = useTranslation(); @@ -74,6 +75,7 @@ export const useLogsData = () => { const [logCount, setLogCount] = useState(0); const [pageSize, setPageSize] = useState(ITEMS_PER_PAGE); const [logType, setLogType] = useState(0); + const [exportingLogs, setExportingLogs] = useState(false); // User and admin const isAdminUser = isAdmin(); @@ -310,6 +312,32 @@ export const useLogsData = () => { } }; + const exportLogs = async () => { + if (exportingLogs) return; + const formValues = getFormValues(); + const currentLogType = + formValues.logType !== undefined ? formValues.logType : logType; + setExportingLogs(true); + try { + await downloadUsageLogsExport(isAdminUser, { + logType: currentLogType, + username: formValues.username, + token_name: formValues.token_name, + model_name: formValues.model_name, + start_timestamp: Math.floor(Date.parse(formValues.start_timestamp) / 1000), + end_timestamp: Math.floor(Date.parse(formValues.end_timestamp) / 1000), + channel: formValues.channel, + group: formValues.group, + request_id: formValues.request_id, + }); + showSuccess(t('导出成功')); + } catch (error) { + showError(error?.message || t('导出失败')); + } finally { + setExportingLogs(false); + } + }; + const handleEyeClick = async () => { if (loadingStat) { return; @@ -887,6 +915,8 @@ export const useLogsData = () => { handlePageChange, handlePageSizeChange, refresh, + exportLogs, + exportingLogs, copyText, handleEyeClick, setLogsFormat, diff --git a/web/classic/src/i18n/locales/en.json b/web/classic/src/i18n/locales/en.json index 829a9e4b2a38..e34a3e42eb33 100644 --- a/web/classic/src/i18n/locales/en.json +++ b/web/classic/src/i18n/locales/en.json @@ -14,15 +14,14 @@ ",点击更新": ", click Update", "(共 {{total}} 个,省略 {{omit}} 个)": "", "(共 {{total}} 个)": "", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Currently only the Epay interface is supported. Configure the callback address in General Settings.", - "请确认商户和所选环境密钥一致。": "Make sure the merchant and keys for the selected environment match.", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Make sure Merchant, Store, Product, and the keys for the selected environment match.", + "(当前仅支持易支付接口,默认使用上方服务器地址作为回调地址!)": "(Currently only supports Epay interface, the default callback address is the server address above!)", "(筛选后显示 {{count}} 条)_one": "(Showing {{count}} item after filtering)", "(筛选后显示 {{count}} 条)_other": "(Showing {{count}} items after filtering)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(Input {{input}} tokens / 1M tokens * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(Input {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + Audio input {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(Input {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + Cache {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(Input {{nonImageInput}} tokens + Image input {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "The maximum value of [Maximum request count] and [Maximum request completion count] is 2147483647.", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[Maximum request count] must be greater than or equal to 0, [Maximum request completion count] must be greater than or equal to 1.", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", @@ -45,8 +44,10 @@ "0 表示不限": "0 means unlimited", "0.002-1之间的小数": "Decimal between 0.002-1", "0.1以上的小数": "Decimal above 0.1", + "0=周日 1=周一 2=周二 3=周三 4=周四 5=周五 6=周六": "0=Sun 1=Mon 2=Tue 3=Wed 4=Thu 5=Fri 6=Sat", "1. 管理员在此创建分组并设置倍率": "1. Admin creates groups and sets ratios here", "1) 点击「打开授权页面」完成登录;2) 浏览器会跳转到 localhost(页面打不开也没关系);3) 复制地址栏完整 URL 粘贴到下方;4) 点击「生成并填入」。": "1) Click \"Open Authorization Page\" to complete login; 2) The browser will redirect to localhost (it's OK if the page doesn't load); 3) Copy the full URL from the address bar and paste it below; 4) Click \"Generate and Fill\".", + "1=一月 ... 12=十二月": "1=Jan ... 12=Dec", "10 - 最高": "10 - Highest", "1h缓存创建 {{price}} / 1M tokens": "1h cache creation {{price}} / 1M tokens", "1h缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}": "1h cache creation {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}", @@ -70,12 +71,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "5m cache creation price: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m cache creation ratio: {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "5m cache creation price: {{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - High", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AGPL v3.0协议": "AGPL v3.0 License", "AI 对话": "AI Chat", "AI模型测试环境": "AI model testing environment", "AI模型配置": "AI model configuration", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "AK/SK mode uses AccessKey and SecretAccessKey; API Key mode uses an API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "anthropic-beta JSON 示例": "", + "Anthropic-compatible models": "Anthropic-compatible models", "API Key": "API Key", "API Key 模式下不支持批量创建": "Batch creation not supported in API Key mode", "API Key 验证失败": "API Key verification failed", @@ -101,12 +110,15 @@ "Bark推送URL必须以http://或https://开头": "Bark push URL must start with http:// or https://", "Bark通知": "Bark notification", "Basic Auth 头": "Basic Auth Header", + "Before you start": "Before you start", "Cache Directory": "Cache Directory", "Cached tokens": "Cached tokens", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "Cached token ratio is returned by the backend: Claude calculates as cached/(prompt+cached), others as cached/prompt.", "Changing batch type to:": "Changing batch type to:", "ChatCompletions→Responses 兼容配置": "ChatCompletions→Responses Compatibility Configuration", "ChatCompletions→Responses 兼容配置(Beta)": "ChatCompletions→Responses Compatibility (Beta)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Claude 强制 beta=true": "Claude Force beta=true", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude appends these values on top of existing request headers. Existing headers are not overwritten, and duplicate values are ignored automatically.", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Claude thinking adaptation BudgetTokens = MaxTokens * BudgetTokens percentage", @@ -115,23 +127,39 @@ "Claude请求头追加": "Claude request header append", "Client ID": "Client ID", "Client Secret": "Client Secret", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Codex 授权": "Codex Authorization", "Codex 渠道不支持批量创建": "Codex channel does not support batch creation", "common.changeLanguage": "Change Language", "Completion tokens": "Completion tokens", "Configuration": "Configuration", + "Configuration reference": "Configuration reference", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "context_int/context_string reads from request context; gjson reads from the entry request JSON body using gjson path.", "CPU 使用率超过此值时拒绝请求": "Reject requests when CPU usage exceeds this value", "CPU 阈值 (%)": "CPU Threshold (%)", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Creem API 密钥,敏感信息不显示": "Creem API key, sensitive information not displayed", "Creem Setting Tips": "Creem only supports preset fixed-amount products. These products and their prices need to be created and configured in advance on the Creem website, so custom dynamic amount top-ups are not supported. Configure the product name and price on Creem, obtain the Product Id, and then fill it in for the product below. Set the top-up amount and display price for this product in the new API.", "Creem 介绍": "Creem is the payment partner you always deserved, we strive for simplicity and straightforwardness on our APIs.", "Creem 充值": "Creem Recharge", "Creem 设置": "Creem Setting", + "Default model name for requests": "Default model name for requests", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default and vip can only be assigned to users by admin in \"User Management\". Suitable for tiered pricing, internal testing, or other scenarios where user self-selection is not desired.", "default为默认设置,可单独设置每个分类的安全等级": "\"default\" is the default setting, and each category can be set separately", "default为默认设置,可单独设置每个模型的版本": "\"default\" is the default setting, and each model can be set separately", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Dify channel only supports chatflow and agent, and agent does not support images!", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "Discord Client ID": "Discord Client ID", "Discord Client Secret": "Discord Client Secret", @@ -139,12 +167,26 @@ "Discovery claims": "Discovery claims", "Discovery scopes": "Discovery scopes", "Discovery 建议 scopes:": "Recommended Discovery scopes:", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", + "Environment variables": "Environment variables", "EUR (欧元)": "EUR (Euro)", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Expr 预览": "Expression Preview", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "false": "false", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "GC execution failed": "GC execution failed", "GC 已执行": "GC executed", "GC 执行失败": "GC execution failed", "GC 次数": "GC Count", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini安全设置": "Gemini safety settings", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Gemini thinking adaptation BudgetTokens = MaxTokens * BudgetTokens percentage", "Gemini思考适配设置": "Gemini thinking adaptation settings", @@ -165,8 +207,17 @@ "Haiku 模型": "Haiku Model", "Homepage URL 填": "Fill in the Homepage URL", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "include_obfuscation controls obfuscation fields in Responses stream. Disabled by default to prevent clients from disabling this security protection", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "The inference_geo field controls Claude's data residency inference region. Disabled by default to prevent unauthorized pass-through of geographic information", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "IP": "IP", "IP白名单": "IP Whitelist", "IP白名单(支持CIDR表达式)": "IP whitelist (supports CIDR expressions)", @@ -189,15 +240,19 @@ "Key 摘要": "Key summary", "Key 来源": "Key Source", "Key 来源类型": "Key Source Type", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Linux DO Client ID": "Linux DO Client ID", "Linux DO Client Secret": "Linux DO Client Secret", "LinuxDO": "LinuxDO", "LinuxDO ID": "LinuxDO ID", "Logo 图片地址": "Logo image address", + "Manual configuration": "Manual configuration", "Midjourney 任务记录": "Midjourney Task Records", "MIT许可证": "MIT License", "New API项目仓库地址:": "New API project repository address: ", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "NewAPI does not pass the incoming request's User-Agent to upstream channels by default; this condition is only used to identify clients accessing this site.", + "Note": "Note", "OAuth Client ID": "OAuth Client ID", "OAuth Client Secret": "OAuth Client Secret", "OAuth 登录失败:": "OAuth login failed: ", @@ -207,7 +262,15 @@ "OIDC ID": "OIDC ID", "Ollama 模型管理": "Ollama Model Management", "Ollama 版本信息": "Ollama Version Info", + "Open menu": "Open menu", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opus 模型": "Opus Model", + "Overview": "Overview", "Passkey": "Passkey", "Passkey 已解绑": "Passkey removed", "Passkey 已重置": "Passkey has been reset", @@ -218,18 +281,31 @@ "Pay Method Name": "", "Pay Method Type": "", "Ping间隔(秒)": "Ping Interval (seconds)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "POST 参数": "POST Parameters", + "Powered by": "Powered by", "price_xxx 的商品价格 ID,新建产品后可获得": "Product price ID for price_xxx, available after creating new product", "Prompt cache hit tokens": "Prompt cache hit tokens", "Prompt tokens": "Prompt tokens", + "Provider": "Provider", "Reasoning Effort": "Reasoning Effort", "Recharge Quota": "Recharge Quota", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Replace": "Replace", "Request ID": "Request ID", "RSA 私钥 (沙盒)": "", "RSA 私钥 (生产)": "", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "The safety_identifier field helps OpenAI identify application users who may violate usage policies. Disabled by default to protect user privacy", "Scopes(可选)": "Scopes (optional)", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "The service_tier field is used to specify service level. Allowing pass-through may result in higher billing than expected. Disabled by default to avoid extra charges", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "Stripe key for sk_xxx or rk_xxx, sensitive information not displayed", "SMTP 发送者邮箱": "SMTP Sender Email", "SMTP 服务器地址": "SMTP Server Address", @@ -244,6 +320,7 @@ "SSRF防护设置": "SSRF Protection Settings", "SSRF防护详细说明": "SSRF protection prevents malicious users from using your server to access internal network resources. Configure whitelists for trusted domains/IPs and restrict allowed ports. Applies to file downloads, webhooks, and notifications.", "standard 已被移除,vip 用户看不到": "standard has been removed, vip users cannot see it", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "The store field authorizes OpenAI to store request data for product evaluation and optimization. Disabled by default. Enabling may cause Codex to malfunction", "Stripe 设置": "Stripe Settings", "Stripe/Creem 商品ID(可选)": "Stripe/Creem Product ID (optional)", @@ -252,9 +329,16 @@ "Telegram Bot Token": "Telegram Bot Token", "Telegram Bot 名称": "Telegram Bot Name", "Telegram ID": "Telegram ID", + "Tip": "Tip", "Token Endpoint": "Token Endpoint", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "Tokens are converted to quota/usage count by ratio. After the request completes, the difference is settled (additional deduction/refund).", + "Token 估算器": "Token Estimator", + "Token 总数": "Total tokens", + "Token 用量范围": "Token Usage Range", + "Token 类型": "Token Type", "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "true": "true", "TTL(秒,0 表示默认)": "TTL (seconds, 0 for default)", "TTL(秒)": "TTL (seconds)", @@ -266,10 +350,14 @@ "URL 标识,只能包含小写字母、数字和连字符": "URL identifier, only lowercase letters, numbers, and hyphens allowed", "URL链接": "URL Link", "USD (美元)": "USD (US Dollar)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", "User Info Endpoint": "User Info Endpoint", "User-Agent include(每行一个,可不写)": "User-Agent include (one per line, optional)", "Value 正则": "Value Regex", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI does not support the functionResponse.id field. When enabled, this field will be automatically removed", + "View guide": "View guide", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "", "Waffo API 参数,可空(最多64位)": "", "Waffo 充值": "", @@ -294,8 +382,12 @@ "Well-Known URL": "Well-Known URL", "Well-Known URL 必须以 http:// 或 https:// 开头": "Well-Known URL must start with http:// or https://", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "Webhook signature key for whsec_xxx, sensitive information not displayed", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Worker地址": "Worker Address", "Worker密钥": "Worker Key", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key", "一个月": "A month", "一天": "One day", "一小时": "One hour", @@ -314,6 +406,7 @@ "上游倍率同步": "Upstream ratio synchronization", "上游模型管理": "Upstream Model Management", "上游返回": "Upstream response", + "上限": "Up To", "下一个表单块": "Next form block", "下一次重置": "Next reset", "下一步": "Next", @@ -455,6 +548,7 @@ "价格:${{price}} * {{ratioType}}:{{ratio}}": "Price: ${{price}} * {{ratioType}}: {{ratio}}", "价格摘要": "Price Summary", "价格暂时不可用,请稍后重试": "Price temporarily unavailable, please try again later", + "价格根据用量档位和请求条件动态调整": "Price adjusts dynamically based on usage tiers and request conditions", "价格模式": "", "价格模式(默认)": "Price Mode (Default)", "价格计算中...": "Calculating price...", @@ -513,6 +607,7 @@ "例如": "e.g.", "例如 /var/cache/new-api": "e.g. /var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "For example, €, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "e.g. Asia/Shanghai", "例如 https://docs.newapi.pro": "E.g., https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "", "例如 https://example.com/console/topup": "", @@ -619,6 +714,7 @@ "倍率模式(默认)": "", "倍率用于计费乘数,勾选「用户可选」后用户可在创建令牌时选择该分组": "Ratio is the billing multiplier. Check \"User Selectable\" to let users pick this group when creating tokens", "倍率类型": "Ratio type", + "值": "Value", "假设再加两个分组 default 和 vip,但不勾选用户可选:": "Now add two more groups default and vip, but without checking User Selectable:", "偏好设置": "Preferences", "停止测试": "Stop Testing", @@ -681,6 +777,7 @@ "兑换码生成管理": "Redemption code generation management", "兑换码管理": "Redemption Code Management", "兑换额度": "Redeem", + "兜底档": "Fallback", "全局控制侧边栏区域和功能显示,管理员隐藏的功能用户无法启用": "Global control of sidebar areas and functions, users cannot enable functions hidden by administrators", "全局设置": "Global Settings", "全选": "Select all", @@ -746,7 +843,6 @@ "最低充值数量": "", "最低充值美元数量": "Minimum recharge dollar amount", "最低充值美元数量必须大于 0": "Minimum recharge dollar amount must be greater than 0", - "留空则自动使用当前站点的默认回调地址": "Leave blank to use the default callback address of the current site", "最后使用时间": "Last used time", "最后更新": "Last Updated", "最后请求": "Last request", @@ -757,6 +853,7 @@ "最近一次": "Last", "最近事件": "Recent Events", "最高优先级": "highest priority", + "最高档": "Highest Tier", "写": "Write", "准入策略": "Admission Policy", "准入策略 JSON(可选)": "Admission Policy JSON (optional)", @@ -764,6 +861,9 @@ "准备完成初始化": "Ready to complete initialization", "减少": "Subtract", "凭证已刷新": "Credentials Refreshed", + "函数": "Functions", + "分时缓存 (Claude)": "Timed Cache (Claude)", + "分档价格表": "Tiered price table", "分类名称": "Category Name", "分组": "Group", "分组JSON设置": "Group JSON Settings", @@ -790,6 +890,9 @@ "切换为System角色": "Switch to System role", "切换为单密钥模式": "Switch to single key mode", "切换主题": "Switch Theme", + "切换到新版前端": "Switch to new frontend", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "The page will refresh and open the new frontend. Continue?", + "切换失败,请稍后重试": "Switch failed, please try again later", "划转到余额": "Transfer to balance", "划转邀请额度": "Transfer invitation quota", "划转金额最低为": "The minimum transfer amount is", @@ -845,6 +948,7 @@ "刷新缓存统计": "Refresh Cache Statistics", "刷新缓存统计失败": "Failed to refresh cache statistics", "刷新页面": "Reload Page", + "前 {{count}} 个": "First {{count}}", "前:": "Before:", "前往 io.net API Keys": "Go to io.net API Keys", "前往设置": "Go to Settings", @@ -874,11 +978,13 @@ "加载模型信息失败": "Failed to load model information", "加载模型列表失败": "Failed to load model list", "加载模型失败": "Failed to load models", + "加载消费统计失败": "Failed to load consumption", "加载用户协议内容失败...": "Failed to load user agreement content...", "加载设置中...": "Loading settings...", "加载详情中...": "Loading details...", "加载账单失败": "Failed to load bills", "加载隐私政策内容失败...": "Failed to load privacy policy content...", + "动态计费": "Dynamic pricing", "勾选后,该分组会出现在用户创建令牌时的下拉菜单中。未勾选的分组只能由管理员分配,用户自己无法选择。": "When checked, this group appears in the dropdown when users create tokens. Unchecked groups can only be assigned by admin.", "包含": "Contains", "包含来自未知或未标明供应商的AI模型,这些模型可能来自小型供应商或开源项目。": "Includes AI models from unknown or unmarked suppliers, which may come from small suppliers or open-source projects.", @@ -890,11 +996,13 @@ "区域": "Region", "升级分组": "Upgrade Group", "单GPU小时费率": "Per GPU Hour Rate", + "单价": "Unit Cost", "单价 (USD)": "", "历史消耗": "Consumption", "原价": "Original price", "原价,和普通用户一样": "original price, same as regular users", "原因:": "Reason: ", + "原始额度": "Raw Quota", "原密码": "Original Password", "原生格式": "Native format", "原生额度": "Raw quota", @@ -928,12 +1036,10 @@ "取消": "Cancel", "取消全选": "Deselect all", "取消选择": "Deselect", - "切换到新版前端": "Switch to new frontend", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "The page will refresh and open the new frontend. Continue?", - "切换失败,请稍后重试": "Switch failed, please try again later", "变换": "Transform", "变更": "Change", "变焦": "zoom", + "变量": "Variables", "变量值": "Variable Value", "变量名": "Variable Name", "只包括请求成功的次数": "Only include successful request times", @@ -962,6 +1068,7 @@ "可空": "", "可选,公告的补充说明": "Optional, additional information for the notice", "可选,用于复现结果": "Optional, for reproducibility", + "可选,用量达到此档时加收的固定费用": "Optional fixed fee charged when usage reaches this tier", "可选:基于用户信息 JSON 做组合条件准入,条件不满足时返回自定义提示": "Optional: Admission based on combined conditions from user info JSON; returns custom message when conditions are not met", "可选:用于自动生成端点或 Discovery URL": "Optional: Used to auto-generate endpoints or Discovery URL", "可选。匹配入口请求的 User-Agent;任意一行作为子串匹配(忽略大小写)即命中。": "Optional. Match the incoming request's User-Agent; any line matched as a substring (case-insensitive) counts as a hit.", @@ -970,6 +1077,7 @@ "可选值": "Optional value", "合计:{{total}}": "Total: {{total}}", "合计:文字部分 {{textTotal}} + 音频部分 {{audioTotal}} = {{total}}": "Total: text {{textTotal}} + audio {{audioTotal}} = {{total}}", + "同时满足": "all must match", "同时重置消息": "Reset messages simultaneously", "同步": "Sync", "同步到渠道": "Sync to Channel", @@ -993,6 +1101,8 @@ "向右展开": "Expand right", "向左展开": "Expand left", "否": "No", + "含时间条件": "Time rules", + "含请求条件": "Request rules", "启动": "Start", "启动参数 (Args)": "Startup Args", "启动命令": "Startup Command", @@ -1042,6 +1152,7 @@ "启用验证": "Enable Authentication", "周": "week", "命中判定:usage 中存在 cached tokens(例如 cached_tokens/prompt_cache_hit_tokens)即视为命中。": "Hit determination: Presence of cached tokens in usage (e.g. cached_tokens/prompt_cache_hit_tokens) is considered a hit.", + "命中档位": "Matched Tier", "命中率": "Hit Rate", "命中该亲和规则后,会把此模板合并到渠道参数覆盖中(同名键由模板覆盖)。": "When this affinity rule is matched, the template is merged into the channel parameter overrides (same-name keys are overridden by the template).", "和": "and", @@ -1062,6 +1173,8 @@ "固定价格": "Fixed Price", "固定价格(每次)": "Fixed Price (per use)", "固定价格值": "Fixed Price Value", + "固定费": "Flat Fee", + "固定阶梯": "Fixed Tier", "图像生成": "Image Generation", "图标": "Icon", "图标使用 react-icons(Simple Icons)或 URL/emoji,例如:github、gitlab、si:google": "Icon uses react-icons (Simple Icons) or URL/emoji, e.g.: github, gitlab, si:google", @@ -1235,8 +1348,10 @@ "实付金额": "Actual payment amount", "实付金额:": "Actual payment amount: ", "实际模型": "Actual model", + "实际环境": "Actual Env", "实际结算金额:{{symbol}}{{total}}(已包含分组价格调整)": "Actual charge: {{symbol}}{{total}} (group pricing adjustment included)", "实际请求体": "Actual request body", + "实际额度": "Actual Quota", "审计信息": "Audit Info", "容器": "Container", "容器ID": "Container ID", @@ -1299,7 +1414,14 @@ "导入配置": "Import configuration", "导入配置失败: ": "Failed to import configuration: ", "导出": "Export", + "导出失败": "Export failed", + "导出成功": "Export completed", + "导出日志": "Export logs", "导出日志失败": "Failed to export logs", + "导出月账单": "Export monthly bill", + "导出月账单和消费明细": "Export monthly bill and consumption details", + "导出消费明细": "Export consumption details", + "导出用量CSV": "Export usage CSV", "导出配置": "Export configuration", "导出配置失败: ": "Failed to export configuration: ", "将 reasoning_content 转换为 标签拼接到内容中": "Convert reasoning_content to tags and append to content", @@ -1317,8 +1439,10 @@ "将清除所有保存的配置并恢复默认设置,此操作不可撤销。是否继续?": "This will clear all saved configurations and restore default settings, this operation cannot be undone. Continue?", "将清除选定时间之前的所有日志": "This will clear all logs before the selected time", "将追加 2 条规则到现有规则列表。": "2 rules will be appended to the existing rule list.", + "将额外乘以上述价格": "will additionally multiply the above prices", "小时": "Hour", "小时费率": "Hourly Rate", + "小计": "Subtotal", "尚未使用": "Not used yet", "局部重绘-提交": "Vary Region", "屏蔽词列表": "Sensitive word list", @@ -1342,6 +1466,7 @@ "已分配内存": "Allocated Memory", "已切换为Assistant角色": "Switched to Assistant role", "已切换为System角色": "Switched to System role", + "已切换到新版前端,正在刷新页面": "Switched to the new frontend, refreshing page", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "Switched to the optimal ratio view, each model uses its lowest ratio group", "已初始化": "Initialized", "已删除": "Deleted", @@ -1360,7 +1485,6 @@ "已发起支付": "Payment initiated", "已发送到 Fluent": "Sent to Fluent", "已取消 Passkey 注册": "Passkey registration cancelled", - "已切换到新版前端,正在刷新页面": "Switched to the new frontend, refreshing page", "已同步到渠道": "Synced to Channel", "已启用": "Enabled", "已启用 Passkey,无需密码即可登录": "Passkey enabled, login without password", @@ -1389,6 +1513,7 @@ "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_one": "", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "Global request pass-through is enabled. Built-in NewAPI features such as parameter overrides, model redirection, and channel adaptation will be disabled. This is not a best practice. If this causes issues, please do not submit an issue.", + "已开始下载": "Download started", "已忽略模型": "", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "Successfully started testing all enabled channels. Please refresh page to view results.", "已打开授权页面": "Authorization page opened", @@ -1446,10 +1571,13 @@ "平均TPM": "Average TPM", "平移": "Pan", "年": "year", + "年份": "Year", + "年份无效": "Invalid year", "应付金额": "Amount Due", "应用": "Apply", "应用同步": "Apply synchronization", "应用更改": "Apply changes", + "应用用户筛选": "Apply user filter", "应用覆盖": "Apply overwrite", "延长后总时长": "Total Duration After Extension", "延长容器时长": "Extend Container Duration", @@ -1463,6 +1591,7 @@ "建立连接时发生错误": "Error occurred while establishing connection", "建议在生产环境中使用 MySQL 或 PostgreSQL 数据库,或确保 SQLite 数据库文件已映射到宿主机的持久化存储。": "It is recommended to use MySQL or PostgreSQL databases in production environments, or ensure that the SQLite database file is mapped to the persistent storage of the host machine.", "开": "On", + "开发者": "Developer", "开启「默认使用 auto 分组」后,新建令牌和初始令牌都会自动设为 auto。": "After enabling \"Default to auto group\", new tokens and initial tokens will be set to auto.", "开启之后会清除用户提示词中的": "After enabling, the user prompt will be cleared", "开启之后将上游地址替换为服务器地址": "After enabling, the upstream address will be replaced with the server address", @@ -1501,6 +1630,7 @@ "当前 API 密钥已过期,请在设置中更新。": "Current API key has expired, please update it in settings.", "当前 Ollama 版本为 ${version}": "Current Ollama version is ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "Currently only OpenAI / Claude semantics support cached token statistics. Other channels will hide token-related fields.", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Currently only the Epay interface is supported. Configure the callback address in General Settings.", "当前余额": "Current balance", "当前值": "Current value", "当前值不是合法 JSON,无法格式化": "Current value is not valid JSON, cannot format", @@ -1587,6 +1717,7 @@ "或": "or", "或其兼容new-api-worker格式的其他版本": "or other versions compatible with new-api-worker format", "或手动输入密钥:": "Or manually enter the secret:", + "所有 Token": "All Tokens", "所有上游数据均可信": "All upstream data is reliable", "所有密钥已复制到剪贴板": "All keys have been copied to the clipboard", "所有用户": "All users", @@ -1643,6 +1774,7 @@ "按次:{{symbol}}{{price}} * {{ratioType}}:{{ratio}} = {{symbol}}{{total}}": "Per request: {{symbol}}{{price}} * {{ratioType}}: {{ratio}} = {{symbol}}{{total}}", "按次计费": "Pay per request", "按照如下格式输入:AccessKey|SecretAccessKey|Region": "Enter in the format: AccessKey|SecretAccessKey|Region", + "按用户筛选(可选)": "Filter by user (optional)", "按量计费": "Pay as you go", "按量计费下需要先填写输入价格,才能保存其它价格项。": "For per-token billing, fill in the input price before saving other price fields.", "按顺序替换content中的变量占位符": "Replace variable placeholders in content in order", @@ -1794,6 +1926,7 @@ "新增订阅": "Add subscription", "新密码": "New Password", "新密码需要和原密码不一致!": "New password must be different from the old password!", + "新年促销": "New Year promo", "新建": "Create", "新建套餐": "Create Plan", "新建容器": "Create Container", @@ -1815,6 +1948,7 @@ "无冲突项": "No conflict items", "无效的部署信息": "Invalid deployment information", "无效的重置链接,请重新发起密码重置请求": "Invalid reset link, please initiate a new password reset request", + "无条件(兜底档)": "No condition (fallback)", "无法发起 Passkey 注册": "Unable to initiate Passkey registration", "无法复制到剪贴板,请手动复制": "Unable to copy to clipboard, please copy manually", "无法添加图片": "Unable to add image", @@ -1823,6 +1957,7 @@ "无法连接 io.net": "Unable to connect to io.net", "无生效": "No active", "无邀请人": "No Inviter", + "无限": "Unlimited", "无限制": "Unlimited", "无限额度": "Unlimited quota", "日": "day", @@ -1839,18 +1974,23 @@ "日志类型": "Log type", "日志设置": "Log settings", "日志详情": "Log details", + "日期": "Day", "旧格式(JSON 对象)": "Legacy Format (JSON Object)", "旧格式(直接覆盖):": "Old format (direct override):", "旧格式必须是 JSON 对象": "Legacy format must be a JSON object", "旧格式模板": "Old format template", "旧的备用码已失效,请保存新的备用码": "Old backup codes have been invalidated, please save the new backup codes", "早上好": "Good morning", + "时区": "Timezone", + "时区(IANA,可选)": "Timezone (IANA, optional)", "时间": "Time", "时间信息": "Time Information", + "时间条件": "Time condition", "时间粒度": "Time granularity", "易支付": "Epay", "易支付商户ID": "Epay merchant ID", "易支付商户密钥": "Epay merchant key", + "星期": "Weekday", "是": "Yes", "是否为企业账户": "Is it an enterprise account?", "是否同时重置对话消息?选择\"是\"将清空所有对话记录并恢复默认示例;选择\"否\"将保留当前对话记录。": "Reset conversation messages at the same time? Selecting \"Yes\" will clear all conversation records and restore default examples; selecting \"No\" will retain current conversation records.", @@ -1956,6 +2096,8 @@ "更新预填组": "Update pre-filled group", "替换": "", "月": "month", + "月份": "Month", + "月份无效": "Invalid month", "有 Reasoning": "Has Reasoning", "有序字符串数组": "Ordered string array", "有效期": "Validity", @@ -1965,7 +2107,6 @@ "服务可用性": "Service Status", "服务商": "Service Provider", "服务器IP": "Server IP", - "节点名称": "Node Name", "服务器地址": "Server Address", "服务器日志功能未启用(未配置日志目录)": "Server logging is not enabled (log directory not configured)", "服务器日志管理": "Server Log Management", @@ -2023,6 +2164,8 @@ "条": "items", "条 - 第": "to", "条,共": "of", + "条件": "Condition", + "条件乘数": "Condition multipliers", "条件取反": "Negate Condition", "条件数": "Conditions", "条件规则": "Condition Rules", @@ -2062,12 +2205,16 @@ "核心配置": "Core Configuration", "核采样,控制词汇选择的多样性": "Nucleus sampling, controls vocabulary selection diversity", "根据 Anthropic 协定,/v1/messages 的输入 tokens 仅统计非缓存输入,不包含缓存读取与缓存写入 tokens。": "Per Anthropic conventions, /v1/messages input tokens count only non-cached input and exclude cache read/write tokens.", + "根据哪个维度的 Token 数量决定落在哪一档": "Determines which tier to apply based on this dimension's token count", + "根据总用量落在哪个档位,所有 Token 都按该档价格计费": "All tokens are charged at the rate of the tier your total usage falls into", "根据模型名称和匹配规则查找模型元数据,优先级:精确 > 前缀 > 后缀 > 包含": "Find model metadata based on model name and matching rules, priority: exact > prefix > suffix > contains", "格式化": "Format", "格式化 JSON": "Format JSON", "格式正确": "Format Correct", "格式示例:": "Format example:", "格式错误": "Format Error", + "档": "tier(s)", + "档位名称": "Tier Name", "检查更新": "Check for updates", "检测全部渠道上游更新": "", "检测到 FluentRead(流畅阅读)": "FluentRead (smooth reading) detected", @@ -2160,6 +2307,7 @@ "次": "request", "欢迎使用,请完成以下设置以开始使用系统": "Welcome! Please complete the following settings to start using the system", "欧元": "EUR", + "止": "To", "正则替换": "", "正在加载可用部署位置...": "Loading available deployment locations...", "正在加载签到状态...": "Loading check-in status...", @@ -2193,6 +2341,7 @@ "此操作将降低用户的权限级别": "This operation will reduce the user's permission level", "此支付方式最低充值金额为": "Minimum recharge amount for this payment method is", "此时用户创建令牌时只能看到 standard 和 premium:": "Users can now only see standard and premium when creating tokens:", + "此档上限(Token 数)": "Tier Limit (Token Count)", "此渠道由 IO.NET 自动同步,类型、密钥和 API 地址已锁定。": "This channel is automatically synchronized by IO.NET, type, key and API address are locked.", "此设置用于系统内部计算,默认值500000是为了精确到6位小数点设计,不推荐修改。": "This setting is used for internal system calculations. The default value of 500000 is designed for 6 decimal places precision, modification is not recommended.", "此页面仅显示未设置价格或倍率的模型,设置后将自动从列表中移除": "This page only shows models without price or ratio settings. After setting, they will be automatically removed from the list", @@ -2206,6 +2355,7 @@ "此项可选,用于通过自定义API地址来进行 API 调用,末尾不要带/v1和/": "Optional for API calls through custom API address, do not add /v1 and / at the end", "每个充值单位对应的 USD 金额,默认 1.0": "", "每个分组代表一个价格档位。管理员创建分组后,可以选择哪些档位对用户开放自选。": "Each group represents a pricing tier. After creating groups, admins can choose which tiers are open for user self-selection.", + "每个档位可设置 0~2 个条件(对 p 和 c),最后一档为兜底档无需条件。": "Each tier can have 0-2 conditions (on p and c). The last tier is the fallback and needs no condition.", "每个用户最多可创建的令牌数量,默认 1000,设置过大可能会影响性能": "Maximum number of tokens each user can create, default 1000. Setting too large may affect performance", "每周": "Weekly", "每天": "Daily", @@ -2214,6 +2364,7 @@ "每日签到": "Daily Check-in", "每日签到可获得随机额度奖励": "Daily check-in rewards random quota", "每月": "Monthly", + "每百万 Token 价格": "Price per 1M Tokens", "每美元对应 Token 数": "Tokens per USD", "每隔多少分钟测试一次所有通道": "How many minutes between testing all channels", "永不过期": "Never expires", @@ -2296,6 +2447,11 @@ "添加密钥环境变量": "Add Secret Environment Variable", "添加成功": "Added successfully", "添加提供商": "Add Provider", + "添加时间条件": "Add time condition", + "添加时间规则": "Add time rule", + "添加更多档位": "Add More Tiers", + "添加条件": "Add Condition", + "添加条件组": "Add condition group", "添加模型": "Add model", "添加模型区域": "Add model region", "添加渠道": "Add channel", @@ -2305,6 +2461,7 @@ "添加规则": "Add Rule", "添加键值对": "Add key-value pair", "添加问答": "Add FAQ", + "添加阶梯": "Add Tier", "添加额度": "Add quota", "清理不活跃缓存": "Clean up inactive cache", "清理失败": "Cleanup failed", @@ -2318,6 +2475,7 @@ "清除历史日志": "Clear historical logs", "清除失效兑换码": "Clear invalid redemption codes", "清除所有模型": "Clear all models", + "清除用户筛选": "Clear user filter", "渠道": "Channel", "渠道 ID": "Channel ID", "渠道ID,名称,密钥,API地址": "Channel ID, name, key, Base URL", @@ -2327,6 +2485,7 @@ "渠道优先级": "Channel Priority", "渠道信息": "Channel information", "渠道创建成功!": "Channel created successfully!", + "渠道历史总消耗": "Lifetime channel usage", "渠道复制失败": "Channel copy failed", "渠道复制失败: ": "Channel copy failed:", "渠道复制成功": "Channel copy successful", @@ -2337,6 +2496,7 @@ "渠道权重": "Channel Weight", "渠道标签": "Channel Tag", "渠道模型信息不完整": "Channel model information is incomplete", + "渠道消费统计": "Channel Consumption", "渠道的基本配置信息": "Channel basic configuration information", "渠道的模型测试": "Channel Model Test", "渠道的高级配置选项": "Advanced channel configuration options", @@ -2398,6 +2558,7 @@ "用户": "User", "用户 ID 字段": "User ID Field", "用户 ID 字段(可选)": "User ID Field (optional)", + "用户ID无效": "Invalid user ID", "用户个人功能": "User personal functions", "用户主页,展示系统信息": "User homepage, displaying system information", "用户优先:如果用户在请求中指定了系统提示词,将优先使用用户的设置": "User priority: If the user specifies a system prompt in the request, the user's setting will be used first", @@ -2438,6 +2599,10 @@ "用户账户创建成功!": "User account created successfully!", "用户账户管理": "User account management", "用时/首字": "Time/first word", + "用量分段计价,每一段各自按对应档位价格计费(类似电费阶梯)": "Usage is charged in segments — each segment at its own tier rate (like utility billing)", + "用量导出时区说明": "If empty, the calendar month follows the server local timezone; if set, it follows that IANA timezone.", + "用量导出说明": "Export CSV for user {{name}} (ID {{id}}) for the selected calendar month (monthly bill = summary, consumption details = per-call lines).", + "用量范围": "Usage Range", "由全站货币展示设置统一控制": "Controlled by the site-wide currency display settings", "由管理员分配,决定用户身份等级(如 default、vip)。": "Assigned by admin, determines user tier (e.g., default, vip).", "由订阅抵扣": "Deducted by subscription", @@ -2447,6 +2612,7 @@ "留空则使用默认端点;支持 {path, method}": "Leave blank to use the default endpoint; supports {path, method}", "留空则保持原有密钥": "Leave empty to keep existing key", "留空则自动使用 服务器地址 + /api/waffo/webhook": "", + "留空则自动使用当前站点的默认回调地址": "Leave blank to use the default callback address of the current site", "留空则默认使用服务器地址,注意不能携带http://或者https://": "If left blank, the server address will be used by default. Note that http:// or https:// should not be included", "登 录": "Log In", "登录": "Sign in", @@ -2522,6 +2688,7 @@ "确认作废": "Confirm invalidation", "确认关闭提示": "Confirm close", "确认冲突项修改": "Confirm conflict item modification", + "确认切换": "Confirm switch", "确认删除": "Confirm deletion", "确认删除模型": "Confirm Delete Model", "确认删除该分组?": "Confirm delete this group?", @@ -2529,7 +2696,6 @@ "确认删除该规则?": "Confirm delete this rule?", "确认取消密码登录": "Confirm cancel password login", "确认启用": "Confirm Enable", - "确认切换": "Confirm switch", "确认密码": "Confirm Password", "确认导入配置": "Confirm import configuration", "确认延长": "Confirm Extension", @@ -2614,6 +2780,8 @@ "第 {{line}} 条操作缺少目标路径": "Rule #{{line}} operation is missing a target path", "第 {{line}} 条请求头透传格式无效": "Rule #{{line}} header pass-through format is invalid", "第 {{line}} 条请求头透传缺少请求头名称": "Rule #{{line}} header pass-through is missing header name", + "第 {{n}} 档": "Tier {{n}}", + "第 {{n}} 组": "Group {{n}}", "第三方支付配置": "Third-party Payment Configuration", "第三方账户绑定状态(只读)": "Third-party account binding status (read-only)", "等价金额:": "Equivalent Amount: ", @@ -2694,6 +2862,7 @@ "纯字符串会直接覆盖整条请求头,或者点击“查看 JSON 示例”按 token 规则处理。": "", "累计签到": "Total check-ins", "累计获得": "Total received", + "累进阶梯": "Graduated Tier", "线路描述": "Route description", "组列表": "Group list", "组名": "Group name", @@ -2717,6 +2886,7 @@ "绘图任务记录": "Drawing task records", "绘图日志": "Drawing Logs", "绘图设置": "Drawing", + "统一定价": "Flat Rate", "统一的": "The Unified", "统计Tokens": "Statistical Tokens", "统计已重置": "Statistics reset", @@ -2732,10 +2902,17 @@ "缓存倍率": "Cache ratio", "缓存倍率 {{cacheRatio}}": "Cache ratio {{cacheRatio}}", "缓存写": "Cache Write", + "缓存创建": "Cache create", "缓存创建 {{price}} / 1M tokens": "Cache creation {{price}} / 1M tokens", "缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}": "Cache creation {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}", "缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})": "Cache creation {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (ratio: {{ratio}})", + "缓存创建 Token (cc)": "Cache Creation Tokens (cc)", "缓存创建 Tokens": "Cache Creation Tokens", + "缓存创建-1h": "Cache create (1h)", + "缓存创建-1小时": "Cache Creation (1-hour)", + "缓存创建-1小时 (cc1h)": "Cache Creation-1hour (cc1h)", + "缓存创建-5分钟": "Cache Creation (5-min)", + "缓存创建-5分钟 (cc5)": "Cache Creation-5min (cc5)", "缓存创建: {{cacheCreationRatio}}": "Cache creation: {{cacheCreationRatio}}", "缓存创建: 1h {{cacheCreationRatio1h}}": "Cache creation: 1h {{cacheCreationRatio1h}}", "缓存创建: 5m {{cacheCreationRatio5m}}": "Cache creation: 5m {{cacheCreationRatio5m}}", @@ -2743,8 +2920,12 @@ "缓存创建:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 缓存创建倍率 {{cacheCreationRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "Cache creation: {{tokens}} / 1M * model ratio {{modelRatio}} * cache creation ratio {{cacheCreationRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "缓存创建价格": "Input Cache Creation Price", "缓存创建价格 {{symbol}}{{price}} / 1M tokens": "Cache creation price {{symbol}}{{price}} / 1M tokens", + "缓存创建价格-1小时": "Cache Creation Price (1-hour)", + "缓存创建价格-5分钟": "Cache Creation Price (5-min)", "缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "Cache creation price: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (Cache creation ratio: {{cacheCreationRatio}})", "缓存创建价格:{{symbol}}{{price}} / 1M tokens": "Cache creation price: {{symbol}}{{price}} / 1M tokens", + "缓存创建价格(1小时)": "Cache Creation Price (1-hour)", + "缓存创建价格(5分钟)": "Cache Creation Price (5-min)", "缓存创建价格合计:5m {{symbol}}{{five}} + 1h {{symbol}}{{one}} = {{symbol}}{{total}} / 1M tokens": "Cache creation price total: 5m {{symbol}}{{five}} + 1h {{symbol}}{{one}} = {{symbol}}{{total}} / 1M tokens", "缓存创建倍率": "Cache creation ratio", "缓存创建倍率 {{cacheCreationRatio}}": "Cache creation ratio {{cacheCreationRatio}}", @@ -2756,6 +2937,8 @@ "缓存目录磁盘空间": "Cache Directory Disk Space", "缓存读": "Cache Read", "缓存读 {{price}} / 1M tokens": "Cache read {{price}} / 1M tokens", + "缓存读取": "Cache read", + "缓存读取 Token (cr)": "Cache Read Tokens (cr)", "缓存读取:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 缓存倍率 {{cacheRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "Cache read: {{tokens}} / 1M * model ratio {{modelRatio}} * cache ratio {{cacheRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "缓存读取价格": "Input Cache Read Price", "缓存读取价格 {{symbol}}{{price}} / 1M tokens": "Cache read price {{symbol}}{{price}} / 1M tokens", @@ -2837,6 +3020,7 @@ "自用模式": "Self-use mode", "自适应列表": "Adaptive list", "至": "until", + "节点名称": "Node Name", "节省": "Save", "花费": "Spend", "花费时间": "Time spent", @@ -2891,10 +3075,13 @@ "补单成功": "Order completed successfully", "表单引用错误,请刷新页面重试": "Form reference error, please refresh the page and try again", "表格视图": "Table view", + "表达式编辑": "Expression Editor", + "表达式错误": "Expression Error", "覆盖": "Override", "覆盖模式:将完全替换现有的所有密钥": "Overwrite mode: completely replace all existing keys", "覆盖模板": "Override Template", "覆盖现有密钥": "Overwrite existing key", + "见上方动态计费详情": "See dynamic pricing details above", "规则": "Rule", "规则 JSON": "Rule JSON", "规则 JSON 格式不正确": "Rule JSON format is incorrect", @@ -2904,6 +3091,7 @@ "规则导航": "Rule Navigation", "规则描述(可选)": "", "规则未找到,请刷新后重试": "Rule not found, please refresh and try again", + "规则版本": "Rule Version", "角色": "Role", "解析响应数据时发生错误": "An error occurred while parsing response data", "解析密钥文件失败: {{msg}}": "Failed to parse key file: {{msg}}", @@ -2920,6 +3108,7 @@ "计费开始": "Billing Start", "计费摘要": "", "计费方式": "Billing Mode", + "计费明细": "Billing Breakdown", "计费显示模式": "Billing Display Mode", "计费模式": "Billing mode", "计费类型": "Billing type", @@ -3056,6 +3245,7 @@ "请求失败": "Request failed", "请求头覆盖": "Request header override", "请求并计费模型": "Request and charge model", + "请求总数": "Total requests", "请求时长: ${time}s": "Request time: ${time}s", "请求次数": "Number of Requests", "请求结束后多退少补": "Adjust after request completion", @@ -3065,7 +3255,9 @@ "请求配置": "Request Configuration", "请求预扣费额度": "Pre-deduction quota for requests", "请点击我": "Please click me", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Make sure Merchant, Store, Product, and the keys for the selected environment match.", "请确认以下设置信息,点击\"初始化系统\"开始配置": "Please confirm the following settings information, click \"Initialize system\" to start configuration", + "请确认商户和所选环境密钥一致。": "Make sure the merchant and keys for the selected environment match.", "请确认您已了解禁用两步验证的后果": "Please confirm that you understand the consequences of disabling two-factor authentication", "请确认管理员密码": "Please confirm the admin password", "请稍后几秒重试,Turnstile 正在检查用户环境!": "Please try again in a few seconds, Turnstile is checking the user environment!", @@ -3268,15 +3460,19 @@ "费用信息": "Cost Information", "费用预估": "Cost Estimate", "资源消耗": "Resource Consumption", + "起": "From", "起始时间": "Start Time", "超级管理员": "Super Admin", "超级管理员未设置充值链接!": "Super administrator has not set the recharge link!", + "超过 {{count}} 个": "Over {{count}}", "超过阈值时拒绝新请求": "Reject new requests when threshold is exceeded", "跟随日志": "Follow Logs", "跟随系统主题设置": "Follow system theme", "跨分组": "Cross-group", "跨分组特殊倍率": "Cross-Group Special Ratios", "跨分组重试": "Cross-group retry", + "跨夜范围": "Cross-midnight range", + "跨阶梯": "Crossed Tier", "路径正则": "Path Regex", "路径正则(每行一个)": "Path Regex (one per line)", "跳转": "Jump", @@ -3295,6 +3491,14 @@ "输入 OIDC 的 Client ID": "Enter OIDC Client ID", "输入 OIDC 的 Token Endpoint": "Enter OIDC Token Endpoint", "输入 OIDC 的 Userinfo Endpoint": "Enter OIDC Userinfo Endpoint", + "输入 Token": "Input Token", + "输入 Token 定价": "Input Token Pricing", + "输入 Token 数": "Input Tokens", + "输入 Token 数 (p)": "Input Tokens (p)", + "输入 Token 数量,查看按当前配置的预计费用。": "Enter token counts to see the estimated cost.", + "输入 Token 数量,查看按当前配置的预计费用(不含分组倍率)。": "Enter token counts to see the estimated cost (before group ratio).", + "输入 Token 数量,查看按当前阶梯配置的预计费用。": "Enter token counts to see the estimated cost with the current tier configuration.", + "输入 Tokens 阶梯": "Input Token Tiers", "输入IP地址后回车,如:8.8.8.8": "Enter IP address and press Enter, e.g.: 8.8.8.8", "输入JSON对象": "Enter JSON Object", "输入与缓存价格合计 * {{ratioType}} {{ratio}} = {{symbol}}{{total}}": "Input and cache pricing subtotal * {{ratioType}} {{ratio}} = {{symbol}}{{total}}", @@ -3321,15 +3525,22 @@ "输入补全价格": "Enter Completion Price", "输入补全倍率": "Enter completion ratio", "输入要添加的邮箱域名": "Enter the email domain to add", + "输入计费表达式...": "Enter billing expression...", "输入认证器应用显示的6位数字验证码": "Enter the 6-digit verification code displayed on the authenticator application", "输入邮箱地址": "Enter Email Address", "输入金额": "Enter amount", + "输入阶梯": "Input Tiers", "输入项目名称,按回车添加": "Enter the item name, press Enter to add", "输入额度": "Enter quota", "输入验证码": "Enter Verification Code", "输入验证码完成设置": "Enter verification code to complete setup", "输出": "Output", "输出 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}}) * {{ratioType}} {{ratio}}": "Output {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} * {{ratioType}} {{ratio}}", + "输出 Token": "Output Token", + "输出 Token 定价": "Output Token Pricing", + "输出 Token 数": "Output Tokens", + "输出 Token 数 (c)": "Output Tokens (c)", + "输出 Tokens 阶梯": "Output Token Tiers", "输出:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 补全倍率 {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "Output: {{tokens}} / 1M * model ratio {{modelRatio}} * completion ratio {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "输出:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 输出倍率 {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "Output: {{tokens}} / 1M * model ratio {{modelRatio}} * output ratio {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "输出价格": "Output Price", @@ -3338,6 +3549,7 @@ "输出价格:{{symbol}}{{price}} / 1M tokens": "Output Price: {{symbol}}{{price}} / 1M tokens", "输出价格:{{symbol}}{{total}} / 1M tokens": "Output Price: {{symbol}}{{total}} / 1M tokens", "输出倍率 {{completionRatio}}": "Output ratio {{completionRatio}}", + "输出阶梯": "Output Tiers", "边栏设置": "Sidebar Settings", "过期于": "Expires at", "过期时间": "Expiration time", @@ -3358,6 +3570,7 @@ "这是基础金额,实际扣费 = 基础金额 x 系统分组倍率。": "This is the base amount. Actual deduction = base amount × system group ratio.", "这是重复键中的最后一个,其值将被使用": "This is the last one among duplicate keys, and its value will be used", "这里直接编辑 JSON 对象。适合简单覆盖参数的场景。": "Edit the JSON object directly here. Suitable for simple parameter override scenarios.", + "进入此档额外收费": "Tier Entry Fee", "进度": "Progress", "进行中": "Ongoing", "进行该操作时,可能导致渠道访问错误,请仅在数据库出现问题时使用": "When performing this operation, it may cause channel access errors. Please only use it when there is a problem with the database.", @@ -3417,6 +3630,7 @@ "递归": "Recursive", "递归策略": "Recursion Strategy", "通义千问": "Qwen", + "通用缓存": "Generic Cache", "通用设置": "General Settings", "通知": "Notice", "通知、价格和隐私相关设置": "Notification, price and privacy related settings", @@ -3558,6 +3772,16 @@ "镜像配置": "Image Configuration", "问题标题": "Question Title", "队列中": "In queue", + "阶": "tiers", + "阶梯内 Token 数": "Tokens in Tier", + "阶梯判断依据": "Tier Criterion", + "阶梯序号": "Tier #", + "阶梯累进": "Graduated", + "阶梯计费": "Tiered Billing", + "阶梯计费(未匹配到对应阶梯)": "Tiered Billing (no matching tier)", + "阶梯计费(表达式解析失败)": "Tiered Billing (expression parse failed)", + "阶梯计费详情": "Tiered Billing Details", + "阶梯配置摘要": "Tier Config Summary", "附加条件": "Additional Conditions", "降低您账户的安全性": "Reduce your account security", "降级": "Demote", @@ -3609,7 +3833,9 @@ "项目内容": "Project content", "项目操作按钮组": "Project action button group", "预估总费用": "Estimated Total Cost", + "预估环境": "Estimated Env", "预估费用仅供参考,实际费用可能略有差异": "Estimated cost is for reference only, actual cost may vary slightly", + "预估额度": "Estimated Quota", "预填组管理": "Pre-filled group", "预扣": "Pre-deduction", "预览失败": "Preview failed", @@ -3619,6 +3845,7 @@ "预览请求体": "Preview request body", "预计结束": "Estimated End", "预计结果": "Estimated result", + "预计费用": "Estimated Cost", "预设模板": "Presets", "预警阈值必须为正数": "Warning threshold must be a positive number", "频率惩罚,减少重复词汇的出现": "Frequency penalty, reduces repeated vocabulary", @@ -3678,122 +3905,6 @@ "默认折叠侧边栏": "Default collapse sidebar", "默认测试模型": "Default Test Model", "默认用户消息": "Default User Message", - "默认补全倍率": "Default completion ratio", - "缓存创建价格-5分钟": "Cache Creation Price (5-min)", - "缓存创建价格-1小时": "Cache Creation Price (1-hour)", - "缓存创建价格(5分钟)": "Cache Creation Price (5-min)", - "缓存创建价格(1小时)": "Cache Creation Price (1-hour)", - "分时缓存 (Claude)": "Timed Cache (Claude)", - "通用缓存": "Generic Cache", - "缓存读取": "Cache read", - "缓存创建": "Cache create", - "缓存创建-5分钟": "Cache Creation (5-min)", - "缓存创建-1小时": "Cache Creation (1-hour)", - "缓存读取 Token (cr)": "Cache Read Tokens (cr)", - "缓存创建 Token (cc)": "Cache Creation Tokens (cc)", - "缓存创建-5分钟 (cc5)": "Cache Creation-5min (cc5)", - "缓存创建-1小时 (cc1h)": "Cache Creation-1hour (cc1h)", - "阶梯计费": "Tiered Billing", - "阶梯计费(表达式解析失败)": "Tiered Billing (expression parse failed)", - "阶梯计费(未匹配到对应阶梯)": "Tiered Billing (no matching tier)", - "输入 Tokens 阶梯": "Input Token Tiers", - "输出 Tokens 阶梯": "Output Token Tiers", - "固定阶梯": "Fixed Tier", - "累进阶梯": "Graduated Tier", - "上限": "Up To", - "单价": "Unit Cost", - "固定费": "Flat Fee", - "Expr 预览": "Expression Preview", - "Token 估算器": "Token Estimator", - "预计费用": "Estimated Cost", - "原始额度": "Raw Quota", - "添加阶梯": "Add Tier", - "无限": "Unlimited", - "输入 Token 定价": "Input Token Pricing", - "输出 Token 定价": "Output Token Pricing", - "统一定价": "Flat Rate", - "阶梯累进": "Graduated", - "根据总用量落在哪个档位,所有 Token 都按该档价格计费": "All tokens are charged at the rate of the tier your total usage falls into", - "用量分段计价,每一段各自按对应档位价格计费(类似电费阶梯)": "Usage is charged in segments — each segment at its own tier rate (like utility billing)", - "Token 用量范围": "Token Usage Range", - "所有 Token": "All Tokens", - "前 {{count}} 个": "First {{count}}", - "超过 {{count}} 个": "Over {{count}}", - "第 {{n}} 档": "Tier {{n}}", - "最高档": "Highest Tier", - "此档上限(Token 数)": "Tier Limit (Token Count)", - "每百万 Token 价格": "Price per 1M Tokens", - "进入此档额外收费": "Tier Entry Fee", - "可选,用量达到此档时加收的固定费用": "Optional fixed fee charged when usage reaches this tier", - "添加更多档位": "Add More Tiers", - "输入 Token 数": "Input Tokens", - "输出 Token 数": "Output Tokens", - "输入 Token 数量,查看按当前阶梯配置的预计费用。": "Enter token counts to see the estimated cost with the current tier configuration.", - "开发者": "Developer", - "阶梯计费详情": "Tiered Billing Details", - "预估环境": "Estimated Env", - "实际环境": "Actual Env", - "预估额度": "Estimated Quota", - "实际额度": "Actual Quota", - "跨阶梯": "Crossed Tier", - "计费明细": "Billing Breakdown", - "阶梯序号": "Tier #", - "Token 类型": "Token Type", - "阶梯内 Token 数": "Tokens in Tier", - "小计": "Subtotal", - "阶梯配置摘要": "Tier Config Summary", - "输入阶梯": "Input Tiers", - "档位名称": "Tier Name", - "用量范围": "Usage Range", - "输入 Token": "Input Token", - "输出 Token": "Output Token", - "阶梯判断依据": "Tier Criterion", - "根据哪个维度的 Token 数量决定落在哪一档": "Determines which tier to apply based on this dimension's token count", - "输入 Token 数 (p)": "Input Tokens (p)", - "输出 Token 数 (c)": "Output Tokens (c)", - "变量": "Variables", - "函数": "Functions", - "输入计费表达式...": "Enter billing expression...", - "表达式编辑": "Expression Editor", - "表达式错误": "Expression Error", - "命中档位": "Matched Tier", - "档": "tier(s)", - "输入 Token 数量,查看按当前配置的预计费用。": "Enter token counts to see the estimated cost.", - "输入 Token 数量,查看按当前配置的预计费用(不含分组倍率)。": "Enter token counts to see the estimated cost (before group ratio).", - "条件": "Condition", - "添加条件": "Add Condition", - "无条件(兜底档)": "No condition (fallback)", - "兜底档": "Fallback", - "每个档位可设置 0~2 个条件(对 p 和 c),最后一档为兜底档无需条件。": "Each tier can have 0-2 conditions (on p and c). The last tier is the fallback and needs no condition.", - "输出阶梯": "Output Tiers", - "阶": "tiers", - "规则版本": "Rule Version", - "时间条件": "Time condition", - "星期": "Weekday", - "月份": "Month", - "日期": "Day", - "时区": "Timezone", - "跨夜范围": "Cross-midnight range", - "添加时间规则": "Add time rule", - "起": "From", - "止": "To", - "值": "Value", - "添加条件组": "Add condition group", - "添加时间条件": "Add time condition", - "同时满足": "all must match", - "新年促销": "New Year promo", - "第 {{n}} 组": "Group {{n}}", - "0=周日 1=周一 2=周二 3=周三 4=周四 5=周五 6=周六": "0=Sun 1=Mon 2=Tue 3=Wed 4=Thu 5=Fri 6=Sat", - "1=一月 ... 12=十二月": "1=Jan ... 12=Dec", - "动态计费": "Dynamic pricing", - "价格根据用量档位和请求条件动态调整": "Price adjusts dynamically based on usage tiers and request conditions", - "分档价格表": "Tiered price table", - "条件乘数": "Condition multipliers", - "将额外乘以上述价格": "will additionally multiply the above prices", - "缓存创建-1h": "Cache create (1h)", - "见上方动态计费详情": "See dynamic pricing details above", - "含时间条件": "Time rules", - "含请求条件": "Request rules", - "(当前仅支持易支付接口,默认使用上方服务器地址作为回调地址!)": "(Currently only supports Epay interface, the default callback address is the server address above!)" + "默认补全倍率": "Default completion ratio" } } diff --git a/web/classic/src/i18n/locales/fr.json b/web/classic/src/i18n/locales/fr.json index e433dc8f72ea..fc8dd143b640 100644 --- a/web/classic/src/i18n/locales/fr.json +++ b/web/classic/src/i18n/locales/fr.json @@ -1,11 +1,11 @@ { "translation": { - " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Recherche Web {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_many": " + Recherche Web {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", + " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Recherche Web {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_other": " + Recherche Web {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 图片生成调用 {{symbol}}{{price}} / 1次 * {{ratioType}} {{ratio}}": " + Appel de génération d'image {{symbol}}{{price}} / 1 fois * {{ratioType}} {{ratio}}", - " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Recherche de fichiers {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_many": " + Recherche de fichiers {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", + " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Recherche de fichiers {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_other": " + Recherche de fichiers {{count}} fois / 1K fois * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " 个模型设置相同的值": " modèles avec la même valeur", " 吗?": " ?", @@ -16,22 +16,20 @@ ",点击更新": ", cliquez sur Mettre à jour", "(共 {{total}} 个,省略 {{omit}} 个)": "", "(共 {{total}} 个)": "", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Seule l'interface Epay est actuellement prise en charge. Configurez l'adresse de rappel dans les paramètres généraux.", - "请确认商户和所选环境密钥一致。": "Vérifiez que le marchand et les clés de l'environnement sélectionné correspondent.", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Vérifiez que Merchant, Store, Product et les clés de l'environnement sélectionné correspondent.", - "(筛选后显示 {{count}} 条)_one": "(Showing {{count}} item after filtering)", "(筛选后显示 {{count}} 条)_many": "(Affichage de {{count}} éléments après filtrage)", + "(筛选后显示 {{count}} 条)_one": "(Showing {{count}} item after filtering)", "(筛选后显示 {{count}} 条)_other": "(Showing {{count}} items after filtering)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(Entrée {{input}} tokens / 1M tokens * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(Entrée {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + Entrée audio {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(Entrée {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + Cache {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(Entrée {{nonImageInput}} tokens + Entrée image {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "La valeur maximale de [Nombre maximal de requêtes] et [Nombre maximal d'achèvements de requêtes] est 2147483647.", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[Nombre maximal de requêtes] doit être supérieur ou égal à 0, [Nombre maximal d'achèvements de requêtes] doit être supérieur ou égal à 1.", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", "{{breakdown}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}": "{{breakdown}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}", - "{{count}} 项操作_one": "", "{{count}} 项操作_many": "", + "{{count}} 项操作_one": "", "{{count}} 项操作_other": "", "{{inputDesc}} + {{outputDesc}}{{extraServices}} = {{symbol}}{{total}}": "{{inputDesc}} + {{outputDesc}}{{extraServices}} = {{symbol}}{{total}}", "{{name}} ID": "{{name}} ID", @@ -74,12 +72,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "Prix de création de cache 5m : {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (ratio de création 5m : {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "Prix de création du cache 5m : {{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - Haute", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AGPL v3.0协议": "Licence AGPL v3.0", "AI 对话": "Conversation IA", "AI模型测试环境": "Environnement de test de modèle d'IA", "AI模型配置": "Configuration du modèle d'IA", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "Mode AK/SK : utiliser AccessKey et SecretAccessKey ; mode API Key : utiliser API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "anthropic-beta JSON 示例": "", + "Anthropic-compatible models": "Anthropic-compatible models", "API Key": "API Key", "API Key 模式下不支持批量创建": "Création en lot non prise en charge en mode clé API", "API Key 验证失败": "API Key verification failed", @@ -104,11 +110,14 @@ "Bark推送URL必须以http://或https://开头": "L'URL de notification Bark doit commencer par http:// ou https://", "Bark通知": "Notification Bark", "Basic Auth 头": "En-tête Basic Auth", + "Before you start": "Before you start", "Cached tokens": "Cached tokens", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "Le ratio de cached tokens est renvoyé par le backend : la sémantique Claude calcule cached/(prompt+cached), les autres calculent cached/prompt.", "Changing batch type to:": "Changement du type de lot en :", "ChatCompletions→Responses 兼容配置": "Configuration de compatibilité ChatCompletions→Responses", "ChatCompletions→Responses 兼容配置(Beta)": "Compatibilité ChatCompletions→Responses (bêta)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Claude 强制 beta=true": "Claude forcer beta=true", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude ajoute ces valeurs aux en-tetes de requete existants. Les en-tetes existants ne sont pas remplaces et les valeurs en double sont ignorees automatiquement.", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Adaptation de la pensée Claude BudgetTokens = MaxTokens * BudgetTokens pourcentage", @@ -117,23 +126,39 @@ "Claude请求头追加": "Ajout des en-tetes de requete Claude", "Client ID": "ID client", "Client Secret": "Secret client", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Codex 授权": "Autorisation Codex", "Codex 渠道不支持批量创建": "Le canal Codex ne prend pas en charge la création par lot", "common.changeLanguage": "Changer de langue", "Completion tokens": "Completion tokens", "Configuration": "Configuration", + "Configuration reference": "Configuration reference", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "context_int/context_string lit depuis le contexte de la requête ; gjson lit depuis le body JSON de la requête d'entrée via le chemin gjson.", "CPU 使用率超过此值时拒绝请求": "Rejeter les requêtes lorsque l'utilisation du CPU dépasse cette valeur", "CPU 阈值 (%)": "Seuil CPU (%)", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Creem API 密钥,敏感信息不显示": "Clé API Creem, les informations sensibles ne sont pas affichées", "Creem Setting Tips": "Creem ne prend en charge que des produits à montant fixe préconfigurés. Ces produits et leurs prix doivent être créés et configurés à l'avance sur le site Creem, les recharges à montant dynamique ne sont donc pas prises en charge. Configurez le nom et le prix du produit sur Creem, récupérez l'identifiant du produit, puis remplissez-le ci-dessous. Définissez enfin le montant et le prix affiché dans new-api.", "Creem 介绍": "Présentation de Creem", "Creem 充值": "Recharge Creem", "Creem 设置": "Paramètres Creem", + "Default model name for requests": "Default model name for requests", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default and vip can only be assigned to users by admin in \"User Management\". Suitable for tiered pricing, internal testing, or other scenarios where user self-selection is not desired.", "default为默认设置,可单独设置每个分类的安全等级": "\"default\" est le paramètre par défaut, et chaque catégorie peut être définie séparément", "default为默认设置,可单独设置每个模型的版本": "\"default\" est le paramètre par défaut, et chaque modèle peut être défini séparément", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Le canal Dify ne prend en charge que chatflow et agent, et l'agent ne prend pas en charge les images !", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "Discord Client ID": "ID client Discord", "Discord Client Secret": "Secret client Discord", @@ -141,11 +166,24 @@ "Discovery claims": "Discovery claims", "Discovery scopes": "Discovery scopes", "Discovery 建议 scopes:": "Scopes Discovery recommandés :", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", + "Environment variables": "Variables d'environnement", "EUR (欧元)": "EUR (Euro)", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "false": "faux", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "GC 已执行": "GC exécuté", "GC 执行失败": "Échec de l'exécution du GC", "GC 次数": "Nombre de GC", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini安全设置": "Paramètres de sécurité Gemini", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Adaptation de la pensée Gemini BudgetTokens = MaxTokens * BudgetTokens pourcentage", "Gemini思考适配设置": "Paramètres d'adaptation de la pensée Gemini", @@ -166,8 +204,17 @@ "Haiku 模型": "Modèle Haiku", "Homepage URL 填": "Remplir l'URL de la page d'accueil", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "include_obfuscation contrôle les champs d'obfuscation dans le flux Responses. Désactivé par défaut pour éviter que les clients ne désactivent cette protection de sécurité", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "Le champ inference_geo contrôle la région de résidence des données d'inférence de Claude. Désactivé par défaut pour éviter la transmission non autorisée d'informations géographiques", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "IP": "IP", "IP白名单": "IP Whitelist", "IP白名单(支持CIDR表达式)": "Liste blanche d'adresses IP (prise en charge des expressions CIDR)", @@ -190,15 +237,19 @@ "Key 摘要": "Résumé de Key", "Key 来源": "Source de clé", "Key 来源类型": "Type de source de clé", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Linux DO Client ID": "ID client Linux DO", "Linux DO Client Secret": "Secret client Linux DO", "LinuxDO": "LinuxDO", "LinuxDO ID": "ID LinuxDO", "Logo 图片地址": "Adresse de l'image du logo", + "Manual configuration": "Manual configuration", "Midjourney 任务记录": "Tâches Midjourney", "MIT许可证": "Licence MIT", "New API项目仓库地址:": "Adresse du référentiel du projet New API : ", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "NewAPI ne transmet pas le User-Agent de la requête entrante aux canaux en amont par défaut ; cette condition sert uniquement à identifier les clients accédant à ce site.", + "Note": "Note", "OAuth Client ID": "OAuth Client ID", "OAuth Client Secret": "OAuth Client Secret", "OAuth 端点": "Points de terminaison OAuth", @@ -206,7 +257,15 @@ "OIDC ID": "ID OIDC", "Ollama 模型管理": "Ollama Model Management", "Ollama 版本信息": "Ollama Version Info", + "Open menu": "Ouvrir le menu", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opus 模型": "Modèle Opus", + "Overview": "Vue d'ensemble", "Passkey": "Passkey", "Passkey 已解绑": "Passkey délié", "Passkey 已重置": "Le Passkey a été réinitialisé", @@ -217,17 +276,30 @@ "Pay Method Name": "", "Pay Method Type": "", "Ping间隔(秒)": "Intervalle de ping (secondes)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "POST 参数": "Paramètres POST", + "Powered by": "Powered by", "price_xxx 的商品价格 ID,新建产品后可获得": "ID de prix du produit price_xxx, peut être obtenu après la création d'un nouveau produit", "Prompt cache hit tokens": "Prompt cache hit tokens", "Prompt tokens": "Prompt tokens", + "Provider": "Fournisseur", "Reasoning Effort": "Effort de raisonnement", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Replace": "Remplacer", "Request ID": "Request ID", "RSA 私钥 (沙盒)": "", "RSA 私钥 (生产)": "", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "Le champ safety_identifier aide OpenAI à identifier les utilisateurs d'applications susceptibles de violer les politiques d'utilisation. Désactivé par défaut pour protéger la confidentialité des utilisateurs", "Scopes(可选)": "Scopes (optionnel)", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "Le champ service_tier est utilisé pour spécifier le niveau de service. Permettre le passage peut entraîner une facturation plus élevée que prévu. Désactivé par défaut pour éviter des frais supplémentaires", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "Clé secrète Stripe sk_xxx ou rk_xxx, les informations sensibles ne sont pas affichées", "SMTP 发送者邮箱": "Adresse e-mail de l'expéditeur SMTP", "SMTP 服务器地址": "Adresse du serveur SMTP", @@ -242,6 +314,7 @@ "SSRF防护设置": "Protection SSRF", "SSRF防护详细说明": "La protection SSRF empêche les utilisateurs malveillants d'utiliser votre serveur pour accéder aux ressources du réseau interne. Configurez des listes blanches pour les domaines/IP de confiance et limitez les ports autorisés. S'applique aux téléchargements de fichiers, aux webhooks et aux notifications.", "standard 已被移除,vip 用户看不到": "standard has been removed, vip users cannot see it", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "Le champ store autorise OpenAI à stocker les données de requête pour l'évaluation et l'optimisation du produit. Désactivé par défaut. L'activation peut causer un dysfonctionnement de Codex", "Stripe 设置": "Paramètres Stripe", "Stripe/Creem 商品ID(可选)": "ID produit Stripe/Creem (optionnel)", @@ -250,9 +323,12 @@ "Telegram Bot Token": "Jeton du bot Telegram", "Telegram Bot 名称": "Nom du bot Telegram", "Telegram ID": "ID Telegram", + "Tip": "Tip", "Token Endpoint": "Point de terminaison du jeton", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "Les tokens sont convertis en quota/nombre d'utilisations selon le ratio. Après la requête, la différence est réglée (déduction supplémentaire/remboursement).", "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "true": "vrai", "TTL(秒,0 表示默认)": "TTL (secondes, 0 pour la valeur par défaut)", "TTL(秒)": "TTL (secondes)", @@ -264,10 +340,14 @@ "URL 标识,只能包含小写字母、数字和连字符": "Identifiant URL, uniquement lettres minuscules, chiffres et tirets autorisés", "URL链接": "Lien URL", "USD (美元)": "USD (Dollar US)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", "User Info Endpoint": "Point de terminaison des informations utilisateur", "User-Agent include(每行一个,可不写)": "User-Agent include (un par ligne, optionnel)", "Value 正则": "Regex de valeur", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI ne prend pas en charge le champ functionResponse.id. Lorsqu'il est activé, ce champ sera automatiquement supprimé", + "View guide": "View guide", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "", "Waffo API 参数,可空(最多64位)": "", "Waffo 充值": "", @@ -291,8 +371,12 @@ "Well-Known URL": "URL bien connue", "Well-Known URL 必须以 http:// 或 https:// 开头": "L'URL bien connue doit commencer par http:// ou https://", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "Clé de signature Webhook whsec_xxx, les informations sensibles ne sont pas affichées", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Worker地址": "Adresse du Worker", "Worker密钥": "Clé du Worker", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key", "一个月": "Un mois", "一天": "Un jour", "一小时": "Une heure", @@ -483,8 +567,8 @@ "作用域:包含规则名称": "Portée : inclure le nom de la règle", "你似乎并没有修改什么": "Vous ne semblez rien avoir modifié", "你可以在“自定义模型名称”处手动添加它们,然后点击填入后再提交,或者直接使用下方操作自动处理。": "Vous pouvez les ajouter manuellement dans « Noms de modèles personnalisés », cliquer sur Remplir puis soumettre, ou utiliser directement les actions ci-dessous pour les traiter automatiquement.", - "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_one": "", "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_many": "", + "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_one": "", "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_other": "", "使用 {{name}} 继续": "Continuer avec {{name}}", "使用 Discord 继续": "Continuer avec Discord", @@ -509,6 +593,7 @@ "使用说明": "Guide", "例如 /var/cache/new-api": "ex. : /var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "Par exemple, €, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "p. ex. Asia/Shanghai", "例如 https://docs.newapi.pro": "Par exemple, https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "", "例如 https://example.com/console/topup": "", @@ -702,15 +787,15 @@ "公告更新失败": "Échec de la mise à jour de l'avis", "公告类型": "Type d'avis", "共": "Total", - "共 {{count}} 个密钥_one": "{{count}} clé au total", "共 {{count}} 个密钥_many": "{{count}} clés au total", + "共 {{count}} 个密钥_one": "{{count}} clé au total", "共 {{count}} 个密钥_other": "{{count}} clés au total", "共 {{count}} 个模型": "{{count}} modèles", - "共 {{count}} 个模型_one": "{{count}} modèle", "共 {{count}} 个模型_many": "{{count}} modèles", + "共 {{count}} 个模型_one": "{{count}} modèle", "共 {{count}} 个模型_other": "{{count}} modèles", - "共 {{count}} 条日志_one": "{{count}} log entry", "共 {{count}} 条日志_many": "{{count}} entrées de journal", + "共 {{count}} 条日志_one": "{{count}} log entry", "共 {{count}} 条日志_other": "{{count}} log entries", "共 {{total}} 项,当前显示 {{start}}-{{end}} 项": "Total {{total}} éléments, affichage actuel {{start}}-{{end}} éléments", "关": "Fermer", @@ -745,7 +830,6 @@ "最低充值数量": "", "最低充值美元数量": "Montant minimum de recharge en dollars", "最低充值美元数量必须大于 0": "Le montant minimum de recharge en dollars doit être supérieur à 0", - "留空则自动使用当前站点的默认回调地址": "Laissez vide pour utiliser l'adresse de rappel par défaut du site actuel", "最后使用时间": "Dernière utilisation", "最后更新": "Last Updated", "最后请求": "Dernière requête", @@ -789,6 +873,9 @@ "切换为System角色": "Basculer vers le rôle Système", "切换为单密钥模式": "Passer en mode clé unique", "切换主题": "Changer de thème", + "切换到新版前端": "Passer au nouveau frontend", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "La page sera actualisée et ouvrira le nouveau frontend. Continuer ?", + "切换失败,请稍后重试": "Le changement a échoué, veuillez réessayer plus tard", "划转到余额": "Transférer au solde", "划转邀请额度": "Quota d'invitation de transfert", "划转金额最低为": "Le montant minimum du virement est de", @@ -926,9 +1013,6 @@ "取消": "Annuler", "取消全选": "Annuler la sélection", "取消选择": "Deselect", - "切换到新版前端": "Passer au nouveau frontend", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "La page sera actualisée et ouvrira le nouveau frontend. Continuer ?", - "切换失败,请稍后重试": "Le changement a échoué, veuillez réessayer plus tard", "变换": "Variation", "变更": "Modification", "变焦": "Zoom", @@ -1295,7 +1379,12 @@ "导入配置": "Importer la configuration", "导入配置失败: ": "Échec de l'importation de la configuration : ", "导出": "Exporter", + "导出失败": "Échec de l'export", "导出日志失败": "Failed to export logs", + "导出月账单": "Exporter la facture mensuelle", + "导出月账单和消费明细": "Exporter la facture mensuelle et le détail de consommation", + "导出消费明细": "Exporter le détail de consommation", + "导出用量CSV": "Exporter l'usage (CSV)", "导出配置": "Exporter la configuration", "导出配置失败: ": "Échec de l'exportation de la configuration : ", "将 reasoning_content 转换为 标签拼接到内容中": "Convertir reasoning_content en balises et les ajouter au contenu", @@ -1308,8 +1397,8 @@ "将只保留最近 {{value}} 个日志文件,其余将被删除。": "Seuls les {{value}} derniers fichiers journaux seront conservés ; le reste sera supprimé.", "将大请求体临时存储到磁盘": "Stocker temporairement les grands corps de requête sur le disque", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。": "La configuration tarifaire du modèle actuellement édité {{name}} sera appliquée aux {{count}} modèles sélectionnés.", - "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_one": "", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_many": "", + "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_one": "", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_other": "", "将清除所有保存的配置并恢复默认设置,此操作不可撤销。是否继续?": "Effacera toutes les configurations enregistrées et rétablira les paramètres par défaut. Cette opération ne peut pas être annulée. Continuer ?", "将清除选定时间之前的所有日志": "Effacera tous les journaux avant l'heure sélectionnée", @@ -1325,8 +1414,8 @@ "展示价格": "Prix affiché", "嵌套映射:用户分组 → 使用分组 → 倍率": "Nested mapping: user group → using group → ratio", "左侧边栏个人设置": "Paramètres personnels de la barre latérale gauche", - "已为 {{count}} 个模型设置{{type}}_one": "{{type}} défini pour {{count}} modèle", "已为 {{count}} 个模型设置{{type}}_many": "{{type}} défini pour {{count}} modèles", + "已为 {{count}} 个模型设置{{type}}_one": "{{type}} défini pour {{count}} modèle", "已为 {{count}} 个模型设置{{type}}_other": "{{type}} défini pour {{count}} modèles", "已为 ${count} 个渠道设置标签!": "Étiquettes définies pour ${count} canaux !", "已从 Discovery 自动填充配置": "Configuration remplie automatiquement depuis Discovery", @@ -1340,28 +1429,28 @@ "已分配内存": "Mémoire allouée", "已切换为Assistant角色": "Basculé vers le rôle Assistant", "已切换为System角色": "Basculé vers le rôle Système", + "已切换到新版前端,正在刷新页面": "Passage au nouveau frontend effectué, actualisation de la page", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "Passé à la vue de ratio optimal, chaque modèle utilise son groupe de ratio le plus bas", "已初始化": "Initialisé", "已删除": "Supprimé", "已删除 {{count}} 个令牌!": "Supprimé {{count}} jetons !", - "已删除 {{count}} 个令牌!_one": "Supprimé {{count}} jeton !", "已删除 {{count}} 个令牌!_many": "Supprimé {{count}} jetons !", + "已删除 {{count}} 个令牌!_one": "Supprimé {{count}} jeton !", "已删除 {{count}} 个令牌!_other": "Supprimé {{count}} jetons !", - "已删除 {{count}} 条失效兑换码_one": "{{count}} code d'échange invalide supprimé", "已删除 {{count}} 条失效兑换码_many": "{{count}} codes d'échange invalides supprimés", + "已删除 {{count}} 条失效兑换码_one": "{{count}} code d'échange invalide supprimé", "已删除 {{count}} 条失效兑换码_other": "{{count}} codes d'échange invalides supprimés", "已删除 ${data} 个通道!": "${data} canaux supprimés !", "已删除所有禁用渠道,共计 ${data} 个": "Tous les canaux désactivés ont été supprimés, au total ${data}", "已删除消息及其回复": "Message et ses réponses supprimés", "已勾选": "Sélectionné", "已勾选 {{count}} 个模型": "{{count}} modèles sélectionnés", - "已勾选 {{count}} 个模型_one": "", "已勾选 {{count}} 个模型_many": "", + "已勾选 {{count}} 个模型_one": "", "已勾选 {{count}} 个模型_other": "", "已发起支付": "Paiement initié", "已发送到 Fluent": "Envoyé à Fluent", "已取消 Passkey 注册": "Enregistrement du Passkey annulé", - "已切换到新版前端,正在刷新页面": "Passage au nouveau frontend effectué, actualisation de la page", "已同步到渠道": "Synced to Channel", "已启用": "Activé", "已启用 Passkey,无需密码即可登录": "Passkey activé. Connexion sans mot de passe disponible.", @@ -1387,10 +1476,11 @@ "已复制自动生成的 API Key": "Auto-generated API Key copied", "已完成": "Completed", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型": "La configuration tarifaire du modèle {{name}} a été appliquée à {{count}} modèles en lot", - "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_one": "", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_many": "", + "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_one": "", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "La transmission globale des requêtes est activée. Les fonctionnalités intégrées de NewAPI (surcharge des paramètres, redirection de modèle, adaptation du canal, etc.) seront désactivées. Ce n'est pas une bonne pratique. Si cela cause des problèmes, merci de ne pas ouvrir d'issue.", + "已开始下载": "Téléchargement démarré", "已忽略模型": "", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "Le test de tous les canaux activés a démarré avec succès. Veuillez actualiser la page pour voir les résultats.", "已打开授权页面": "Page d'autorisation ouverte", @@ -1398,8 +1488,8 @@ "已批量处理上游模型更新:渠道 {{channels}} 个,加入 {{added}} 个,删除 {{removed}} 个,失败 {{fails}} 个": "", "已提交": "Soumis", "已支付金额": "Amount Paid", - "已新增 {{count}} 个模型:{{list}}_one": "{{count}} nouveau modèle ajouté : {{list}}", "已新增 {{count}} 个模型:{{list}}_many": "{{count}} nouveaux modèles ajoutés : {{list}}", + "已新增 {{count}} 个模型:{{list}}_one": "{{count}} nouveau modèle ajouté : {{list}}", "已新增 {{count}} 个模型:{{list}}_other": "{{count}} nouveaux modèles ajoutés : {{list}}", "已更新完毕所有已启用通道余额!": "Le quota de tous les canaux activés a été mis à jour !", "已有保存的配置": "Configuration enregistrée existante", @@ -1409,13 +1499,13 @@ "已服务": "Served", "已注销": "Déconnecté", "已添加": "Ajouté", - "已添加 {{count}} 个模板_one": "{{count}} modèle ajouté", "已添加 {{count}} 个模板_many": "{{count}} modèles ajoutés", + "已添加 {{count}} 个模板_one": "{{count}} modèle ajouté", "已添加 {{count}} 个模板_other": "{{count}} modèles ajoutés", "已添加到白名单": "Ajouté à la liste blanche", "已清理 {{count}} 个日志文件,释放 {{size}}": "{{count}} fichiers journaux nettoyés, {{size}} libérés", - "已清理 {{count}} 个日志文件,释放 {{size}}_one": "", "已清理 {{count}} 个日志文件,释放 {{size}}_many": "", + "已清理 {{count}} 个日志文件,释放 {{size}}_one": "", "已清理 {{count}} 个日志文件,释放 {{size}}_other": "", "已清空": "Vidé", "已清空测试结果": "Résultats de test effacés", @@ -1435,8 +1525,8 @@ "已达到购买上限": "Limite d'achat atteinte", "已过期": "Expiré", "已运行时间": "Uptime", - "已选择 {{count}} 个模型_one": "{{count}} modèle sélectionné", "已选择 {{count}} 个模型_many": "{{count}} modèles sélectionnés", + "已选择 {{count}} 个模型_one": "{{count}} modèle sélectionné", "已选择 {{count}} 个模型_other": "{{count}} modèles sélectionnés", "已选择 {{selected}} / {{total}}": "{{selected}} / {{total}} sélectionnés", "已选择 ${count} 个渠道": "${count} canaux sélectionnés", @@ -1452,6 +1542,8 @@ "平均TPM": "TPM moyen", "平移": "Panoramique", "年": "an", + "年份": "Année", + "年份无效": "Année invalide", "应付金额": "Montant à payer", "应用": "Appliquer", "应用同步": "Appliquer la synchronisation", @@ -1507,6 +1599,7 @@ "当前 API 密钥已过期,请在设置中更新。": "Current API key has expired, please update it in settings.", "当前 Ollama 版本为 ${version}": "Current Ollama version is ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "Actuellement, seules les sémantiques OpenAI / Claude prennent en charge les statistiques de tokens en cache. Les autres canaux masqueront les champs liés aux tokens.", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Seule l'interface Epay est actuellement prise en charge. Configurez l'adresse de rappel dans les paramètres généraux.", "当前余额": "Solde actuel", "当前值": "Valeur actuelle", "当前值不是合法 JSON,无法格式化": "La valeur actuelle n'est pas un JSON valide, impossible de formater", @@ -1839,6 +1932,7 @@ "旧格式模板": "Modèle d'ancien format", "旧的备用码已失效,请保存新的备用码": "Les anciens codes de sauvegarde ont été invalidés, veuillez enregistrer les nouveaux codes de sauvegarde", "早上好": "Bonjour", + "时区(IANA,可选)": "Fuseau horaire (IANA, optionnel)", "时间": "Heure", "时间信息": "Time Information", "时间粒度": "Granularité temporelle", @@ -1949,6 +2043,7 @@ "更新预填组": "Mettre à jour le groupe pré-rempli", "替换": "", "月": "mois", + "月份无效": "Mois invalide", "有 Reasoning": "A un raisonnement", "有序字符串数组": "Ordered string array", "有效期": "Validité", @@ -1958,7 +2053,6 @@ "服务可用性": "État du service", "服务商": "Service Provider", "服务器IP": "IP du serveur", - "节点名称": "Nom du nœud", "服务器地址": "Adresse du serveur", "服务器日志功能未启用(未配置日志目录)": "La journalisation du serveur n'est pas activée (répertoire de journaux non configuré)", "服务器日志管理": "Gestion des journaux du serveur", @@ -2425,6 +2519,8 @@ "用户账户创建成功!": "Compte utilisateur créé avec succès !", "用户账户管理": "Comptes utilisateurs", "用时/首字": "Temps/premier mot", + "用量导出时区说明": "Sans fuseau, le mois civil suit l'heure locale du serveur ; avec un fuseau IANA, le mois civil suit ce fuseau.", + "用量导出说明": "Exporter le CSV pour l'utilisateur {{name}} (ID {{id}}) pour le mois civil choisi (facture mensuelle = résumé, détail = lignes par appel).", "由全站货币展示设置统一控制": "Contrôlé par les paramètres globaux d'affichage des devises", "由管理员分配,决定用户身份等级(如 default、vip)。": "Assigned by admin, determines user tier (e.g., default, vip).", "由订阅抵扣": "Déduit par l'abonnement", @@ -2434,6 +2530,7 @@ "留空则使用默认端点;支持 {path, method}": "Laissez vide pour utiliser le point de terminaison par défaut ; prend en charge {path, method}", "留空则保持原有密钥": "Laisser vide pour conserver la clé existante", "留空则自动使用 服务器地址 + /api/waffo/webhook": "", + "留空则自动使用当前站点的默认回调地址": "Laissez vide pour utiliser l'adresse de rappel par défaut du site actuel", "留空则默认使用服务器地址,注意不能携带http://或者https://": "Laissez vide pour utiliser l'adresse du serveur par défaut, notez que vous ne pouvez pas inclure http:// ou https://", "登 录": "Se connecter", "登录": "Se connecter", @@ -2479,11 +2576,11 @@ "确定要充值 $": "Confirmer la recharge de $", "确定要删除供应商 \"{{name}}\" 吗?此操作不可撤销。": "Êtes-vous sûr de vouloir supprimer le fournisseur \"{{name}}\" ? Cette opération est irréversible.", "确定要删除所有已自动禁用的密钥吗?": "Êtes-vous sûr de vouloir supprimer toutes les clés désactivées automatiquement ?", - "确定要删除所选的 {{count}} 个令牌吗?_one": "Êtes-vous sûr de vouloir supprimer le jeton sélectionné ?", "确定要删除所选的 {{count}} 个令牌吗?_many": "Êtes-vous sûr de vouloir supprimer les {{count}} jetons sélectionnés ?", + "确定要删除所选的 {{count}} 个令牌吗?_one": "Êtes-vous sûr de vouloir supprimer le jeton sélectionné ?", "确定要删除所选的 {{count}} 个令牌吗?_other": "Êtes-vous sûr de vouloir supprimer les {{count}} jetons sélectionnés ?", - "确定要删除所选的 {{count}} 个模型吗?_one": "Êtes-vous sûr de vouloir supprimer le modèle sélectionné ?", "确定要删除所选的 {{count}} 个模型吗?_many": "Êtes-vous sûr de vouloir supprimer les {{count}} modèles sélectionnés ?", + "确定要删除所选的 {{count}} 个模型吗?_one": "Êtes-vous sûr de vouloir supprimer le modèle sélectionné ?", "确定要删除所选的 {{count}} 个模型吗?_other": "Êtes-vous sûr de vouloir supprimer les {{count}} modèles sélectionnés ?", "确定要删除此 OAuth 提供商吗?": "Êtes-vous sûr de vouloir supprimer ce fournisseur OAuth ?", "确定要删除此API信息吗?": "Êtes-vous sûr de vouloir supprimer ces informations d'API ?", @@ -2510,6 +2607,7 @@ "确认作废": "Confirmer l'invalidation", "确认关闭提示": "Confirmer la fermeture", "确认冲突项修改": "Confirmer la modification de l'élément de conflit", + "确认切换": "Confirmer le changement", "确认删除": "Confirmer la suppression", "确认删除模型": "Confirm Delete Model", "确认删除该分组?": "Confirm delete this group?", @@ -2517,7 +2615,6 @@ "确认删除该规则?": "Confirm delete this rule?", "确认取消密码登录": "Confirmer l'annulation de la connexion par mot de passe", "确认启用": "Confirmer l'activation", - "确认切换": "Confirmer le changement", "确认密码": "Confirmer le mot de passe", "确认导入配置": "Confirmer l'importation de la configuration", "确认延长": "Confirm Extension", @@ -2823,6 +2920,7 @@ "自用模式": "Mode auto-utilisation", "自适应列表": "Liste adaptative", "至": "jusqu'à", + "节点名称": "Nom du nœud", "节省": "Économiser", "花费": "Dépenser", "花费时间": "passer du temps", @@ -3050,7 +3148,9 @@ "请求配置": "Configuration des requêtes", "请求预扣费额度": "Quota de pré-déduction pour les demandes", "请点击我": "Veuillez cliquer sur moi", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Vérifiez que Merchant, Store, Product et les clés de l'environnement sélectionné correspondent.", "请确认以下设置信息,点击\"初始化系统\"开始配置": "Veuillez confirmer les informations de configuration suivantes, cliquez sur \"Initialiser le système\" pour commencer la configuration", + "请确认商户和所选环境密钥一致。": "Vérifiez que le marchand et les clés de l'environnement sélectionné correspondent.", "请确认您已了解禁用两步验证的后果": "Veuillez confirmer que vous comprenez les conséquences de la désactivation de l'authentification à deux facteurs", "请确认管理员密码": "Veuillez confirmer le mot de passe de l'administrateur", "请稍后几秒重试,Turnstile 正在检查用户环境!": "Veuillez réessayer dans quelques secondes, Turnstile vérifie l'environnement utilisateur !", @@ -3536,6 +3636,8 @@ "镜像配置": "Image Configuration", "问题标题": "Titre de la question", "队列中": "En file d'attente", + "阶梯计费(未匹配到对应阶梯)": "Facturation par paliers (aucun palier correspondant)", + "阶梯计费(表达式解析失败)": "Facturation par paliers (échec de l'analyse de l'expression)", "附加条件": "Conditions supplémentaires", "降低您账户的安全性": "Réduire la sécurité de votre compte", "降级": "Rétrograder", @@ -3647,8 +3749,6 @@ "默认折叠侧边栏": "Réduire la barre latérale par défaut", "默认测试模型": "Modèle de test par défaut", "默认用户消息": "Bonjour", - "默认补全倍率": "Taux de complétion par défaut", - "阶梯计费(表达式解析失败)": "Facturation par paliers (échec de l'analyse de l'expression)", - "阶梯计费(未匹配到对应阶梯)": "Facturation par paliers (aucun palier correspondant)" + "默认补全倍率": "Taux de complétion par défaut" } } diff --git a/web/classic/src/i18n/locales/ja.json b/web/classic/src/i18n/locales/ja.json index 5cfa0a2615f2..64279cb2577b 100644 --- a/web/classic/src/i18n/locales/ja.json +++ b/web/classic/src/i18n/locales/ja.json @@ -14,14 +14,12 @@ ",点击更新": "、クリックして更新してください", "(共 {{total}} 个,省略 {{omit}} 个)": "", "(共 {{total}} 个)": "", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "現在は Epay API のみ対応しています。コールバックアドレスは一般設定で設定してください。", - "请确认商户和所选环境密钥一致。": "加盟店情報と選択中の環境の鍵が一致していることを確認してください。", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Merchant、Store、Product と選択中の環境の鍵が一致していることを確認してください。", "(筛选后显示 {{count}} 条)_other": "(Showing {{count}} items after filtering)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(入力 {{input}} tokens / 1M tokens * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(入力 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + オーディオ入力 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(入力 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + キャッシュ {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(入力 {{nonImageInput}} tokens + 画像入力 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "[最大リクエスト数]と[最大成功リクエスト数]の最大値は2147483647です", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[最大リクエスト数]は0以上、[最大成功リクエスト数]は1以上である必要があります", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", @@ -68,12 +66,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "5m cache creation price: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m cache creation ratio: {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "5m キャッシュ作成価格:{{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - 高", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AGPL v3.0协议": "AGPL v3.0ライセンス", "AI 对话": "AIチャット", "AI模型测试环境": "AIモデルテスト環境", "AI模型配置": "AIモデル設定", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "AK/SK mode uses AccessKey and SecretAccessKey; API Key mode uses an API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "anthropic-beta JSON 示例": "", + "Anthropic-compatible models": "Anthropic-compatible models", "API Key": "API Key", "API Key 模式下不支持批量创建": "APIキーモードでは一括作成はサポート対象外です", "API Key 验证失败": "API Key verification failed", @@ -98,11 +104,14 @@ "Bark推送URL必须以http://或https://开头": "BarkプッシュURLは、http://またはhttps://で始まることが必須です", "Bark通知": "Bark通知", "Basic Auth 头": "Basic Auth ヘッダー", + "Before you start": "Before you start", "Cached tokens": "Cached tokens", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "キャッシュトークン比率はバックエンドから返されます:Claudeのセマンティクスはcached/(prompt+cached)、その他はcached/promptで計算されます。", "Changing batch type to:": "Changing batch type to:", "ChatCompletions→Responses 兼容配置": "ChatCompletions→Responses 互換設定", "ChatCompletions→Responses 兼容配置(Beta)": "ChatCompletions→Responses 互換設定(ベータ)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Claude 强制 beta=true": "Claude 強制 beta=true", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude は既存のリクエストヘッダーにこれらの値を追加します。既存の同名ヘッダーは上書きされず、重複した値は自動的に無視されます。", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Claude思考モード:BudgetTokens = MaxTokens * BudgetTokensの割合", @@ -111,23 +120,39 @@ "Claude请求头追加": "Claudeリクエストヘッダーの追加", "Client ID": "Client ID", "Client Secret": "Client Secret", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Codex 授权": "Codex 認可", "Codex 渠道不支持批量创建": "Codexチャネルはバッチ作成をサポートしていません", "common.changeLanguage": "common.changeLanguage", "Completion tokens": "Completion tokens", "Configuration": "Configuration", + "Configuration reference": "Configuration reference", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "context_int/context_stringはリクエストコンテキストから読み取り、gjsonはエントリリクエストのJSON bodyからgjsonパスで読み取ります。", "CPU 使用率超过此值时拒绝请求": "CPU使用率がこの値を超えた場合にリクエストを拒否", "CPU 阈值 (%)": "CPUしきい値 (%)", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Creem API 密钥,敏感信息不显示": "Creem API key, sensitive information not displayed", "Creem Setting Tips": "Creem only supports preset fixed-amount products. These products and their prices need to be created and configured in advance on the Creem website, so custom dynamic amount top-ups are not supported. Configure the product name and price on Creem, obtain the Product Id, and then fill it in for the product below. Set the top-up amount and display price for this product in the new API.", "Creem 介绍": "Creem is the payment partner you always deserved, we strive for simplicity and straightforwardness on our APIs.", "Creem 充值": "Creem Recharge", "Creem 设置": "Creem Setting", + "Default model name for requests": "Default model name for requests", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default と vip は管理者が「ユーザー管理」で割り当てるのみ可能です。ユーザー等級別の料金設定やテストなど、ユーザーに自主選択させたくないシーンに適しています。", "default为默认设置,可单独设置每个分类的安全等级": "「default」はデフォルト設定で、各分類のセキュリティレベルを個別に設定できます", "default为默认设置,可单独设置每个模型的版本": "「default」はデフォルト設定で、各モデルのバージョンを個別に設定できます", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Difyチャネルはchatflowとagentのみに対応しており、agentは画像のサポート対象外です", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "Discord Client ID": "Discord Client ID", "Discord Client Secret": "Discord Client Secret", @@ -135,11 +160,24 @@ "Discovery claims": "Discovery claims", "Discovery scopes": "Discovery scopes", "Discovery 建议 scopes:": "推奨Discovery scopes:", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", + "Environment variables": "環境変数", "EUR (欧元)": "EUR (Euro)", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "false": "false", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "GC 已执行": "GC実行済み", "GC 执行失败": "GC実行失敗", "GC 次数": "GC回数", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini安全设置": "Geminiセキュリティ設定", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Gemini思考モード:BudgetTokens = MaxTokens * BudgetTokensの割合", "Gemini思考适配设置": "Gemini思考モード設定", @@ -160,8 +198,17 @@ "Haiku 模型": "Haikuモデル", "Homepage URL 填": "ホームページURLを入力してください", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "include_obfuscationはResponsesストリームの難読化フィールドを制御します。クライアントがこのセキュリティ保護を無効にするのを防ぐため、デフォルトで無効です", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "inference_geoフィールドはClaudeのデータ常駐推論リージョンを制御します。未承認の地理情報のパススルーを防ぐため、デフォルトで無効です", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "IP": "IP", "IP白名单": "IP Whitelist", "IP白名单(支持CIDR表达式)": "IPホワイトリスト(CIDR表記に対応)", @@ -184,15 +231,19 @@ "Key 摘要": "Key 要約", "Key 来源": "キーソース", "Key 来源类型": "キーソースタイプ", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Linux DO Client ID": "Linux DO Client ID", "Linux DO Client Secret": "Linux DO Client Secret", "LinuxDO": "LinuxDO", "LinuxDO ID": "LinuxDO ID", "Logo 图片地址": "ロゴ画像URL", + "Manual configuration": "Manual configuration", "Midjourney 任务记录": "Midjourneyタスク履歴", "MIT许可证": "MITライセンス", "New API项目仓库地址:": "New APIプロジェクトリポジトリ:", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "NewAPIはデフォルトでは入力リクエストのUser-Agentを上流チャネルにパススルーしません。この条件はこのサイトにアクセスするクライアントの識別にのみ使用されます。", + "Note": "Note", "OAuth Client ID": "OAuth Client ID", "OAuth Client Secret": "OAuth Client Secret", "OAuth 端点": "OAuthエンドポイント", @@ -200,7 +251,15 @@ "OIDC ID": "OIDC ID", "Ollama 模型管理": "Ollama Model Management", "Ollama 版本信息": "Ollama Version Info", + "Open menu": "メニューを開く", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opus 模型": "Opusモデル", + "Overview": "概要", "Passkey": "Passkey", "Passkey 已解绑": "Passkeyが連携解除されました。", "Passkey 已重置": "Passkeyがリセットされました。", @@ -211,17 +270,30 @@ "Pay Method Name": "", "Pay Method Type": "", "Ping间隔(秒)": "Ping間隔(秒)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "POST 参数": "POSTパラメータ", + "Powered by": "Powered by", "price_xxx 的商品价格 ID,新建产品后可获得": "price_xxx の料金ID。新規製品の作成後に取得できます", "Prompt cache hit tokens": "Prompt cache hit tokens", "Prompt tokens": "Prompt tokens", + "Provider": "プロバイダ", "Reasoning Effort": "Reasoning Effort", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Replace": "置換", "Request ID": "Request ID", "RSA 私钥 (沙盒)": "", "RSA 私钥 (生产)": "", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "safety_identifierフィールドは、OpenAIが利用ポリシーに違反する可能性のあるアプリユーザーを特定するために使用されます。ユーザーのプライバシーを保護するため、デフォルトでは無効です", "Scopes(可选)": "Scopes(オプション)", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "service_tierフィールドはサービス階層の指定に使用されます。パススルーを許可すると実際の課金額が想定を上回る場合があるため、追加料金を避けるためにデフォルトでは無効になっています", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "sk_xxx または rk_xxx のStripe APIキー。機密情報は表示されません", "SMTP 发送者邮箱": "SMTP 送信元メールアドレス", "SMTP 服务器地址": "SMTP サーバーURL", @@ -236,6 +308,7 @@ "SSRF防护设置": "SSRF保護設定", "SSRF防护详细说明": "SSRF保護の詳細説明", "standard 已被移除,vip 用户看不到": "standard は削除され、vipユーザーには表示されません", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "storeフィールドは、製品の評価と最適化のためにOpenAIがリクエストデータを保存することを許可します。デフォルトでは無効です。有効にすると、Codexが正常に利用できなくなる場合があります", "Stripe 设置": "Stripe 設定", "Stripe/Creem 商品ID(可选)": "Stripe/Creem 商品ID(任意)", @@ -244,9 +317,12 @@ "Telegram Bot Token": "Telegram Bot Token", "Telegram Bot 名称": "Telegram Bot 名称", "Telegram ID": "Telegram ID", + "Tip": "Tip", "Token Endpoint": "Token Endpoint", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "トークンは比率に基づいて「クォータ/回数」に換算されます。リクエスト完了後に差額精算(追加控除/返金)が行われます。", "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "true": "true", "TTL(秒,0 表示默认)": "TTL(秒、0はデフォルト)", "TTL(秒)": "TTL(秒)", @@ -258,10 +334,14 @@ "URL 标识,只能包含小写字母、数字和连字符": "URL識別子、小文字、数字、ハイフンのみ使用可能", "URL链接": "URL", "USD (美元)": "USD (US Dollar)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", "User Info Endpoint": "User Info Endpoint", "User-Agent include(每行一个,可不写)": "User-Agent include(1行に1つ、オプション)", "Value 正则": "値の正規表現", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AIはfunctionResponse.idフィールドをサポートしていません。有効にすると、このフィールドは自動的に削除されます", + "View guide": "View guide", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "", "Waffo API 参数,可空(最多64位)": "", "Waffo 充值": "", @@ -285,8 +365,12 @@ "Well-Known URL": "Well-Known URL", "Well-Known URL 必须以 http:// 或 https:// 开头": "Well-Known URLは、http://またはhttps://で始まることが必須です", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "whsec_xxx のWebhook署名シークレット。機密情報は表示されません", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Worker地址": "Workerアドレス", "Worker密钥": "WorkerAPIキー", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key", "一个月": "1ヶ月", "一天": "1日", "一小时": "1時間", @@ -501,6 +585,7 @@ "使用说明": "ガイド", "例如 /var/cache/new-api": "例:/var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "例:€, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "例: Asia/Shanghai", "例如 https://docs.newapi.pro": "例:https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "", "例如 https://example.com/console/topup": "", @@ -732,7 +817,6 @@ "最低充值数量": "", "最低充值美元数量": "最低チャージUSD額", "最低充值美元数量必须大于 0": "最低チャージUSD額は 0 より大きい必要があります", - "留空则自动使用当前站点的默认回调地址": "空欄の場合は現在のサイトのデフォルトのコールバックアドレスを使用します", "最后使用时间": "最終利用日時", "最后更新": "Last Updated", "最后请求": "最終リクエスト日時", @@ -776,6 +860,9 @@ "切换为System角色": "システムロールに切り替える", "切换为单密钥模式": "シングルAPIキーモードに切り替える", "切换主题": "テーマを切り替える", + "切换到新版前端": "新しいフロントエンドに切り替え", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "ページを更新して新しいフロントエンドを開きます。続行しますか?", + "切换失败,请稍后重试": "切り替えに失敗しました。しばらくしてからもう一度お試しください", "划转到余额": "残高への振替", "划转邀请额度": "招待クォータの振替", "划转金额最低为": "最低振替額:", @@ -913,9 +1000,6 @@ "取消": "キャンセル", "取消全选": "すべての選択を解除", "取消选择": "Deselect", - "切换到新版前端": "新しいフロントエンドに切り替え", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "ページを更新して新しいフロントエンドを開きます。続行しますか?", - "切换失败,请稍后重试": "切り替えに失敗しました。しばらくしてからもう一度お試しください", "变换": "バリエーション", "变更": "変更", "变焦": "ズーム", @@ -1282,7 +1366,12 @@ "导入配置": "設定のインポート", "导入配置失败: ": "設定のインポートに失敗しました:", "导出": "エクスポート", + "导出失败": "エクスポートに失敗しました", "导出日志失败": "Failed to export logs", + "导出月账单": "月次請求サマリーをエクスポート", + "导出月账单和消费明细": "月次請求サマリーと利用明細をエクスポート", + "导出消费明细": "利用明細をエクスポート", + "导出用量CSV": "利用状況をCSVでエクスポート", "导出配置": "設定のエクスポート", "导出配置失败: ": "設定のエクスポートに失敗しました:", "将 reasoning_content 转换为 标签拼接到内容中": "reasoning_contentをタグに変換し、コンテンツに結合します。", @@ -1324,6 +1413,7 @@ "已分配内存": "割り当て済みメモリ", "已切换为Assistant角色": "アシスタントロールに切り替えられました", "已切换为System角色": "システムロールに切り替えられました", + "已切换到新版前端,正在刷新页面": "新しいフロントエンドに切り替えました。ページを更新しています", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "各モデルが最低倍率グループを利用する最適倍率ビューに切り替えられました", "已初始化": "初期化済み", "已删除": "削除済み", @@ -1340,7 +1430,6 @@ "已发起支付": "支払いを開始しました", "已发送到 Fluent": "Fluentに送信されました", "已取消 Passkey 注册": "Passkeyの登録がキャンセルされました", - "已切换到新版前端,正在刷新页面": "新しいフロントエンドに切り替えました。ページを更新しています", "已同步到渠道": "Synced to Channel", "已启用": "有効", "已启用 Passkey,无需密码即可登录": "Passkeyが有効になり、パスワードなしでログインできます", @@ -1368,6 +1457,7 @@ "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型": "モデル {{name}} の価格設定を {{count}} 個のモデルに一括適用しました", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "全体のリクエストパススルーが有効です。パラメータ上書き、モデルリダイレクト、チャネル適応などの NewAPI 内蔵機能は無効になります。ベストプラクティスではありません。これにより問題が発生しても issue を投稿しないでください。", + "已开始下载": "ダウンロードを開始しました", "已忽略模型": "", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "有効なすべてのチャネルのテストを開始しました。ページを更新して結果を確認してください。", "已打开授权页面": "認可ページを開きました", @@ -1423,6 +1513,8 @@ "平均TPM": "平均TPM", "平移": "パン", "年": "年", + "年份": "年", + "年份无效": "年が無効です", "应付金额": "支払金額", "应用": "適用", "应用同步": "同期の実行", @@ -1478,6 +1570,7 @@ "当前 API 密钥已过期,请在设置中更新。": "Current API key has expired, please update it in settings.", "当前 Ollama 版本为 ${version}": "Current Ollama version is ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "現在、OpenAI / Claudeセマンティクスのみがキャッシュトークン統計をサポートしています。他のチャネルではトークン関連フィールドが非表示になります。", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "現在は Epay API のみ対応しています。コールバックアドレスは一般設定で設定してください。", "当前余额": "現在の残高", "当前值": "現在の値", "当前值不是合法 JSON,无法格式化": "現在の値は有効なJSONではないため、フォーマットできません", @@ -1810,6 +1903,7 @@ "旧格式模板": "旧形式テンプレート", "旧的备用码已失效,请保存新的备用码": "古いバックアップコードは無効になりました。新規バックアップコードを保存してください", "早上好": "おはようございます", + "时区(IANA,可选)": "タイムゾーン(IANA、任意)", "时间": "時間", "时间信息": "Time Information", "时间粒度": "時間粒度", @@ -1920,6 +2014,7 @@ "更新预填组": "事前入力グループの更新", "替换": "", "月": "月", + "月份无效": "月が無効です", "有 Reasoning": "推論あり", "有序字符串数组": "順序付き文字列配列", "有效期": "有効期限", @@ -1929,7 +2024,6 @@ "服务可用性": "サービスの可用性", "服务商": "Service Provider", "服务器IP": "サーバーIP", - "节点名称": "ノード名", "服务器地址": "サーバーURL", "服务器日志功能未启用(未配置日志目录)": "サーバーログ機能が有効になっていません(ログディレクトリが未設定)", "服务器日志管理": "サーバーログ管理", @@ -2396,6 +2490,8 @@ "用户账户创建成功!": "ユーザーアカウントの作成に成功しました", "用户账户管理": "ユーザーアカウント管理", "用时/首字": "所要時間 / 初回トークン", + "用量导出时区说明": "未指定の場合はサーバーのローカル時間で暦月を区切ります。IANAを指定するとそのタイムゾーンの暦月です。", + "用量导出说明": "ユーザー {{name}}(ID {{id}})の選択した暦月についてCSVをエクスポートします(月次=集計、明細=呼び出しごと)。", "由全站货币展示设置统一控制": "サイト全体の通貨表示設定で統一して管理", "由管理员分配,决定用户身份等级(如 default、vip)。": "管理者が割り当て、ユーザーの等級を決定します(例:default、vip)。", "由订阅抵扣": "サブスクリプションで相殺", @@ -2405,6 +2501,7 @@ "留空则使用默认端点;支持 {path, method}": "未入力の場合、デフォルトのエンドポイントが使用されます。{path, method}に対応しています", "留空则保持原有密钥": "空欄で既存のキーを保持", "留空则自动使用 服务器地址 + /api/waffo/webhook": "", + "留空则自动使用当前站点的默认回调地址": "空欄の場合は現在のサイトのデフォルトのコールバックアドレスを使用します", "留空则默认使用服务器地址,注意不能携带http://或者https://": "未入力の場合、デフォルトのサーバーURLが使用されます。ご注意:http://またはhttps://は含めないでください", "登 录": "ログイン", "登录": "ログイン", @@ -2479,6 +2576,7 @@ "确认作废": "無効化の確認", "确认关闭提示": "閉じる確認", "确认冲突项修改": "競合項目の変更の確認", + "确认切换": "切り替えを確認", "确认删除": "削除の確認", "确认删除模型": "Confirm Delete Model", "确认删除该分组?": "このグループを削除しますか?", @@ -2486,7 +2584,6 @@ "确认删除该规则?": "このルールを削除しますか?", "确认取消密码登录": "パスワードログイン無効化の確認", "确认启用": "有効化を確認", - "确认切换": "切り替えを確認", "确认密码": "パスワード(確認用)", "确认导入配置": "設定インポートの確認", "确认延长": "Confirm Extension", @@ -2792,6 +2889,7 @@ "自用模式": "個人モード", "自适应列表": "レスポンシブリスト", "至": "まで", + "节点名称": "ノード名", "节省": "節約", "花费": "費用", "花费时间": "所要時間", @@ -3019,7 +3117,9 @@ "请求配置": "リクエスト設定", "请求预扣费额度": "リクエスト時の事前差し引きクォータ", "请点击我": "こちらをクリック", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Merchant、Store、Product と選択中の環境の鍵が一致していることを確認してください。", "请确认以下设置信息,点击\"初始化系统\"开始配置": "以下の設定内容をご確認の上、「システム初期化」をクリックして設定を開始してください", + "请确认商户和所选环境密钥一致。": "加盟店情報と選択中の環境の鍵が一致していることを確認してください。", "请确认您已了解禁用两步验证的后果": "2要素認証を無効にするリスクを理解しているかご確認ください", "请确认管理员密码": "管理者パスワード(確認用)", "请稍后几秒重试,Turnstile 正在检查用户环境!": "Turnstileがユーザー環境を確認中のため、数秒後に再試行してください", @@ -3505,6 +3605,8 @@ "镜像配置": "Image Configuration", "问题标题": "質問タイトル", "队列中": "待機中", + "阶梯计费(未匹配到对应阶梯)": "段階課金(一致する階層なし)", + "阶梯计费(表达式解析失败)": "段階課金(式の解析に失敗)", "附加条件": "追加条件", "降低您账户的安全性": "アカウントのセキュリティを低下させる", "降级": "降格", @@ -3616,8 +3718,6 @@ "默认折叠侧边栏": "サイドバーをデフォルトで折りたたむ", "默认测试模型": "デフォルトテストモデル", "默认用户消息": "こんにちは", - "默认补全倍率": "デフォルト補完倍率", - "阶梯计费(表达式解析失败)": "段階課金(式の解析に失敗)", - "阶梯计费(未匹配到对应阶梯)": "段階課金(一致する階層なし)" + "默认补全倍率": "デフォルト補完倍率" } } diff --git a/web/classic/src/i18n/locales/ru.json b/web/classic/src/i18n/locales/ru.json index f4950bfeed8e..6e5dc81ce3b5 100644 --- a/web/classic/src/i18n/locales/ru.json +++ b/web/classic/src/i18n/locales/ru.json @@ -1,13 +1,13 @@ { "translation": { - " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Web-поиск {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_few": " + Web-поиск {{count}} раза / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_many": " + Web-поиск {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", + " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Web-поиск {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_other": " + Web-поиск {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 图片生成调用 {{symbol}}{{price}} / 1次 * {{ratioType}} {{ratio}}": " + Генерация изображения {{symbol}}{{price}} / 1 вызов * {{ratioType}} {{ratio}}", - " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Поиск файлов {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_few": " + Поиск файлов {{count}} раза / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_many": " + Поиск файлов {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", + " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_one": " + Поиск файлов {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}_other": " + Поиск файлов {{count}} раз / 1K раз * {{symbol}}{{price}} * {{ratioType}} {{ratio}}", " 个模型设置相同的值": " моделей с одинаковыми значениями настроек", " 吗?": "?", @@ -18,24 +18,22 @@ ",点击更新": ", нажмите для обновления", "(共 {{total}} 个,省略 {{omit}} 个)": "", "(共 {{total}} 个)": "", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Сейчас поддерживается только интерфейс Epay. Настройте адрес обратного вызова в общих настройках.", - "请确认商户和所选环境密钥一致。": "Убедитесь, что мерчант и ключи выбранной среды совпадают.", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Убедитесь, что Merchant, Store, Product и ключи выбранной среды совпадают.", - "(筛选后显示 {{count}} 条)_one": "(Showing {{count}} item after filtering)", "(筛选后显示 {{count}} 条)_few": "(Показано {{count}} элемента после фильтрации)", "(筛选后显示 {{count}} 条)_many": "(Показано {{count}} элементов после фильтрации)", + "(筛选后显示 {{count}} 条)_one": "(Showing {{count}} item after filtering)", "(筛选后显示 {{count}} 条)_other": "(Showing {{count}} items after filtering)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(Ввод {{input}} токенов / 1M токенов * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(Ввод {{nonAudioInput}} токенов / 1M токенов * {{symbol}}{{price}} + аудио ввод {{audioInput}} токенов / 1M токенов * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(Ввод {{nonCacheInput}} токенов / 1M токенов * {{symbol}}{{price}} + кэш {{cacheInput}} токенов / 1M токенов * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(Ввод {{nonImageInput}} токенов + ввод изображения {{imageInput}} токенов / 1M токенов * {{symbol}}{{price}}", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "[Максимальное количество запросов] и [Максимальное количество выполненных запросов] имеют максимальное значение 2147483647.", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[Максимальное количество запросов] должно быть больше или равно 0, [Максимальное количество выполненных запросов] должно быть больше или равно 1.", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", "{{breakdown}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}": "{{breakdown}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}", - "{{count}} 项操作_one": "", "{{count}} 项操作_few": "", "{{count}} 项操作_many": "", + "{{count}} 项操作_one": "", "{{count}} 项操作_other": "", "{{inputDesc}} + {{outputDesc}}{{extraServices}} = {{symbol}}{{total}}": "{{inputDesc}} + {{outputDesc}}{{extraServices}} = {{symbol}}{{total}}", "{{name}} ID": "{{name}} ID", @@ -78,12 +76,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "Цена создания кеша за 5м: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M токенов (множитель создания 5м: {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "Цена создания кеша 5m: {{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - Высокий", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AGPL v3.0协议": "Лицензия AGPL v3.0", "AI 对话": "AI диалог", "AI模型测试环境": "Среда тестирования AI моделей", "AI模型配置": "Конфигурация AI моделей", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "Режим AK/SK: используйте AccessKey и SecretAccessKey; режим API Key: используйте API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "anthropic-beta JSON 示例": "", + "Anthropic-compatible models": "Anthropic-compatible models", "API Key": "API Key", "API Key 模式下不支持批量创建": "Режим API Key не поддерживает массовое создание", "API Key 验证失败": "API Key verification failed", @@ -108,11 +114,14 @@ "Bark推送URL必须以http://或https://开头": "URL для push-уведомлений Bark должен начинаться с http:// или https://", "Bark通知": "Уведомления Bark", "Basic Auth 头": "Заголовок Basic Auth", + "Before you start": "Before you start", "Cached tokens": "Cached tokens", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "Доля кэшированных токенов возвращается бэкендом: семантика Claude считает cached/(prompt+cached), остальные — cached/prompt.", "Changing batch type to:": "Изменение типа пакета на:", "ChatCompletions→Responses 兼容配置": "Настройка совместимости ChatCompletions→Responses", "ChatCompletions→Responses 兼容配置(Beta)": "Совместимость ChatCompletions→Responses (бета)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Claude 强制 beta=true": "Claude принудительно beta=true", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude добавляет эти значения поверх существующих заголовков запроса. Уже существующие заголовки не перезаписываются, а дублирующиеся значения автоматически игнорируются.", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Адаптация мышления Claude BudgetTokens = MaxTokens * процент BudgetTokens", @@ -121,23 +130,39 @@ "Claude请求头追加": "Добавление заголовков запроса Claude", "Client ID": "ID клиента", "Client Secret": "Секрет клиента", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Codex 授权": "Авторизация Codex", "Codex 渠道不支持批量创建": "Канал Codex не поддерживает пакетное создание", "common.changeLanguage": "common.changeLanguage", "Completion tokens": "Completion tokens", "Configuration": "Конфигурация", + "Configuration reference": "Configuration reference", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "context_int/context_string читаются из контекста запроса; gjson читает из JSON body входящего запроса по gjson path.", "CPU 使用率超过此值时拒绝请求": "Отклонять запросы, когда использование CPU превышает это значение", "CPU 阈值 (%)": "Порог CPU (%)", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Creem API 密钥,敏感信息不显示": "API-ключ Creem, чувствительные данные не отображаются", "Creem Setting Tips": "Creem поддерживает только преднастроенные товары с фиксированной суммой. Эти товары и их цены нужно заранее создать и настроить на сайте Creem, поэтому пополнения с произвольной суммой не поддерживаются. Настройте название и цену товара в Creem, получите идентификатор товара и укажите его ниже. Затем задайте сумму пополнения и отображаемую цену в new-api.", "Creem 介绍": "О сервисе Creem", "Creem 充值": "Пополнение через Creem", "Creem 设置": "Настройки Creem", + "Default model name for requests": "Default model name for requests", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default and vip can only be assigned to users by admin in \"User Management\". Suitable for tiered pricing, internal testing, or other scenarios where user self-selection is not desired.", "default为默认设置,可单独设置每个分类的安全等级": "default - это настройка по умолчанию, можно отдельно установить уровень безопасности для каждой категории", "default为默认设置,可单独设置每个模型的版本": "default - это настройка по умолчанию, можно отдельно установить версию для каждой модели", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Канал Dify адаптирован только для chatflow и agent, и agent не поддерживает изображения!", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "Discord Client ID": "ID клиента Discord", "Discord Client Secret": "Секрет клиента Discord", @@ -145,11 +170,24 @@ "Discovery claims": "Discovery claims", "Discovery scopes": "Discovery scopes", "Discovery 建议 scopes:": "Рекомендуемые Discovery scopes:", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", + "Environment variables": "Переменные окружения", "EUR (欧元)": "EUR (евро)", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "false": "false", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "GC 已执行": "GC выполнен", "GC 执行失败": "Ошибка выполнения GC", "GC 次数": "Количество GC", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini安全设置": "Настройки безопасности Gemini", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Адаптация мышления Gemini BudgetTokens = MaxTokens * процент BudgetTokens", "Gemini思考适配设置": "Настройки адаптации мышления Gemini", @@ -170,8 +208,17 @@ "Haiku 模型": "Модель Haiku", "Homepage URL 填": "URL домашней страницы:", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "include_obfuscation управляет полями обфускации в потоке Responses. Отключено по умолчанию, чтобы клиенты не отключали эту защиту", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "Поле inference_geo управляет регионом размещения данных инференса Claude. Отключено по умолчанию для предотвращения несанкционированной передачи географической информации", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "IP": "IP", "IP白名单": "IP Whitelist", "IP白名单(支持CIDR表达式)": "Белый список IP (поддерживает выражения CIDR)", @@ -194,15 +241,19 @@ "Key 摘要": "Сводка Key", "Key 来源": "Источник ключа", "Key 来源类型": "Тип источника ключа", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Linux DO Client ID": "ID клиента Linux DO", "Linux DO Client Secret": "Секрет клиента Linux DO", "LinuxDO": "LinuxDO", "LinuxDO ID": "ID LinuxDO", "Logo 图片地址": "Адрес изображения логотипа", + "Manual configuration": "Manual configuration", "Midjourney 任务记录": "Записи задач Midjourney", "MIT许可证": "Лицензия MIT", "New API项目仓库地址:": "Адрес репозитория проекта New API:", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "NewAPI по умолчанию не передаёт User-Agent входящего запроса в вышестоящие каналы; это условие используется только для идентификации клиентов, обращающихся к данному сайту.", + "Note": "Note", "OAuth Client ID": "OAuth Client ID", "OAuth Client Secret": "OAuth Client Secret", "OAuth 端点": "Конечные точки OAuth", @@ -210,7 +261,15 @@ "OIDC ID": "ID OIDC", "Ollama 模型管理": "Ollama Model Management", "Ollama 版本信息": "Ollama Version Info", + "Open menu": "Открыть меню", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opus 模型": "Модель Opus", + "Overview": "Обзор", "Passkey": "Passkey", "Passkey 已解绑": "Passkey отвязан", "Passkey 已重置": "Passkey сброшен", @@ -221,17 +280,30 @@ "Pay Method Name": "", "Pay Method Type": "", "Ping间隔(秒)": "Интервал Ping (секунды)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "POST 参数": "Параметры POST", + "Powered by": "Powered by", "price_xxx 的商品价格 ID,新建产品后可获得": "ID цены товара price_xxx, можно получить после создания нового продукта", "Prompt cache hit tokens": "Prompt cache hit tokens", "Prompt tokens": "Prompt tokens", + "Provider": "Провайдер", "Reasoning Effort": "Усилие рассуждения", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Replace": "Заменить", "Request ID": "Request ID", "RSA 私钥 (沙盒)": "", "RSA 私钥 (生产)": "", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "Поле safety_identifier помогает OpenAI идентифицировать пользователей приложений, которые могут нарушать политику использования. По умолчанию отключено для защиты конфиденциальности пользователей", "Scopes(可选)": "Scopes (необязательно)", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "Поле service_tier используется для указания уровня сервиса, позволяет передавать параметры, которые могут привести к фактической оплате выше ожидаемой. По умолчанию отключено для избежания дополнительных расходов", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "Ключ Stripe sk_xxx или rk_xxx, конфиденциальная информация не отображается", "SMTP 发送者邮箱": "Email отправителя SMTP", "SMTP 服务器地址": "Адрес сервера SMTP", @@ -246,6 +318,7 @@ "SSRF防护设置": "Настройки защиты SSRF", "SSRF防护详细说明": "Подробное описание защиты SSRF", "standard 已被移除,vip 用户看不到": "standard has been removed, vip users cannot see it", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "Поле store используется для авторизации OpenAI хранить данные запросов для оценки и оптимизации продукта. По умолчанию отключено, после включения может привести к неработоспособности Codex", "Stripe 设置": "Настройки Stripe", "Stripe/Creem 商品ID(可选)": "ID продукта Stripe/Creem (необязательно)", @@ -254,9 +327,12 @@ "Telegram Bot Token": "Токен бота Telegram", "Telegram Bot 名称": "Имя бота Telegram", "Telegram ID": "ID Telegram", + "Tip": "Tip", "Token Endpoint": "Конечная точка токена", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "Токены конвертируются в квоту/количество использований по коэффициенту. После завершения запроса производится расчёт разницы (дополнительное списание/возврат).", "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "true": "true", "TTL(秒,0 表示默认)": "TTL (секунды, 0 — по умолчанию)", "TTL(秒)": "TTL (секунды)", @@ -268,10 +344,14 @@ "URL 标识,只能包含小写字母、数字和连字符": "Идентификатор URL, допускаются только строчные буквы, цифры и дефисы", "URL链接": "URL ссылка", "USD (美元)": "USD (доллар США)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", "User Info Endpoint": "Конечная точка информации о пользователе", "User-Agent include(每行一个,可不写)": "User-Agent include (по одному в строке, необязательно)", "Value 正则": "Regex значения", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI не поддерживает поле functionResponse.id. При включении это поле будет автоматически удалено", + "View guide": "View guide", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "", "Waffo API 参数,可空(最多64位)": "", "Waffo 充值": "", @@ -295,8 +375,12 @@ "Well-Known URL": "Well-Known URL", "Well-Known URL 必须以 http:// 或 https:// 开头": "Well-Known URL должен начинаться с http:// или https://", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "Ключ подписи Webhook whsec_xxx, конфиденциальная информация не отображается", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Worker地址": "Адрес Worker", "Worker密钥": "Ключ Worker", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key", "一个月": "Один месяц", "一天": "Один день", "一小时": "Один час", @@ -487,9 +571,9 @@ "作用域:包含规则名称": "Область действия: включить имя правила", "你似乎并没有修改什么": "Похоже, вы ничего не изменили", "你可以在“自定义模型名称”处手动添加它们,然后点击填入后再提交,或者直接使用下方操作自动处理。": "Вы можете добавить их вручную в разделе «Пользовательские названия моделей», нажать «Заполнить», затем отправить или воспользоваться действиями ниже для автоматической обработки.", - "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_one": "", "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_few": "", "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_many": "", + "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_one": "", "你还没有处理{{type}}模型({{count}}个)。是否仅提交当前已勾选内容?_other": "", "使用 {{name}} 继续": "Продолжить с {{name}}", "使用 Discord 继续": "Продолжить через Discord", @@ -514,6 +598,7 @@ "使用说明": "Guide", "例如 /var/cache/new-api": "напр.: /var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "Например €, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "напр. Asia/Shanghai", "例如 https://docs.newapi.pro": "Например https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "", "例如 https://example.com/console/topup": "", @@ -707,18 +792,18 @@ "公告更新失败": "Не удалось обновить объявление", "公告类型": "Тип объявления", "共": "Всего", - "共 {{count}} 个密钥_one": "Всего {{count}} ключ", "共 {{count}} 个密钥_few": "Всего {{count}} ключа", "共 {{count}} 个密钥_many": "Всего {{count}} ключей", + "共 {{count}} 个密钥_one": "Всего {{count}} ключ", "共 {{count}} 个密钥_other": "Всего {{count}} ключей", "共 {{count}} 个模型": "Всего {{count}} моделей", - "共 {{count}} 个模型_one": "{{count}} модель", "共 {{count}} 个模型_few": "{{count}} модели", "共 {{count}} 个模型_many": "{{count}} моделей", + "共 {{count}} 个模型_one": "{{count}} модель", "共 {{count}} 个模型_other": "{{count}} моделей", - "共 {{count}} 条日志_one": "{{count}} log entry", "共 {{count}} 条日志_few": "{{count}} записи журнала", "共 {{count}} 条日志_many": "{{count}} записей журнала", + "共 {{count}} 条日志_one": "{{count}} log entry", "共 {{count}} 条日志_other": "{{count}} log entries", "共 {{total}} 项,当前显示 {{start}}-{{end}} 项": "Всего {{total}} элементов, отображаются {{start}}-{{end}}", "关": "Выкл", @@ -753,7 +838,6 @@ "最低充值数量": "", "最低充值美元数量": "Минимальная сумма пополнения в долларах", "最低充值美元数量必须大于 0": "Минимальная сумма пополнения в долларах должна быть больше 0", - "留空则自动使用当前站点的默认回调地址": "Оставьте пустым, чтобы использовать адрес обратного вызова сайта по умолчанию", "最后使用时间": "Время последнего использования", "最后更新": "Last Updated", "最后请求": "Последний запрос", @@ -797,6 +881,9 @@ "切换为System角色": "Переключиться на роль System", "切换为单密钥模式": "Переключиться на режим одного ключа", "切换主题": "Переключить тему", + "切换到新版前端": "Переключиться на новый интерфейс", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "Страница обновится и откроет новый интерфейс. Продолжить?", + "切换失败,请稍后重试": "Не удалось переключиться, повторите попытку позже", "划转到余额": "Перевести на баланс", "划转邀请额度": "Перевести пригласительную квоту", "划转金额最低为": "Минимальная сумма перевода", @@ -934,9 +1021,6 @@ "取消": "Отмена", "取消全选": "Отменить выбор всех", "取消选择": "Deselect", - "切换到新版前端": "Переключиться на новый интерфейс", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "Страница обновится и откроет новый интерфейс. Продолжить?", - "切换失败,请稍后重试": "Не удалось переключиться, повторите попытку позже", "变换": "Трансформация", "变更": "Изменение", "变焦": "Масштабирование", @@ -1303,7 +1387,12 @@ "导入配置": "Импорт конфигурации", "导入配置失败: ": "Ошибка импорта конфигурации: ", "导出": "Экспорт", + "导出失败": "Ошибка экспорта", "导出日志失败": "Failed to export logs", + "导出月账单": "Экспорт месячного счёта", + "导出月账单和消费明细": "Экспорт месячного счёта и детализации расходов", + "导出消费明细": "Экспорт детализации расходов", + "导出用量CSV": "Экспорт использования (CSV)", "导出配置": "Экспорт конфигурации", "导出配置失败: ": "Ошибка экспорта конфигурации: ", "将 reasoning_content 转换为 标签拼接到内容中": "Преобразовать reasoning_content в теги и добавить к содержимому", @@ -1316,9 +1405,9 @@ "将只保留最近 {{value}} 个日志文件,其余将被删除。": "Будут сохранены только последние {{value}} файлов журналов; остальные будут удалены.", "将大请求体临时存储到磁盘": "Временное сохранение больших тел запросов на диск", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。": "Ценовая конфигурация редактируемой модели {{name}} будет применена к {{count}} выбранным моделям.", - "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_one": "", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_few": "", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_many": "", + "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_one": "", "将把当前编辑中的模型 {{name}} 的价格配置,批量应用到已勾选的 {{count}} 个模型。_other": "", "将清除所有保存的配置并恢复默认设置,此操作不可撤销。是否继续?": "Будут очищены все сохраненные конфигурации и восстановлены настройки по умолчанию, эта операция необратима. Продолжить?", "将清除选定时间之前的所有日志": "Будут очищены все логи до выбранного времени", @@ -1334,9 +1423,9 @@ "展示价格": "Отображаемая цена", "嵌套映射:用户分组 → 使用分组 → 倍率": "Nested mapping: user group → using group → ratio", "左侧边栏个人设置": "Персональные настройки левой боковой панели", - "已为 {{count}} 个模型设置{{type}}_one": "Установлено {{type}} для {{count}} модели", "已为 {{count}} 个模型设置{{type}}_few": "Установлено {{type}} для {{count}} моделей", "已为 {{count}} 个模型设置{{type}}_many": "Установлено {{type}} для {{count}} моделей", + "已为 {{count}} 个模型设置{{type}}_one": "Установлено {{type}} для {{count}} модели", "已为 {{count}} 个模型设置{{type}}_other": "Установлено {{type}} для {{count}} моделей", "已为 ${count} 个渠道设置标签!": "Установлены метки для ${count} каналов!", "已从 Discovery 自动填充配置": "Конфигурация автозаполнена из Discovery", @@ -1350,31 +1439,31 @@ "已分配内存": "Выделенная память", "已切换为Assistant角色": "Переключено на роль Assistant", "已切换为System角色": "Переключено на роль System", + "已切换到新版前端,正在刷新页面": "Переключено на новый интерфейс, страница обновляется", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "Переключено на оптимальный вид множителей, каждая модель использует свою группу с минимальным множителем", "已初始化": "Инициализировано", "已删除": "Удалено", "已删除 {{count}} 个令牌!": "Удалено {{count}} токенов!", - "已删除 {{count}} 个令牌!_one": "Удалён {{count}} токен!", "已删除 {{count}} 个令牌!_few": "Удалено {{count}} токена!", "已删除 {{count}} 个令牌!_many": "Удалено {{count}} токенов!", + "已删除 {{count}} 个令牌!_one": "Удалён {{count}} токен!", "已删除 {{count}} 个令牌!_other": "Удалено {{count}} токенов!", - "已删除 {{count}} 条失效兑换码_one": "Удален {{count}} недействительный код купона", "已删除 {{count}} 条失效兑换码_few": "Удалено {{count}} недействительных кода купона", "已删除 {{count}} 条失效兑换码_many": "Удалено {{count}} недействительных кодов купонов", + "已删除 {{count}} 条失效兑换码_one": "Удален {{count}} недействительный код купона", "已删除 {{count}} 条失效兑换码_other": "Удалено {{count}} недействительных кодов купонов", "已删除 ${data} 个通道!": "Удалено ${data} каналов!", "已删除所有禁用渠道,共计 ${data} 个": "Удалены все отключенные каналы, всего ${data}", "已删除消息及其回复": "Сообщение и его ответы удалены", "已勾选": "Выбрано", "已勾选 {{count}} 个模型": "Выбрано моделей: {{count}}", - "已勾选 {{count}} 个模型_one": "", "已勾选 {{count}} 个模型_few": "", "已勾选 {{count}} 个模型_many": "", + "已勾选 {{count}} 个模型_one": "", "已勾选 {{count}} 个模型_other": "", "已发起支付": "Оплата инициирована", "已发送到 Fluent": "Отправлено в Fluent", "已取消 Passkey 注册": "Регистрация Passkey отменена", - "已切换到新版前端,正在刷新页面": "Переключено на новый интерфейс, страница обновляется", "已同步到渠道": "Synced to Channel", "已启用": "Включено", "已启用 Passkey,无需密码即可登录": "Passkey включен, вход без пароля", @@ -1400,11 +1489,12 @@ "已复制自动生成的 API Key": "Auto-generated API Key copied", "已完成": "Completed", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型": "Ценовая конфигурация модели {{name}} массово применена к {{count}} моделям", - "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_one": "", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_few": "", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_many": "", + "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_one": "", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "Глобальная сквозная передача запросов включена. Встроенные возможности NewAPI, такие как переопределение параметров, перенаправление моделей и адаптация канала, будут отключены. Это не является лучшей практикой. Если из-за этого возникнут проблемы, пожалуйста, не создавайте issue.", + "已开始下载": "Загрузка начата", "已忽略模型": "", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "Успешно начато тестирование всех включенных каналов, обновите страницу для просмотра результатов.", "已打开授权页面": "Страница авторизации открыта", @@ -1412,9 +1502,9 @@ "已批量处理上游模型更新:渠道 {{channels}} 个,加入 {{added}} 个,删除 {{removed}} 个,失败 {{fails}} 个": "", "已提交": "Отправлено", "已支付金额": "Amount Paid", - "已新增 {{count}} 个模型:{{list}}_one": "Добавлена {{count}} модель: {{list}}", "已新增 {{count}} 个模型:{{list}}_few": "Добавлено {{count}} модели: {{list}}", "已新增 {{count}} 个模型:{{list}}_many": "Добавлено {{count}} моделей: {{list}}", + "已新增 {{count}} 个模型:{{list}}_one": "Добавлена {{count}} модель: {{list}}", "已新增 {{count}} 个模型:{{list}}_other": "Добавлено {{count}} моделей: {{list}}", "已更新完毕所有已启用通道余额!": "Балансы всех включенных каналов обновлены!", "已有保存的配置": "Сохраненные конфигурации уже существуют", @@ -1424,15 +1514,15 @@ "已服务": "Served", "已注销": "Выход выполнен", "已添加": "Добавлено", - "已添加 {{count}} 个模板_one": "Добавлен {{count}} шаблон", "已添加 {{count}} 个模板_few": "Добавлено {{count}} шаблона", "已添加 {{count}} 个模板_many": "Добавлено {{count}} шаблонов", + "已添加 {{count}} 个模板_one": "Добавлен {{count}} шаблон", "已添加 {{count}} 个模板_other": "Добавлено {{count}} шаблонов", "已添加到白名单": "Добавлено в белый список", "已清理 {{count}} 个日志文件,释放 {{size}}": "Очищено {{count}} файлов журналов, освобождено {{size}}", - "已清理 {{count}} 个日志文件,释放 {{size}}_one": "", "已清理 {{count}} 个日志文件,释放 {{size}}_few": "", "已清理 {{count}} 个日志文件,释放 {{size}}_many": "", + "已清理 {{count}} 个日志文件,释放 {{size}}_one": "", "已清理 {{count}} 个日志文件,释放 {{size}}_other": "", "已清空": "Очищено", "已清空测试结果": "Результаты тестов очищены", @@ -1452,9 +1542,9 @@ "已达到购买上限": "Достигнут лимит покупок", "已过期": "Просрочено", "已运行时间": "Uptime", - "已选择 {{count}} 个模型_one": "Выбрана {{count}} модель", "已选择 {{count}} 个模型_few": "Выбрано {{count}} модели", "已选择 {{count}} 个模型_many": "Выбрано {{count}} моделей", + "已选择 {{count}} 个模型_one": "Выбрана {{count}} модель", "已选择 {{count}} 个模型_other": "Выбрано {{count}} моделей", "已选择 {{selected}} / {{total}}": "Выбрано {{selected}} / {{total}}", "已选择 ${count} 个渠道": "Выбрано ${count} каналов", @@ -1470,6 +1560,8 @@ "平均TPM": "Среднее TPM", "平移": "Панорамирование", "年": "год", + "年份": "Год", + "年份无效": "Некорректный год", "应付金额": "К оплате", "应用": "Применить", "应用同步": "Синхронизация приложения", @@ -1525,6 +1617,7 @@ "当前 API 密钥已过期,请在设置中更新。": "Current API key has expired, please update it in settings.", "当前 Ollama 版本为 ${version}": "Current Ollama version is ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "В настоящее время только семантика OpenAI / Claude поддерживает статистику кэшированных токенов. Другие каналы скроют поля, связанные с токенами.", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Сейчас поддерживается только интерфейс Epay. Настройте адрес обратного вызова в общих настройках.", "当前余额": "Текущий баланс", "当前值": "Текущее значение", "当前值不是合法 JSON,无法格式化": "Текущее значение не является допустимым JSON, форматирование невозможно", @@ -1857,6 +1950,7 @@ "旧格式模板": "Шаблон старого формата", "旧的备用码已失效,请保存新的备用码": "Старые резервные коды больше не действительны, пожалуйста, сохраните новые резервные коды", "早上好": "Доброе утро", + "时区(IANA,可选)": "Часовой пояс (IANA, необязательно)", "时间": "Время", "时间信息": "Time Information", "时间粒度": "Временная гранулярность", @@ -1967,6 +2061,7 @@ "更新预填组": "Обновить предварительно заполненную группу", "替换": "", "月": "мес.", + "月份无效": "Некорректный месяц", "有 Reasoning": "Есть рассуждение", "有序字符串数组": "Ordered string array", "有效期": "Срок действия", @@ -1976,7 +2071,6 @@ "服务可用性": "Доступность сервиса", "服务商": "Service Provider", "服务器IP": "IP сервера", - "节点名称": "Имя узла", "服务器地址": "Адрес сервера", "服务器日志功能未启用(未配置日志目录)": "Ведение журнала сервера не включено (каталог журналов не настроен)", "服务器日志管理": "Управление журналами сервера", @@ -2443,6 +2537,8 @@ "用户账户创建成功!": "Аккаунт пользователя создан успешно!", "用户账户管理": "Управление аккаунтами пользователей", "用时/首字": "Время/первый символ", + "用量导出时区说明": "Если не указан, календарный месяц по локальному времени сервера; если указан IANA — по этому поясу.", + "用量导出说明": "Экспорт CSV для пользователя {{name}} (ID {{id}}) за выбранный календарный месяц (счёт = сводка, детали = построчно).", "由全站货币展示设置统一控制": "Управляется глобальными настройками отображения валюты", "由管理员分配,决定用户身份等级(如 default、vip)。": "Assigned by admin, determines user tier (e.g., default, vip).", "由订阅抵扣": "Списано по подписке", @@ -2452,6 +2548,7 @@ "留空则使用默认端点;支持 {path, method}": "Если оставить пустым, будет использоваться конечная точка по умолчанию; поддерживает {path, method}", "留空则保持原有密钥": "Оставьте пустым для сохранения существующего ключа", "留空则自动使用 服务器地址 + /api/waffo/webhook": "", + "留空则自动使用当前站点的默认回调地址": "Оставьте пустым, чтобы использовать адрес обратного вызова сайта по умолчанию", "留空则默认使用服务器地址,注意不能携带http://或者https://": "Если оставить пустым, по умолчанию будет использоваться адрес сервера, обратите внимание, что нельзя указывать http:// или https://", "登 录": "ВОЙТИ", "登录": "Войти", @@ -2497,13 +2594,13 @@ "确定要充值 $": "Подтвердить пополнение на $", "确定要删除供应商 \"{{name}}\" 吗?此操作不可撤销。": "Подтвердить удаление поставщика \"{{name}}\"? Это действие нельзя отменить.", "确定要删除所有已自动禁用的密钥吗?": "Подтвердить удаление всех автоматически отключенных ключей?", - "确定要删除所选的 {{count}} 个令牌吗?_one": "Подтвердить удаление выбранного {{count}} токена?", "确定要删除所选的 {{count}} 个令牌吗?_few": "Подтвердить удаление выбранных {{count}} токенов?", "确定要删除所选的 {{count}} 个令牌吗?_many": "Подтвердить удаление выбранных {{count}} токенов?", + "确定要删除所选的 {{count}} 个令牌吗?_one": "Подтвердить удаление выбранного {{count}} токена?", "确定要删除所选的 {{count}} 个令牌吗?_other": "Подтвердить удаление выбранных {{count}} токенов?", - "确定要删除所选的 {{count}} 个模型吗?_one": "Подтвердить удаление выбранной {{count}} модели?", "确定要删除所选的 {{count}} 个模型吗?_few": "Подтвердить удаление выбранных {{count}} моделей?", "确定要删除所选的 {{count}} 个模型吗?_many": "Подтвердить удаление выбранных {{count}} моделей?", + "确定要删除所选的 {{count}} 个模型吗?_one": "Подтвердить удаление выбранной {{count}} модели?", "确定要删除所选的 {{count}} 个模型吗?_other": "Подтвердить удаление выбранных {{count}} моделей?", "确定要删除此 OAuth 提供商吗?": "Вы уверены, что хотите удалить этого OAuth-провайдера?", "确定要删除此API信息吗?": "Подтвердить удаление этой информации API?", @@ -2530,6 +2627,7 @@ "确认作废": "Подтвердить аннулирование", "确认关闭提示": "Подтвердить закрытие", "确认冲突项修改": "Подтвердить изменение конфликтующих элементов", + "确认切换": "Подтвердить переключение", "确认删除": "Подтвердить удаление", "确认删除模型": "Confirm Delete Model", "确认删除该分组?": "Confirm delete this group?", @@ -2537,7 +2635,6 @@ "确认删除该规则?": "Confirm delete this rule?", "确认取消密码登录": "Подтвердить отмену входа по паролю", "确认启用": "Подтвердить включение", - "确认切换": "Подтвердить переключение", "确认密码": "Подтвердить пароль", "确认导入配置": "Подтвердить импорт конфигурации", "确认延长": "Confirm Extension", @@ -2843,6 +2940,7 @@ "自用模式": "Режим личного использования", "自适应列表": "Адаптивный список", "至": "до", + "节点名称": "Имя узла", "节省": "Экономия", "花费": "Расходы", "花费时间": "Затраченное время", @@ -3070,7 +3168,9 @@ "请求配置": "Настройки запросов", "请求预扣费额度": "Запрос суммы предварительного удержания", "请点击我": "Пожалуйста, нажмите на меня", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Убедитесь, что Merchant, Store, Product и ключи выбранной среды совпадают.", "请确认以下设置信息,点击\"初始化系统\"开始配置": "Пожалуйста, подтвердите следующую информацию о настройках, нажмите \"Инициализация системы\" для начала конфигурации", + "请确认商户和所选环境密钥一致。": "Убедитесь, что мерчант и ключи выбранной среды совпадают.", "请确认您已了解禁用两步验证的后果": "Пожалуйста, подтвердите, что вы понимаете последствия отключения двухфакторной аутентификации", "请确认管理员密码": "Пожалуйста, подтвердите пароль администратора", "请稍后几秒重试,Turnstile 正在检查用户环境!": "Пожалуйста, повторите попытку через несколько секунд, Turnstile проверяет среду пользователя!", @@ -3556,6 +3656,8 @@ "镜像配置": "Image Configuration", "问题标题": "Заголовок проблемы", "队列中": "В очереди", + "阶梯计费(未匹配到对应阶梯)": "Многоуровневая тарификация (подходящий уровень не найден)", + "阶梯计费(表达式解析失败)": "Многоуровневая тарификация (ошибка разбора выражения)", "附加条件": "Дополнительные условия", "降低您账户的安全性": "Снижает безопасность вашего аккаунта", "降级": "Понизить версию", @@ -3667,8 +3769,6 @@ "默认折叠侧边栏": "Сворачивать боковую панель по умолчанию", "默认测试模型": "Модель для тестирования по умолчанию", "默认用户消息": "Здравствуйте", - "默认补全倍率": "Коэффициент завершения по умолчанию", - "阶梯计费(表达式解析失败)": "Многоуровневая тарификация (ошибка разбора выражения)", - "阶梯计费(未匹配到对应阶梯)": "Многоуровневая тарификация (подходящий уровень не найден)" + "默认补全倍率": "Коэффициент завершения по умолчанию" } } diff --git a/web/classic/src/i18n/locales/vi.json b/web/classic/src/i18n/locales/vi.json index 1d83bf6b7381..1882d50724fa 100644 --- a/web/classic/src/i18n/locales/vi.json +++ b/web/classic/src/i18n/locales/vi.json @@ -14,14 +14,12 @@ ",点击更新": ", nhấn để cập nhật", "(共 {{total}} 个,省略 {{omit}} 个)": "", "(共 {{total}} 个)": "", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Hiện tại chỉ hỗ trợ giao diện Epay. Hãy cấu hình địa chỉ gọi lại trong cài đặt chung.", - "请确认商户和所选环境密钥一致。": "Hãy đảm bảo merchant và khóa của môi trường đã chọn khớp nhau.", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Hãy đảm bảo Merchant, Store, Product và khóa của môi trường đã chọn khớp nhau.", "(筛选后显示 {{count}} 条)_other": "(Showing {{count}} items after filtering)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(Đầu vào {{input}} tokens / 1M tokens * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(Đầu vào {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + Đầu vào âm thanh {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(Đầu vào {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + Bộ nhớ đệm {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(Đầu vào {{nonImageInput}} tokens + Đầu vào hình ảnh {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "Giá trị tối đa của [Số lần yêu cầu tối đa] và [Số lần hoàn thành yêu cầu tối đa] là 2147483647.", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[Số lần yêu cầu tối đa] phải lớn hơn hoặc bằng 0, [Số lần hoàn thành yêu cầu tối đa] phải lớn hơn hoặc bằng 1.", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", @@ -68,12 +66,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "5m cache creation price: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m cache creation ratio: {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "Giá tạo bộ nhớ đệm 5m: {{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - Cao", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AGPL v3.0协议": "Giấy phép AGPL v3.0", "AI 对话": "Trò chuyện AI", "AI模型测试环境": "Môi trường thử nghiệm mô hình AI", "AI模型配置": "Cấu hình mô hình AI", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "AK/SK mode uses AccessKey and SecretAccessKey; API Key mode uses an API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "anthropic-beta JSON 示例": "", + "Anthropic-compatible models": "Anthropic-compatible models", "API Key": "API Key", "API Key 模式下不支持批量创建": "Không hỗ trợ tạo hàng loạt trong chế độ API Key", "API Key 验证失败": "API Key verification failed", @@ -98,11 +104,14 @@ "Bark推送URL必须以http://或https://开头": "URL đẩy Bark phải bắt đầu bằng http:// hoặc https://", "Bark通知": "Thông báo Bark", "Basic Auth 头": "Header Basic Auth", + "Before you start": "Before you start", "Cached tokens": "Cached tokens", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "Tỷ lệ cached tokens được trả về từ backend: ngữ nghĩa Claude tính theo cached/(prompt+cached), còn lại tính theo cached/prompt.", "Changing batch type to:": "Đang thay đổi loại hàng loạt thành:", "ChatCompletions→Responses 兼容配置": "Cấu hình tương thích ChatCompletions→Responses", "ChatCompletions→Responses 兼容配置(Beta)": "Tương thích ChatCompletions→Responses (Beta)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Claude 强制 beta=true": "Claude buộc beta=true", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude sẽ thêm các giá trị này vào các tiêu đề yêu cầu hiện có. Các tiêu đề cùng tên sẽ không bị ghi đè và các giá trị trùng lặp sẽ tự động bị bỏ qua.", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Thích ứng tư duy Claude BudgetTokens = MaxTokens * Tỷ lệ phần trăm BudgetTokens", @@ -111,23 +120,39 @@ "Claude请求头追加": "Thêm tiêu đề yêu cầu Claude", "Client ID": "Client ID", "Client Secret": "Client Secret", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Codex 授权": "Xác thực Codex", "Codex 渠道不支持批量创建": "Kênh Codex không hỗ trợ tạo hàng loạt", "common.changeLanguage": "Thay đổi ngôn ngữ", "Completion tokens": "Completion tokens", "Configuration": "Cấu hình", + "Configuration reference": "Configuration reference", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "context_int/context_string đọc từ context yêu cầu; gjson đọc từ JSON body yêu cầu đầu vào theo gjson path.", "CPU 使用率超过此值时拒绝请求": "Từ chối yêu cầu khi sử dụng CPU vượt quá giá trị này", "CPU 阈值 (%)": "Ngưỡng CPU (%)", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Creem API 密钥,敏感信息不显示": "Khóa API Creem, thông tin nhạy cảm không được hiển thị", "Creem Setting Tips": "Creem chỉ hỗ trợ các sản phẩm có số tiền cố định được thiết lập sẵn. Các sản phẩm này và giá của chúng cần được tạo và cấu hình trước trên trang web Creem, vì vậy việc nạp tiền số tiền động tùy chỉnh không được hỗ trợ. Cấu hình tên sản phẩm và giá trên Creem, lấy ID sản phẩm, sau đó điền vào sản phẩm bên dưới. Đặt số tiền nạp và giá hiển thị cho sản phẩm này trong API mới.", "Creem 介绍": "Creem là đối tác thanh toán mà bạn luôn xứng đáng có được, chúng tôi phấn đấu cho sự đơn giản và thẳng thắn trên các API của mình.", "Creem 充值": "Nạp tiền Creem", "Creem 设置": "Cài đặt Creem", + "Default model name for requests": "Default model name for requests", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default and vip can only be assigned to users by admin in \"User Management\". Suitable for tiered pricing, internal testing, or other scenarios where user self-selection is not desired.", "default为默认设置,可单独设置每个分类的安全等级": "\"default\" là cài đặt mặc định, và mỗi danh mục có thể được đặt riêng", "default为默认设置,可单独设置每个模型的版本": "\"default\" là cài đặt mặc định, và mỗi mô hình có thể được đặt riêng", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Kênh Dify chỉ hỗ trợ chatflow và agent, và agent không hỗ trợ hình ảnh!", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "Discord Client ID": "Discord Client ID", "Discord Client Secret": "Discord Client Secret", @@ -135,11 +160,24 @@ "Discovery claims": "Discovery claims", "Discovery scopes": "Discovery scopes", "Discovery 建议 scopes:": "Discovery scopes được đề xuất:", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", + "Environment variables": "Biến môi trường", "EUR (欧元)": "EUR (Euro)", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "false": "sai", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "GC 已执行": "GC đã thực thi", "GC 执行失败": "Thực thi GC thất bại", "GC 次数": "Số lần GC", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini安全设置": "Cài đặt an toàn Gemini", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Thích ứng tư duy Gemini BudgetTokens = MaxTokens * Tỷ lệ phần trăm BudgetTokens", "Gemini思考适配设置": "Cài đặt thích ứng tư duy Gemini", @@ -160,8 +198,17 @@ "Haiku 模型": "Model Haiku", "Homepage URL 填": "Điền URL trang chủ", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "include_obfuscation kiểm soát trường làm mờ trong luồng Responses. Mặc định tắt để tránh client vô hiệu hóa bảo vệ bảo mật này", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "Trường inference_geo kiểm soát vùng lưu trữ dữ liệu suy luận của Claude. Mặc định tắt để ngăn truyền thông tin địa lý trái phép", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "IP": "IP", "IP白名单": "IP Whitelist", "IP白名单(支持CIDR表达式)": "Danh sách trắng IP (hỗ trợ biểu thức CIDR)", @@ -184,15 +231,19 @@ "Key 摘要": "Tóm tắt Key", "Key 来源": "Nguồn Key", "Key 来源类型": "Loại nguồn Key", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Linux DO Client ID": "Linux DO Client ID", "Linux DO Client Secret": "Linux DO Client Secret", "LinuxDO": "LinuxDO", "LinuxDO ID": "LinuxDO ID", "Logo 图片地址": "Địa chỉ hình ảnh Logo", + "Manual configuration": "Manual configuration", "Midjourney 任务记录": "Hồ sơ tác vụ Midjourney", "MIT许可证": "Giấy phép MIT", "New API项目仓库地址:": "Địa chỉ kho dự án New API: ", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "NewAPI mặc định không truyền User-Agent của yêu cầu đến kênh upstream; điều kiện này chỉ dùng để nhận diện client truy cập trang web này.", + "Note": "Note", "OAuth Client ID": "OAuth Client ID", "OAuth Client Secret": "OAuth Client Secret", "OAuth 端点": "Endpoint OAuth", @@ -200,7 +251,15 @@ "OIDC ID": "OIDC ID", "Ollama 模型管理": "Ollama Model Management", "Ollama 版本信息": "Ollama Version Info", + "Open menu": "Mở menu", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opus 模型": "Model Opus", + "Overview": "Tổng quan", "Passkey": "Passkey", "Passkey 已解绑": "Đã xóa Passkey", "Passkey 已重置": "Passkey đã được đặt lại", @@ -211,18 +270,31 @@ "Pay Method Name": "", "Pay Method Type": "", "Ping间隔(秒)": "Khoảng thời gian Ping (giây)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "POST 参数": "Tham số POST", + "Powered by": "Powered by", "price_xxx 的商品价格 ID,新建产品后可获得": "ID giá sản phẩm cho price_xxx, có sẵn sau khi tạo sản phẩm mới", "Prompt cache hit tokens": "Prompt cache hit tokens", "Prompt tokens": "Prompt tokens", + "Provider": "Nhà cung cấp", "Reasoning Effort": "Nỗ lực suy luận", "Recharge Quota": "Hạn ngạch nạp tiền", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Replace": "Thay thế", "Request ID": "Request ID", "RSA 私钥 (沙盒)": "", "RSA 私钥 (生产)": "", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "Trường safety_identifier giúp OpenAI xác định người dùng ứng dụng có thể vi phạm chính sách sử dụng. Tắt theo mặc định để bảo vệ quyền riêng tư của người dùng", "Scopes(可选)": "Scopes (tùy chọn)", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "Trường service_tier được sử dụng để chỉ định cấp độ dịch vụ. Cho phép truyền qua có thể dẫn đến việc tính phí thực tế cao hơn dự kiến. Tắt theo mặc định để tránh phí bổ sung", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "Khóa Stripe cho sk_xxx hoặc rk_xxx, thông tin nhạy cảm không được hiển thị", "SMTP 发送者邮箱": "Email người gửi SMTP", "SMTP 服务器地址": "Địa chỉ máy chủ SMTP", @@ -237,6 +309,7 @@ "SSRF防护设置": "Cài đặt bảo vệ SSRF", "SSRF防护详细说明": "Bảo vệ SSRF ngăn chặn người dùng độc hại sử dụng máy chủ của bạn để truy cập tài nguyên mạng nội bộ. Cấu hình danh sách trắng cho các tên miền/IP đáng tin cậy và hạn chế các cổng được phép. Áp dụng cho tải xuống tệp, webhook và thông báo.", "standard 已被移除,vip 用户看不到": "standard has been removed, vip users cannot see it", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "Trường store ủy quyền cho OpenAI lưu trữ dữ liệu yêu cầu để đánh giá và tối ưu hóa sản phẩm. Tắt theo mặc định. Bật có thể khiến Codex hoạt động không chính xác", "Stripe 设置": "Cài đặt Stripe", "Stripe/Creem 商品ID(可选)": "ID sản phẩm Stripe/Creem (tùy chọn)", @@ -245,9 +318,12 @@ "Telegram Bot Token": "Telegram Bot Token", "Telegram Bot 名称": "Tên Telegram Bot", "Telegram ID": "Telegram ID", + "Tip": "Tip", "Token Endpoint": "Token Endpoint", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "Token được quy đổi thành hạn mức/số lần theo tỷ lệ. Sau khi yêu cầu hoàn tất, chênh lệch sẽ được quyết toán (trừ thêm/hoàn trả).", "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "true": "đúng", "TTL(秒,0 表示默认)": "TTL (giây, 0 là mặc định)", "TTL(秒)": "TTL (giây)", @@ -259,10 +335,14 @@ "URL 标识,只能包含小写字母、数字和连字符": "Định danh URL, chỉ cho phép chữ thường, số và dấu gạch ngang", "URL链接": "Liên kết URL", "USD (美元)": "USD (Đô la Mỹ)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", "User Info Endpoint": "User Info Endpoint", "User-Agent include(每行一个,可不写)": "User-Agent include (mỗi dòng một mục, tùy chọn)", "Value 正则": "Regex giá trị", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI không hỗ trợ trường functionResponse.id. Khi bật, trường này sẽ tự động bị xóa", + "View guide": "View guide", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "", "Waffo API 参数,可空(最多64位)": "", "Waffo 充值": "", @@ -286,8 +366,12 @@ "Well-Known URL": "Well-Known URL", "Well-Known URL 必须以 http:// 或 https:// 开头": "Well-Known URL phải bắt đầu bằng http:// hoặc https://", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "Khóa chữ ký Webhook cho whsec_xxx, thông tin nhạy cảm không được hiển thị", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Worker地址": "Địa chỉ Worker", "Worker密钥": "Khóa Worker", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key", "一个月": "Một tháng", "一天": "Một ngày", "一小时": "Một giờ", @@ -502,6 +586,7 @@ "使用说明": "Guide", "例如 /var/cache/new-api": "VD: /var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "Ví dụ, €, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "ví dụ Asia/Shanghai", "例如 https://docs.newapi.pro": "Ví dụ, https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "", "例如 https://example.com/console/topup": "", @@ -733,7 +818,6 @@ "最低充值数量": "", "最低充值美元数量": "Số tiền nạp đô la tối thiểu", "最低充值美元数量必须大于 0": "Số tiền nạp đô la tối thiểu phải lớn hơn 0", - "留空则自动使用当前站点的默认回调地址": "Để trống để dùng địa chỉ gọi lại mặc định của trang hiện tại", "最后使用时间": "Thời gian sử dụng cuối cùng", "最后更新": "Last Updated", "最后请求": "Yêu cầu cuối cùng", @@ -777,6 +861,9 @@ "切换为System角色": "Chuyển sang vai trò System", "切换为单密钥模式": "Chuyển sang chế độ khóa đơn", "切换主题": "Chuyển chủ đề", + "切换到新版前端": "Chuyển sang frontend mới", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "Trang sẽ được làm mới và mở frontend mới. Tiếp tục?", + "切换失败,请稍后重试": "Chuyển đổi thất bại, vui lòng thử lại sau", "划转到余额": "Chuyển sang số dư", "划转邀请额度": "Chuyển hạn ngạch mời", "划转金额最低为": "Số tiền chuyển tối thiểu là", @@ -914,9 +1001,6 @@ "取消": "Hủy", "取消全选": "Bỏ chọn tất cả", "取消选择": "Deselect", - "切换到新版前端": "Chuyển sang frontend mới", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "Trang sẽ được làm mới và mở frontend mới. Tiếp tục?", - "切换失败,请稍后重试": "Chuyển đổi thất bại, vui lòng thử lại sau", "变换": "Biến đổi", "变更": "Thay đổi", "变焦": "thu phóng", @@ -1283,7 +1367,12 @@ "导入配置": "Nhập cấu hình", "导入配置失败: ": "Nhập cấu hình thất bại: ", "导出": "Xuất", + "导出失败": "Xuất thất bại", "导出日志失败": "Failed to export logs", + "导出月账单": "Xuất hóa đơn tháng", + "导出月账单和消费明细": "Xuất hóa đơn tháng và chi tiết tiêu thụ", + "导出消费明细": "Xuất chi tiết tiêu thụ", + "导出用量CSV": "Xuất CSV sử dụng", "导出配置": "Xuất cấu hình", "导出配置失败: ": "Xuất cấu hình thất bại: ", "将 reasoning_content 转换为 标签拼接到内容中": "Chuyển đổi reasoning_content thành thẻ và nối vào nội dung", @@ -1325,6 +1414,7 @@ "已分配内存": "Bộ nhớ đã phân bổ", "已切换为Assistant角色": "Đã chuyển sang vai trò Assistant", "已切换为System角色": "Đã chuyển sang vai trò System", + "已切换到新版前端,正在刷新页面": "Đã chuyển sang frontend mới, đang làm mới trang", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "Đã chuyển sang chế độ xem tỷ lệ tối ưu, mỗi mô hình sử dụng nhóm tỷ lệ thấp nhất của nó", "已初始化": "Đã khởi tạo", "已删除": "Đã xóa", @@ -1341,7 +1431,6 @@ "已发起支付": "Đã khởi tạo thanh toán", "已发送到 Fluent": "Đã gửi đến Fluent", "已取消 Passkey 注册": "Đã hủy đăng ký Passkey", - "已切换到新版前端,正在刷新页面": "Đã chuyển sang frontend mới, đang làm mới trang", "已同步到渠道": "Synced to Channel", "已启用": "Đã bật", "已启用 Passkey,无需密码即可登录": "Đã bật Passkey, đăng nhập không cần mật khẩu", @@ -1369,6 +1458,7 @@ "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型": "Đã áp dụng hàng loạt cấu hình giá của mô hình {{name}} cho {{count}} mô hình", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "Đã bật truyền qua yêu cầu toàn cục. Các tính năng tích hợp của NewAPI như ghi đè tham số, chuyển hướng mô hình và thích ứng kênh sẽ bị vô hiệu hóa. Đây không phải là thực hành tốt nhất. Nếu phát sinh vấn đề, vui lòng không gửi issue.", + "已开始下载": "Đã bắt đầu tải xuống", "已忽略模型": "", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "Đã bắt đầu kiểm tra tất cả các kênh đã bật thành công. Vui lòng làm mới trang để xem kết quả.", "已打开授权页面": "Đã mở trang xác thực", @@ -1424,6 +1514,8 @@ "平均TPM": "TPM trung bình", "平移": "Pan", "年": "năm", + "年份": "Năm", + "年份无效": "Năm không hợp lệ", "应付金额": "Số tiền phải trả", "应用": "Áp dụng", "应用同步": "Áp dụng đồng bộ hóa", @@ -1479,6 +1571,7 @@ "当前 API 密钥已过期,请在设置中更新。": "Current API key has expired, please update it in settings.", "当前 Ollama 版本为 ${version}": "Current Ollama version is ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "Hiện chỉ ngữ nghĩa OpenAI / Claude hỗ trợ thống kê token đệm. Các kênh khác sẽ ẩn các trường liên quan đến token.", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "Hiện tại chỉ hỗ trợ giao diện Epay. Hãy cấu hình địa chỉ gọi lại trong cài đặt chung.", "当前余额": "Số dư hiện tại", "当前值": "Giá trị hiện tại", "当前值不是合法 JSON,无法格式化": "Giá trị hiện tại không phải JSON hợp lệ, không thể định dạng", @@ -1811,6 +1904,7 @@ "旧格式模板": "Mẫu định dạng cũ", "旧的备用码已失效,请保存新的备用码": "Mã dự phòng cũ đã bị vô hiệu hóa, vui lòng lưu mã dự phòng mới", "早上好": "Chào buổi sáng", + "时区(IANA,可选)": "Múi giờ (IANA, tùy chọn)", "时间": "Thời gian", "时间信息": "Time Information", "时间粒度": "Độ chi tiết thời gian", @@ -1921,6 +2015,7 @@ "更新预填组": "Cập nhật nhóm điền sẵn", "替换": "", "月": "tháng", + "月份无效": "Tháng không hợp lệ", "有 Reasoning": "Có lập luận", "有序字符串数组": "Ordered string array", "有效期": "Thời hạn", @@ -1930,7 +2025,6 @@ "服务可用性": "Trạng thái dịch vụ", "服务商": "Service Provider", "服务器IP": "IP máy chủ", - "节点名称": "Tên nút", "服务器地址": "Địa chỉ máy chủ", "服务器日志功能未启用(未配置日志目录)": "Ghi nhật ký máy chủ chưa được bật (chưa cấu hình thư mục nhật ký)", "服务器日志管理": "Quản lý nhật ký máy chủ", @@ -2578,6 +2672,8 @@ "用户额度设置": "Cài đặt hạn ngạch người dùng", "用时/首字": "Thời gian/từ đầu tiên", "用途": "Mục đích", + "用量导出时区说明": "Để trống thì tháng dương lịch theo giờ máy chủ; nhập IANA thì theo múi giờ đó.", + "用量导出说明": "Xuất CSV cho người dùng {{name}} (ID {{id}}) theo tháng dương lịch đã chọn (hóa đơn tháng = tóm tắt, chi tiết = từng lần gọi).", "由全站货币展示设置统一控制": "Được điều khiển bởi cài đặt hiển thị tiền tệ toàn site", "由管理员分配,决定用户身份等级(如 default、vip)。": "Assigned by admin, determines user tier (e.g., default, vip).", "由订阅抵扣": "Khấu trừ bởi gói đăng ký", @@ -2597,6 +2693,7 @@ "留空则保持原有密钥": "Để trống để giữ khóa hiện tại", "留空则禁用": "Để trống để vô hiệu hóa", "留空则自动使用 服务器地址 + /api/waffo/webhook": "", + "留空则自动使用当前站点的默认回调地址": "Để trống để dùng địa chỉ gọi lại mặc định của trang hiện tại", "留空则自动生成": "Để trống để tự động tạo", "留空则默认使用服务器地址,注意不能携带http://或者https://": "Nếu để trống, địa chỉ máy chủ sẽ được sử dụng theo mặc định. Lưu ý rằng không được bao gồm http:// hoặc https://", "登 录": "Đăng nhập", @@ -2707,6 +2804,7 @@ "确认修改": "Xác nhận sửa đổi", "确认关闭提示": "Xác nhận đóng", "确认冲突项修改": "Xác nhận sửa đổi mục xung đột", + "确认切换": "Xác nhận chuyển đổi", "确认删除": "Xác nhận xóa", "确认删除模型": "Confirm Delete Model", "确认删除该分组?": "Confirm delete this group?", @@ -2714,7 +2812,6 @@ "确认删除该规则?": "Confirm delete this rule?", "确认取消密码登录": "Xác nhận hủy đăng nhập mật khẩu", "确认启用": "Xác nhận bật", - "确认切换": "Xác nhận chuyển đổi", "确认密码": "Xác nhận mật khẩu", "确认导入配置": "Xác nhận nhập cấu hình", "确认延长": "Confirm Extension", @@ -3124,6 +3221,7 @@ "自适应列表": "Danh sách thích ứng", "至": "đến", "节点": "Nút", + "节点名称": "Tên nút", "节省": "Tiết kiệm", "花费": "Chi tiêu", "花费时间": "Thời gian chi tiêu", @@ -3421,7 +3519,9 @@ "请求频率限制": "Giới hạn tần suất yêu cầu", "请点击我": "Vui lòng nhấp vào tôi", "请确认": "Vui lòng xác nhận", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "Hãy đảm bảo Merchant, Store, Product và khóa của môi trường đã chọn khớp nhau.", "请确认以下设置信息,点击\"初始化系统\"开始配置": "Vui lòng xác nhận thông tin cài đặt sau, nhấp vào \"Khởi tạo hệ thống\" để bắt đầu cấu hình", + "请确认商户和所选环境密钥一致。": "Hãy đảm bảo merchant và khóa của môi trường đã chọn khớp nhau.", "请确认您已了解禁用两步验证的后果": "Vui lòng xác nhận rằng bạn hiểu hậu quả của việc vô hiệu hóa xác thực hai yếu tố", "请确认是否删除": "Vui lòng xác nhận xóa", "请确认是否重置": "Vui lòng xác nhận đặt lại", @@ -4070,6 +4170,8 @@ "阅读": "Đọc", "阅读更多": "Đọc thêm", "队列中": "Trong hàng đợi", + "阶梯计费(未匹配到对应阶梯)": "Thanh toán theo bậc (không tìm thấy bậc phù hợp)", + "阶梯计费(表达式解析失败)": "Thanh toán theo bậc (không phân tích được biểu thức)", "附加条件": "Điều kiện bổ sung", "降低您账户的安全性": "Giảm bảo mật tài khoản của bạn", "降级": "Hạ cấp", @@ -4181,8 +4283,6 @@ "默认折叠侧边栏": "Mặc định thu gọn thanh bên", "默认测试模型": "Mô hình kiểm tra mặc định", "默认用户消息": "Xin chào", - "默认补全倍率": "Tỷ lệ hoàn thành mặc định", - "阶梯计费(表达式解析失败)": "Thanh toán theo bậc (không phân tích được biểu thức)", - "阶梯计费(未匹配到对应阶梯)": "Thanh toán theo bậc (không tìm thấy bậc phù hợp)" + "默认补全倍率": "Tỷ lệ hoàn thành mặc định" } } diff --git a/web/classic/src/i18n/locales/zh-CN.json b/web/classic/src/i18n/locales/zh-CN.json index 2156b46d8ee2..54f73ff4ee8f 100644 --- a/web/classic/src/i18n/locales/zh-CN.json +++ b/web/classic/src/i18n/locales/zh-CN.json @@ -12,14 +12,12 @@ ",点击更新": ",点击更新", "(共 {{total}} 个,省略 {{omit}} 个)": "(共 {{total}} 个,省略 {{omit}} 个)", "(共 {{total}} 个)": "(共 {{total}} 个)", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "当前仅支持易支付接口,回调地址请在通用设置中配置。", - "请确认商户和所选环境密钥一致。": "请确认商户和所选环境密钥一致。", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "请确认 Merchant、Store、Product 和所选环境密钥一致。", "(筛选后显示 {{count}} 条)_other": "(筛选后显示 {{count}} 条)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}", + ") and choose a model name available on your account.": "),并选择你账户可用的模型名称。", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", @@ -40,7 +38,9 @@ "0 表示不限": "0 表示不限", "0.002-1之间的小数": "0.002-1之间的小数", "0.1以上的小数": "0.1以上的小数", + "0=周日 1=周一 2=周二 3=周三 4=周四 5=周五 6=周六": "0=周日 1=周一 2=周二 3=周三 4=周四 5=周五 6=周六", "1) 点击「打开授权页面」完成登录;2) 浏览器会跳转到 localhost(页面打不开也没关系);3) 复制地址栏完整 URL 粘贴到下方;4) 点击「生成并填入」。": "1) 点击「打开授权页面」完成登录;2) 浏览器会跳转到 localhost(页面打不开也没关系);3) 复制地址栏完整 URL 粘贴到下方;4) 点击「生成并填入」。", + "1=一月 ... 12=十二月": "1=一月 ... 12=十二月", "10 - 最高": "10 - 最高", "1h缓存创建 {{price}} / 1M tokens": "1h缓存创建 {{price}} / 1M tokens", "1h缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}": "1h缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}", @@ -61,12 +61,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - 高", + "Add a custom Anthropic provider or Claude model in Trae settings.": "在 Trae 设置中添加 Anthropic 自定义 Provider 或 Claude 模型。", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "在 OpenCode 中添加 FaceCloud 作为 OpenAI 兼容 Provider。", + "Add the FaceCloud provider configuration:": "添加 FaceCloud Provider 配置:", + "Add the following environment variables:": "添加以下环境变量:", + "Add the following variables:": "添加以下变量:", "AGPL v3.0协议": "AGPL v3.0协议", "AI 对话": "AI 对话", "AI模型测试环境": "AI模型测试环境", "AI模型配置": "AI模型配置", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "也可运行 opencode auth login 添加自定义 Provider:id 设为 facecloud,Base URL 设为 FaceCloud 的 /v1 端点,并按提示粘贴 API Key。", + "and your-model-name with your API key and desired model.": "和 your-model-name 替换为你的 API Key 与目标模型。", "anthropic-beta JSON 示例": "anthropic-beta JSON 示例", + "Anthropic-compatible models": "Anthropic 兼容模型", "API Key": "API Key", "API Key 模式下不支持批量创建": "API Key 模式下不支持批量创建", "API Key 验证失败": "API Key 验证失败", @@ -76,6 +84,7 @@ "API 密钥 (沙盒)": "API 密钥 (沙盒)", "API 密钥 (生产)": "API 密钥 (生产)", "API 文档": "API 文档", + "API 私钥": "API 私钥", "API 配置": "API 配置", "API令牌管理": "API令牌管理", "API使用记录": "API使用记录", @@ -91,11 +100,14 @@ "Bark推送URL必须以http://或https://开头": "Bark推送URL必须以http://或https://开头", "Bark通知": "Bark通知", "Basic Auth 头": "Basic Auth 头", + "Before you start": "开始之前", "Cached tokens": "Cached tokens", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。", "Changing batch type to:": "Changing batch type to:", "ChatCompletions→Responses 兼容配置": "ChatCompletions→Responses 兼容配置", "ChatCompletions→Responses 兼容配置(Beta)": "ChatCompletions→Responses 兼容配置(Beta)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code 从 ~/.claude/settings.json 读取配置。保存后请重启 CLI。", "Claude 强制 beta=true": "Claude 强制 beta=true", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比", @@ -104,23 +116,39 @@ "Claude请求头追加": "Claude请求头追加", "Client ID": "Client ID", "Client Secret": "Client Secret", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy 通过 CODEBUDDY_API_KEY 与 CODEBUDDY_BASE_URL 定位 API。请将 your-model-name 替换为你账户已启用的模型。", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex 使用 ~/.codex/config.toml 配置,并从 FACEAPI_API_KEY 环境变量读取 API Key。", "Codex 授权": "Codex 授权", "Codex 渠道不支持批量创建": "Codex 渠道不支持批量创建", "common.changeLanguage": "common.changeLanguage", "Completion tokens": "Completion tokens", "Configuration": "Configuration", + "Configuration reference": "配置说明", + "Configure Codex": "配置 Codex", + "Configure environment": "配置环境变量", + "Configure FaceCloud": "配置 FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "配置 OpenAI Codex CLI,通过 OpenAI 兼容 Chat Completions 使用 FaceCloud。", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "为 Trae IDE / Trae Agent(Trace)配置完整 FaceCloud 端点路径以使用自定义模型。", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "通过环境变量或 settings.json 将腾讯 CodeBuddy CLI 接入 FaceCloud。", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。", "CPU 使用率超过此值时拒绝请求": "CPU 使用率超过此值时拒绝请求", "CPU 阈值 (%)": "CPU 阈值 (%)", + "Create or edit": "创建或编辑", + "Create the config directory if it does not exist:": "若目录不存在,请先创建:", "Creem API 密钥,敏感信息不显示": "Creem API 密钥,敏感信息不显示", "Creem Setting Tips": "Creem 只支持预设的固定金额产品,这产品以及价格需要提前在Creem网站内创建配置,所以不支持自定义动态金额充值。在Creem端配置产品的名字以及价格,获取Product Id 后填到下面的产品,在new-api为该产品设置充值额度,以及展示价格。", "Creem 介绍": "Creem 是一个简单的支付处理平台,支持固定金额产品销售,以及订阅销售。", "Creem 充值": "Creem 充值", "Creem 设置": "Creem 设置", + "Default model name for requests": "默认请求模型名称", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。", "default为默认设置,可单独设置每个分类的安全等级": "default为默认设置,可单独设置每个分类的安全等级", "default为默认设置,可单独设置每个模型的版本": "default为默认设置,可单独设置每个模型的版本", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Dify渠道只适配chatflow和agent,并且agent不支持图片!", + "Disables attribution header when using a proxy": "使用代理时禁用归属请求头", + "Disables experimental beta headers for third-party gateways": "禁用实验性 Beta 请求头,便于第三方网关接入", "Discord": "Discord", "Discord Client ID": "Discord Client ID", "Discord Client Secret": "Discord Client Secret", @@ -128,11 +156,25 @@ "Discovery claims": "Discovery claims", "Discovery scopes": "Discovery scopes", "Discovery 建议 scopes:": "Discovery 建议 scopes:", + "Edit opencode.json with the FaceCloud provider:": "在 opencode.json 中添加 FaceCloud Provider:", + "Endpoint reference": "端点参考", + "Environment variable holding your API key": "存放 API Key 的环境变量名", + "Environment variables": "环境变量", "EUR (欧元)": "EUR (欧元)", + "Export the following variables in your terminal or shell profile:": "在终端或 Shell 配置中导出以下变量:", + "Expr 预览": "Expr 预览", + "FaceCloud gateway URL": "FaceCloud 网关地址", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini 兼容基础 URL", + "FaceCloud Integration Guides": "FaceCloud 集成教程", "false": "false", + "For model availability and pricing, visit the pricing page or dashboard.": "模型可用性与价格请查看定价页或控制台。", + "For OpenAI-compatible models, set the request URL to:": "OpenAI 兼容模型请将请求 URL 设为:", + "Full endpoint URL": "完整端点 URL", "GC 已执行": "GC 已执行", "GC 执行失败": "GC 执行失败", "GC 次数": "GC 次数", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI 默认从 ~/.env 加载环境变量,也可在 Shell 配置文件中导出。", "Gemini安全设置": "Gemini安全设置", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比", "Gemini思考适配设置": "Gemini思考适配设置", @@ -152,8 +194,17 @@ "Grok设置": "Grok设置", "Homepage URL 填": "Homepage URL 填", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "若 CodeBuddy 支持 settings.json 的 env 字段(类似 Claude Code),可持久化配置:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "若返回 404,请检查 Trae 中是否填写了完整路径,并确认 FaceCloud 已开放对应转发路由。", + "Important": "重要", + "in the examples below with your real key. API base URL:": "替换为你的真实 Key。API 基础地址:", + "in your home directory.": "(位于用户主目录)。", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息", + "Install Claude Code": "安装 Claude Code", + "Integration": "集成", + "Integration guides": "集成教程", + "Interactive login": "交互式登录", "IP": "IP", "IP白名单": "IP白名单", "IP白名单(支持CIDR表达式)": "IP白名单(支持CIDR表达式)", @@ -176,15 +227,19 @@ "Key 摘要": "Key 摘要", "Key 来源": "Key 来源", "Key 来源类型": "Key 来源类型", + "Launch OpenCode and verify that requests route through FaceCloud.": "启动 OpenCode 并确认请求经由 FaceCloud 转发。", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "了解如何将 FaceCloud 接入常用 AI 编程工具与 IDE。FaceCloud 作为统一 API 网关,只需一个 API Key 即可使用多种模型服务。", "Linux DO Client ID": "Linux DO Client ID", "Linux DO Client Secret": "Linux DO Client Secret", "LinuxDO": "LinuxDO", "LinuxDO ID": "LinuxDO ID", "Logo 图片地址": "Logo 图片地址", + "Manual configuration": "手动配置", "Midjourney 任务记录": "Midjourney 任务记录", "MIT许可证": "MIT许可证", "New API项目仓库地址:": "New API项目仓库地址:", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。", + "Note": "说明", "OAuth Client ID": "OAuth Client ID", "OAuth Client Secret": "OAuth Client Secret", "OAuth 登录失败:": "OAuth 登录失败:", @@ -194,6 +249,14 @@ "OIDC ID": "OIDC ID", "Ollama 模型管理": "Ollama 模型管理", "Ollama 版本信息": "Ollama 版本信息", + "Open menu": "打开菜单", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "打开 Trae IDE 设置,进入自定义模型或 AI Provider 配置。", + "OpenAI-compatible base URL at {{url}}": "OpenAI 兼容基础 URL:{{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI 兼容端点:{{url}}", + "OpenAI-compatible models": "OpenAI 兼容模型", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode 配置文件位于 ~/.config/opencode/opencode.json,也可通过 opencode auth login 交互式登录。", + "Overview": "概览", "Passkey": "Passkey", "Passkey 已解绑": "Passkey 已解绑", "Passkey 已重置": "Passkey 已重置", @@ -204,17 +267,31 @@ "Pay Method Name": "Pay Method Name", "Pay Method Type": "Pay Method Type", "Ping间隔(秒)": "Ping间隔(秒)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "将 Google Gemini CLI 指向 FaceCloud 的 Gemini 兼容 API。", "POST 参数": "POST 参数", + "Powered by": "技术支持", "price_xxx 的商品价格 ID,新建产品后可获得": "price_xxx 的商品价格 ID,新建产品后可获得", + "Product ID": "Product ID", "Prompt cache hit tokens": "Prompt cache hit tokens", "Prompt tokens": "Prompt tokens", + "Provider": "提供商", "Reasoning Effort": "Reasoning Effort", + "Reload your shell or run source on the file after exporting the variable.": "导出变量后请重新加载 Shell,或执行 source 使配置生效。", + "Replace": "将", "Request ID": "Request ID", "RSA 私钥 (沙盒)": "RSA 私钥 (沙盒)", "RSA 私钥 (生产)": "RSA 私钥 (生产)", + "Run claude in a new terminal session to verify the connection.": "在新终端中运行 claude 验证连接。", + "Run codebuddy from the same shell session to use FaceCloud.": "在同一 Shell 会话中运行 codebuddy 即可使用 FaceCloud。", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "运行 Gemini CLI 并发送测试请求以确认连接。", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私", "Scopes(可选)": "Scopes(可选)", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用", + "Set the API key to your FaceCloud key (": "API Key 填写 FaceCloud Key(", + "Set the messages endpoint to:": "将 messages 端点设为:", + "Set your API key": "设置 API Key", + "settings.json (optional)": "settings.json(可选)", + "Shell environment": "Shell 环境变量", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示", "SMTP 发送者邮箱": "SMTP 发送者邮箱", "SMTP 服务器地址": "SMTP 服务器地址", @@ -228,6 +305,8 @@ "SSRF防护设置": "SSRF防护设置", "SSRF防护详细说明": "SSRF防护可防止恶意用户利用您的服务器访问内网资源。您可以配置受信任域名/IP的白名单,并限制允许的端口。适用于文件下载、Webhook回调和通知功能。", "standard 已被移除,vip 用户看不到": "standard 已被移除,vip 用户看不到", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "启动 Codex 并选择 FaceCloud Provider,将 model 改为你账户可用的模型。", + "Store ID": "Store ID", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用", "Stripe 设置": "Stripe 设置", "Stripe/Creem 商品ID(可选)": "Stripe/Creem 商品ID(可选)", @@ -236,9 +315,15 @@ "Telegram Bot Token": "Telegram Bot Token", "Telegram Bot 名称": "Telegram Bot 名称", "Telegram ID": "Telegram ID", + "Tip": "提示", "Token Endpoint": "Token Endpoint", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。", + "Token 估算器": "Token 估算器", + "Token 用量范围": "Token 用量范围", + "Token 类型": "Token 类型", "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace(Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae 需要填写完整 URL(含路径),不要只填域名,请使用下方所示的 /v1/chat/completions 或 /v1/messages。", "true": "true", "TTL(秒,0 表示默认)": "TTL(秒,0 表示默认)", "TTL(秒)": "TTL(秒)", @@ -250,12 +335,18 @@ "URL 标识,只能包含小写字母、数字和连字符": "URL 标识,只能包含小写字母、数字和连字符", "URL链接": "URL链接", "USD (美元)": "USD (美元)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "在 Authorization 头中使用 Bearer 方式携带 FaceCloud API Key。", + "Use chat completions wire format": "使用 Chat Completions 协议", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "在终端中将 FaceCloud 配置为 Claude Code CLI 的 Anthropic API 端点。", "User Info Endpoint": "User Info Endpoint", "User-Agent include(每行一个,可不写)": "User-Agent include(每行一个,可不写)", "Value 正则": "Value 正则", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段", + "View guide": "查看教程", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)", "Waffo API 参数,可空(最多64位)": "Waffo API 参数,可空(最多64位)", + "Waffo Pancake": "Waffo Pancake", + "Waffo Pancake 设置": "Waffo Pancake 设置", "Waffo 充值": "Waffo 充值", "Waffo 充值的最低数量,默认 1": "Waffo 充值的最低数量,默认 1", "Waffo 公钥 (沙盒)": "Waffo 公钥 (沙盒)", @@ -265,6 +356,7 @@ "Waffo 设置": "Waffo 设置", "Web 搜索:{{count}} / 1K * 单价 {{price}} * {{ratioType}} {{ratio}} = {{amount}}": "Web 搜索:{{count}} / 1K * 单价 {{price}} * {{ratioType}} {{ratio}} = {{amount}}", "Web 搜索调用 {{webSearchCallCount}} 次": "Web 搜索调用 {{webSearchCallCount}} 次", + "Webhook 公钥": "Webhook 公钥", "Webhook 密钥": "Webhook 密钥", "Webhook 签名密钥": "Webhook 签名密钥", "Webhook地址": "Webhook地址", @@ -277,11 +369,17 @@ "Well-Known URL": "Well-Known URL", "Well-Known URL 必须以 http:// 或 https:// 开头": "Well-Known URL 必须以 http:// 或 https:// 开头", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "替换为你的 FaceCloud API Key,并将 GEMINI_MODEL 设为你账户支持的模型。", + "with your FaceCloud API key.": "替换为你的 FaceCloud API Key。", "Worker地址": "Worker地址", "Worker密钥": "Worker密钥", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "你需要一个 FaceCloud API Key。在控制台创建后,将示例中的", + "Your FaceCloud API key": "你的 FaceCloud API Key", "一个月": "一个月", "一天": "一天", "一小时": "一小时", + "一次性余额充值": "一次性余额充值", + "一次性支付,付款后自动返回": "一次性支付,付款后自动返回", "一次调用消耗多少刀,优先级大于模型倍率": "一次调用消耗多少刀,优先级大于模型倍率", "一行一个,不区分大小写": "一行一个,不区分大小写", "一行一个屏蔽词,不需要符号分割": "一行一个屏蔽词,不需要符号分割", @@ -297,6 +395,7 @@ "上游倍率同步": "上游倍率同步", "上游模型管理": "上游模型管理", "上游返回": "上游返回", + "上限": "上限", "下一个表单块": "下一个表单块", "下一次重置": "下一次重置", "下一步": "下一步", @@ -409,6 +508,7 @@ "从认证器应用中获取验证码,或使用备用码": "从认证器应用中获取验证码,或使用备用码", "从配置文件同步": "从配置文件同步", "从默认列表中去掉一个分组": "从默认列表中去掉一个分组", + "付款完成后将自动回到账户页": "付款完成后将自动回到账户页", "代理地址": "代理地址", "代理设置": "代理设置", "代码已复制到剪贴板": "代码已复制到剪贴板", @@ -434,6 +534,7 @@ "价格:${{price}} * {{ratioType}}:{{ratio}}": "价格:${{price}} * {{ratioType}}:{{ratio}}", "价格摘要": "价格摘要", "价格暂时不可用,请稍后重试": "价格暂时不可用,请稍后重试", + "价格根据用量档位和请求条件动态调整": "价格根据用量档位和请求条件动态调整", "价格模式": "价格模式", "价格模式(默认)": "价格模式(默认)", "价格计算中...": "价格计算中...", @@ -491,6 +592,7 @@ "例如": "例如", "例如 /var/cache/new-api": "例如 /var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "例如 €, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "例如 Asia/Shanghai", "例如 https://docs.newapi.pro": "例如 https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "例如 https://example.com/api/waffo/webhook", "例如 https://example.com/console/topup": "例如 https://example.com/console/topup", @@ -597,6 +699,7 @@ "倍率模式(默认)": "倍率模式(默认)", "倍率用于计费乘数,勾选「用户可选」后用户可在创建令牌时选择该分组": "倍率用于计费乘数,勾选「用户可选」后用户可在创建令牌时选择该分组", "倍率类型": "倍率类型", + "值": "值", "假设再加两个分组 default 和 vip,但不勾选用户可选:": "假设再加两个分组 default 和 vip,但不勾选用户可选:", "偏好设置": "偏好设置", "停止测试": "停止测试", @@ -631,9 +734,11 @@ "元": "元", "充值": "充值", "充值价格(x元/美金)": "充值价格(x元/美金)", + "充值价格必须大于 0": "充值价格必须大于 0", "充值价格显示": "充值价格显示", "充值分组倍率": "充值分组倍率", "充值分组倍率不是合法的 JSON 字符串": "充值分组倍率不是合法的 JSON 字符串", + "充值完成后跳回的页面": "充值完成后跳回的页面", "充值数量": "充值数量", "充值数量,最低 ": "充值数量,最低 ", "充值数量不能小于": "充值数量不能小于", @@ -659,6 +764,7 @@ "兑换码生成管理": "兑换码生成管理", "兑换码管理": "兑换码管理", "兑换额度": "兑换额度", + "兜底档": "兜底档", "全局控制侧边栏区域和功能显示,管理员隐藏的功能用户无法启用": "全局控制侧边栏区域和功能显示,管理员隐藏的功能用户无法启用", "全局设置": "全局设置", "全选": "全选", @@ -719,9 +825,9 @@ "再次输入部署名称": "再次输入部署名称", "最低": "最低", "最低充值数量": "最低充值数量", + "最低充值数量必须大于 0": "最低充值数量必须大于 0", "最低充值美元数量": "最低充值美元数量", "最低充值美元数量必须大于 0": "最低充值美元数量必须大于 0", - "留空则自动使用当前站点的默认回调地址": "留空则自动使用当前站点的默认回调地址", "最后使用时间": "最后使用时间", "最后更新": "最后更新", "最后请求": "最后请求", @@ -732,6 +838,7 @@ "最近一次": "最近一次", "最近事件": "最近事件", "最高优先级": "最高优先级", + "最高档": "最高档", "写": "写", "准入策略": "准入策略", "准入策略 JSON(可选)": "准入策略 JSON(可选)", @@ -739,6 +846,9 @@ "准备完成初始化": "准备完成初始化", "减少": "减少", "凭证已刷新": "凭证已刷新", + "函数": "函数", + "分时缓存 (Claude)": "分时缓存 (Claude)", + "分档价格表": "分档价格表", "分类名称": "分类名称", "分组": "分组", "分组JSON设置": "分组JSON设置", @@ -761,13 +871,13 @@ "分组速率配置优先级高于全局速率限制。": "分组速率配置优先级高于全局速率限制。", "分组速率限制": "分组速率限制", "分钟": "分钟", - "切换到新版前端": "切换到新版前端", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "切换后页面会自动刷新,并进入新版前端。是否继续?", - "切换失败,请稍后重试": "切换失败,请稍后重试", "切换为Assistant角色": "切换为Assistant角色", "切换为System角色": "切换为System角色", "切换为单密钥模式": "切换为单密钥模式", "切换主题": "切换主题", + "切换到新版前端": "切换到新版前端", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "切换后页面会自动刷新,并进入新版前端。是否继续?", + "切换失败,请稍后重试": "切换失败,请稍后重试", "划转到余额": "划转到余额", "划转邀请额度": "划转邀请额度", "划转金额最低为": "划转金额最低为", @@ -823,6 +933,7 @@ "刷新缓存统计": "刷新缓存统计", "刷新缓存统计失败": "刷新缓存统计失败", "刷新页面": "刷新页面", + "前 {{count}} 个": "前 {{count}} 个", "前:": "前:", "前往 io.net API Keys": "前往 io.net API Keys", "前往设置": "前往设置", @@ -857,6 +968,7 @@ "加载详情中...": "加载详情中...", "加载账单失败": "加载账单失败", "加载隐私政策内容失败...": "加载隐私政策内容失败...", + "动态计费": "动态计费", "勾选后,该分组会出现在用户创建令牌时的下拉菜单中。未勾选的分组只能由管理员分配,用户自己无法选择。": "勾选后,该分组会出现在用户创建令牌时的下拉菜单中。未勾选的分组只能由管理员分配,用户自己无法选择。", "包含": "包含", "包含来自未知或未标明供应商的AI模型,这些模型可能来自小型供应商或开源项目。": "包含来自未知或未标明供应商的AI模型,这些模型可能来自小型供应商或开源项目。", @@ -868,6 +980,7 @@ "区域": "区域", "升级分组": "升级分组", "单GPU小时费率": "单GPU小时费率", + "单价": "单价", "单价 (USD)": "单价 (USD)", "历史消耗": "历史消耗", "原价": "原价", @@ -909,6 +1022,7 @@ "变换": "变换", "变更": "变更", "变焦": "变焦", + "变量": "变量", "变量值": "变量值", "变量名": "变量名", "只包括请求成功的次数": "只包括请求成功的次数", @@ -936,7 +1050,9 @@ "可视化编辑": "可视化编辑", "可空": "可空", "可选,公告的补充说明": "可选,公告的补充说明", + "可选,填写图片 URL": "可选,填写图片 URL", "可选,用于复现结果": "可选,用于复现结果", + "可选,用量达到此档时加收的固定费用": "可选,用量达到此档时加收的固定费用", "可选:基于用户信息 JSON 做组合条件准入,条件不满足时返回自定义提示": "可选:基于用户信息 JSON 做组合条件准入,条件不满足时返回自定义提示", "可选:用于自动生成端点或 Discovery URL": "可选:用于自动生成端点或 Discovery URL", "可选。匹配入口请求的 User-Agent;任意一行作为子串匹配(忽略大小写)即命中。": "可选。匹配入口请求的 User-Agent;任意一行作为子串匹配(忽略大小写)即命中。", @@ -945,6 +1061,7 @@ "可选值": "可选值", "合计:{{total}}": "合计:{{total}}", "合计:文字部分 {{textTotal}} + 音频部分 {{audioTotal}} = {{total}}": "合计:文字部分 {{textTotal}} + 音频部分 {{audioTotal}} = {{total}}", + "同时满足": "同时满足", "同时重置消息": "同时重置消息", "同步": "同步", "同步到渠道": "同步到渠道", @@ -968,6 +1085,8 @@ "向右展开": "向右展开", "向左展开": "向左展开", "否": "否", + "含时间条件": "含时间条件", + "含请求条件": "含请求条件", "启动": "启动", "启动参数 (Args)": "启动参数 (Args)", "启动命令": "启动命令", @@ -982,6 +1101,7 @@ "启用 io.net 部署时必须填写 API Key": "启用 io.net 部署时必须填写 API Key", "启用 Prompt 检查": "启用 Prompt 检查", "启用 Waffo": "启用 Waffo", + "启用 Waffo Pancake": "启用 Waffo Pancake", "启用2FA失败": "启用2FA失败", "启用Claude思考适配(-thinking后缀)": "启用Claude思考适配(-thinking后缀)", "启用FunctionCall思维签名填充": "启用FunctionCall思维签名填充", @@ -991,6 +1111,7 @@ "启用SSRF防护(推荐开启以保护服务器安全)": "启用SSRF防护(推荐开启以保护服务器安全)", "启用供应商": "启用供应商", "启用全部": "启用全部", + "启用后会按测试环境保存这组配置": "启用后会按测试环境保存这组配置", "启用后可接入 io.net GPU 资源": "启用后可接入 io.net GPU 资源", "启用后可添加图片URL进行多模态对话": "启用后可添加图片URL进行多模态对话", "启用后套餐将在用户端展示。是否继续?": "启用后套餐将在用户端展示。是否继续?", @@ -1017,6 +1138,7 @@ "启用验证": "启用验证", "周": "周", "命中判定:usage 中存在 cached tokens(例如 cached_tokens/prompt_cache_hit_tokens)即视为命中。": "命中判定:usage 中存在 cached tokens(例如 cached_tokens/prompt_cache_hit_tokens)即视为命中。", + "命中档位": "命中档位", "命中率": "命中率", "命中该亲和规则后,会把此模板合并到渠道参数覆盖中(同名键由模板覆盖)。": "命中该亲和规则后,会把此模板合并到渠道参数覆盖中(同名键由模板覆盖)。", "和": "和", @@ -1037,6 +1159,8 @@ "固定价格": "固定价格", "固定价格(每次)": "固定价格(每次)", "固定价格值": "固定价格值", + "固定费": "固定费", + "固定阶梯": "固定阶梯", "图像生成": "图像生成", "图标": "图标", "图标使用 react-icons(Simple Icons)或 URL/emoji,例如:github、gitlab、si:google": "图标使用 react-icons(Simple Icons)或 URL/emoji,例如:github、gitlab、si:google", @@ -1207,8 +1331,10 @@ "实付金额": "实付金额", "实付金额:": "实付金额:", "实际模型": "实际模型", + "实际环境": "实际环境", "实际结算金额:{{symbol}}{{total}}(已包含分组价格调整)": "实际结算金额:{{symbol}}{{total}}(已包含分组价格调整)", "实际请求体": "实际请求体", + "实际额度": "实际额度", "审计信息": "审计信息", "容器": "容器", "容器ID": "容器ID", @@ -1271,7 +1397,12 @@ "导入配置": "导入配置", "导入配置失败: ": "导入配置失败: ", "导出": "导出", + "导出失败": "导出失败", "导出日志失败": "导出日志失败", + "导出月账单": "导出月账单", + "导出月账单和消费明细": "导出月账单和消费明细", + "导出消费明细": "导出消费明细", + "导出用量CSV": "导出用量 CSV", "导出配置": "导出配置", "导出配置失败: ": "导出配置失败: ", "将 reasoning_content 转换为 标签拼接到内容中": "将 reasoning_content 转换为 标签拼接到内容中", @@ -1288,8 +1419,10 @@ "将清除所有保存的配置并恢复默认设置,此操作不可撤销。是否继续?": "将清除所有保存的配置并恢复默认设置,此操作不可撤销。是否继续?", "将清除选定时间之前的所有日志": "将清除选定时间之前的所有日志", "将追加 2 条规则到现有规则列表。": "将追加 2 条规则到现有规则列表。", + "将额外乘以上述价格": "将额外乘以上述价格", "小时": "小时", "小时费率": "小时费率", + "小计": "小计", "尚未使用": "尚未使用", "局部重绘-提交": "局部重绘-提交", "屏蔽词列表": "屏蔽词列表", @@ -1310,9 +1443,9 @@ "已停止批量测试": "已停止批量测试", "已关闭后续提醒": "已关闭后续提醒", "已分配内存": "已分配内存", - "已切换到新版前端,正在刷新页面": "已切换到新版前端,正在刷新页面", "已切换为Assistant角色": "已切换为Assistant角色", "已切换为System角色": "已切换为System角色", + "已切换到新版前端,正在刷新页面": "已切换到新版前端,正在刷新页面", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "已切换至最优倍率视图,每个模型使用其最低倍率分组", "已初始化": "已初始化", "已删除": "已删除", @@ -1355,6 +1488,7 @@ "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型": "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。", + "已开始下载": "已开始下载", "已忽略模型": "已忽略模型", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "已成功开始测试所有已启用通道,请刷新页面查看结果。", "已打开授权页面": "已打开授权页面", @@ -1408,6 +1542,8 @@ "平均TPM": "平均TPM", "平移": "平移", "年": "年", + "年份": "年份", + "年份无效": "年份无效", "应付金额": "应付金额", "应用": "应用", "应用同步": "应用同步", @@ -1425,6 +1561,7 @@ "建立连接时发生错误": "建立连接时发生错误", "建议在生产环境中使用 MySQL 或 PostgreSQL 数据库,或确保 SQLite 数据库文件已映射到宿主机的持久化存储。": "建议在生产环境中使用 MySQL 或 PostgreSQL 数据库,或确保 SQLite 数据库文件已映射到宿主机的持久化存储。", "开": "开", + "开发者": "开发者", "开启「默认使用 auto 分组」后,新建令牌和初始令牌都会自动设为 auto。": "开启「默认使用 auto 分组」后,新建令牌和初始令牌都会自动设为 auto。", "开启之后会清除用户提示词中的": "开启之后会清除用户提示词中的", "开启之后将上游地址替换为服务器地址": "开启之后将上游地址替换为服务器地址", @@ -1463,9 +1600,11 @@ "当前 API 密钥已过期,请在设置中更新。": "当前 API 密钥已过期,请在设置中更新。", "当前 Ollama 版本为 ${version}": "当前 Ollama 版本为 ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "当前仅支持易支付接口,回调地址请在通用设置中配置。", "当前余额": "当前余额", "当前值": "当前值", "当前值不是合法 JSON,无法格式化": "当前值不是合法 JSON,无法格式化", + "当前入口状态": "当前入口状态", "当前分组为 auto,会自动选择最优分组,当一个组不可用时自动降级到下一个组(熔断机制)": "当前分组为 auto,会自动选择最优分组,当一个组不可用时自动降级到下一个组(熔断机制)", "当前剩余": "当前剩余", "当前参数覆盖不是合法的 JSON": "当前参数覆盖不是合法的 JSON", @@ -1491,6 +1630,7 @@ "当前设置类型: ": "当前设置类型: ", "当前跟随系统": "当前跟随系统", "当前配置无法连接到 io.net。": "当前配置无法连接到 io.net。", + "当前金额未达到 Waffo Pancake 的最低充值要求": "当前金额未达到 Waffo Pancake 的最低充值要求", "当前额度": "当前额度", "当某个分组的用户使用另一个分组的令牌时,可设置特殊倍率覆盖基础倍率。例如:vip 分组的用户使用 default 分组时倍率为 0.5": "当某个分组的用户使用另一个分组的令牌时,可设置特殊倍率覆盖基础倍率。例如:vip 分组的用户使用 default 分组时倍率为 0.5", "当模型没有设置价格时仍接受调用,仅当您信任该网站时使用,可能会产生高额费用": "当模型没有设置价格时仍接受调用,仅当您信任该网站时使用,可能会产生高额费用", @@ -1549,6 +1689,7 @@ "或": "或", "或其兼容new-api-worker格式的其他版本": "或其兼容new-api-worker格式的其他版本", "或手动输入密钥:": "或手动输入密钥:", + "所有 Token": "所有 Token", "所有上游数据均可信": "所有上游数据均可信", "所有密钥已复制到剪贴板": "所有密钥已复制到剪贴板", "所有用户": "所有用户", @@ -1676,10 +1817,11 @@ "支付方式": "支付方式", "支付方式名称": "支付方式名称", "支付方式名称不能为空": "支付方式名称不能为空", + "支付方式图标": "支付方式图标", "支付方式类型": "支付方式类型", + "支付方式颜色": "支付方式颜色", "支付渠道": "支付渠道", "支付设置": "支付设置", - "易支付设置": "易支付设置", "支付请求失败": "支付请求失败", "支付返回地址": "支付返回地址", "支付金额": "支付金额", @@ -1753,12 +1895,14 @@ "新增订阅": "新增订阅", "新密码": "新密码", "新密码需要和原密码不一致!": "新密码需要和原密码不一致!", + "新年促销": "新年促销", "新建": "新建", "新建套餐": "新建套餐", "新建容器": "新建容器", "新建容器部署": "新建容器部署", "新建数量": "新建数量", "新建组": "新建组", + "新支付方式": "新支付方式", "新格式(支持条件判断与json自定义):": "新格式(支持条件判断与json自定义):", "新格式(规则 + 条件)": "新格式(规则 + 条件)", "新格式模板": "新格式模板", @@ -1774,6 +1918,7 @@ "无冲突项": "无冲突项", "无效的部署信息": "无效的部署信息", "无效的重置链接,请重新发起密码重置请求": "无效的重置链接,请重新发起密码重置请求", + "无条件(兜底档)": "无条件(兜底档)", "无法发起 Passkey 注册": "无法发起 Passkey 注册", "无法复制到剪贴板,请手动复制": "无法复制到剪贴板,请手动复制", "无法添加图片": "无法添加图片", @@ -1782,6 +1927,7 @@ "无法连接 io.net": "无法连接 io.net", "无生效": "无生效", "无邀请人": "无邀请人", + "无限": "无限", "无限制": "无限制", "无限额度": "无限额度", "日": "日", @@ -1798,18 +1944,24 @@ "日志类型": "日志类型", "日志设置": "日志设置", "日志详情": "日志详情", + "日期": "日期", "旧格式(JSON 对象)": "旧格式(JSON 对象)", "旧格式(直接覆盖):": "旧格式(直接覆盖):", "旧格式必须是 JSON 对象": "旧格式必须是 JSON 对象", "旧格式模板": "旧格式模板", "旧的备用码已失效,请保存新的备用码": "旧的备用码已失效,请保存新的备用码", "早上好": "早上好", + "时区": "时区", + "时区(IANA,可选)": "时区(IANA,可选)", "时间": "时间", "时间信息": "时间信息", + "时间条件": "时间条件", "时间粒度": "时间粒度", "易支付": "易支付", "易支付商户ID": "易支付商户ID", "易支付商户密钥": "易支付商户密钥", + "易支付设置": "易支付设置", + "星期": "星期", "是": "是", "是否为企业账户": "是否为企业账户", "是否同时重置对话消息?选择\"是\"将清空所有对话记录并恢复默认示例;选择\"否\"将保留当前对话记录。": "是否同时重置对话消息?选择\"是\"将清空所有对话记录并恢复默认示例;选择\"否\"将保留当前对话记录。", @@ -1890,6 +2042,7 @@ "更新": "更新", "更新 Creem 设置": "更新 Creem 设置", "更新 Stripe 设置": "更新 Stripe 设置", + "更新 Waffo Pancake 设置": "更新 Waffo Pancake 设置", "更新 Waffo 设置": "更新 Waffo 设置", "更新SSRF防护设置": "更新SSRF防护设置", "更新Worker设置": "更新Worker设置", @@ -1904,8 +2057,8 @@ "更新成功": "更新成功", "更新所有已启用通道余额": "更新所有已启用通道余额", "更新支付设置": "更新支付设置", - "更新易支付设置": "更新易支付设置", "更新时间": "更新时间", + "更新易支付设置": "更新易支付设置", "更新服务器地址": "更新服务器地址", "更新模型信息": "更新模型信息", "更新渠道信息": "更新渠道信息", @@ -1916,6 +2069,8 @@ "更新预填组": "更新预填组", "替换": "替换", "月": "月", + "月份": "月份", + "月份无效": "月份无效", "有 Reasoning": "有 Reasoning", "有序字符串数组": "有序字符串数组", "有效期": "有效期", @@ -1925,7 +2080,6 @@ "服务可用性": "服务可用性", "服务商": "服务商", "服务器IP": "服务器IP", - "节点名称": "节点名称", "服务器地址": "服务器地址", "服务器日志功能未启用(未配置日志目录)": "服务器日志功能未启用(未配置日志目录)", "服务器日志管理": "服务器日志管理", @@ -1983,6 +2137,8 @@ "条": "条", "条 - 第": "条 - 第", "条,共": "条,共", + "条件": "条件", + "条件乘数": "条件乘数", "条件取反": "条件取反", "条件数": "条件数", "条件规则": "条件规则", @@ -2022,12 +2178,16 @@ "核心配置": "核心配置", "核采样,控制词汇选择的多样性": "核采样,控制词汇选择的多样性", "根据 Anthropic 协定,/v1/messages 的输入 tokens 仅统计非缓存输入,不包含缓存读取与缓存写入 tokens。": "根据 Anthropic 协定,/v1/messages 的输入 tokens 仅统计非缓存输入,不包含缓存读取与缓存写入 tokens。", + "根据哪个维度的 Token 数量决定落在哪一档": "根据哪个维度的 Token 数量决定落在哪一档", + "根据总用量落在哪个档位,所有 Token 都按该档价格计费": "根据总用量落在哪个档位,所有 Token 都按该档价格计费", "根据模型名称和匹配规则查找模型元数据,优先级:精确 > 前缀 > 后缀 > 包含": "根据模型名称和匹配规则查找模型元数据,优先级:精确 > 前缀 > 后缀 > 包含", "格式化": "格式化", "格式化 JSON": "格式化 JSON", "格式正确": "格式正确", "格式示例:": "格式示例:", "格式错误": "格式错误", + "档": "档", + "档位标签": "档位标签", "检查更新": "检查更新", "检测全部渠道上游更新": "检测全部渠道上游更新", "检测到 FluentRead(流畅阅读)": "检测到 FluentRead(流畅阅读)", @@ -2120,6 +2280,7 @@ "次": "次", "欢迎使用,请完成以下设置以开始使用系统": "欢迎使用,请完成以下设置以开始使用系统", "欧元": "欧元", + "止": "止", "正则替换": "正则替换", "正在加载可用部署位置...": "正在加载可用部署位置...", "正在加载签到状态...": "正在加载签到状态...", @@ -2153,6 +2314,7 @@ "此操作将降低用户的权限级别": "此操作将降低用户的权限级别", "此支付方式最低充值金额为": "此支付方式最低充值金额为", "此时用户创建令牌时只能看到 standard 和 premium:": "此时用户创建令牌时只能看到 standard 和 premium:", + "此档上限(Token 数)": "此档上限(Token 数)", "此渠道由 IO.NET 自动同步,类型、密钥和 API 地址已锁定。": "此渠道由 IO.NET 自动同步,类型、密钥和 API 地址已锁定。", "此设置用于系统内部计算,默认值500000是为了精确到6位小数点设计,不推荐修改。": "此设置用于系统内部计算,默认值500000是为了精确到6位小数点设计,不推荐修改。", "此页面仅显示未设置价格或倍率的模型,设置后将自动从列表中移除": "此页面仅显示未设置价格或倍率的模型,设置后将自动从列表中移除", @@ -2166,6 +2328,7 @@ "此项可选,用于通过自定义API地址来进行 API 调用,末尾不要带/v1和/": "此项可选,用于通过自定义API地址来进行 API 调用,末尾不要带/v1和/", "每个充值单位对应的 USD 金额,默认 1.0": "每个充值单位对应的 USD 金额,默认 1.0", "每个分组代表一个价格档位。管理员创建分组后,可以选择哪些档位对用户开放自选。": "每个分组代表一个价格档位。管理员创建分组后,可以选择哪些档位对用户开放自选。", + "每个档位可设置 0~2 个条件(对 p 和 c),最后一档为兜底档无需条件。": "每个档位可设置 0~2 个条件(对 p 和 c),最后一档为兜底档无需条件。", "每个用户最多可创建的令牌数量,默认 1000,设置过大可能会影响性能": "每个用户最多可创建的令牌数量,默认 1000,设置过大可能会影响性能", "每周": "每周", "每天": "每天", @@ -2174,6 +2337,7 @@ "每日签到": "每日签到", "每日签到可获得随机额度奖励": "每日签到可获得随机额度奖励", "每月": "每月", + "每百万 Token 价格": "每百万 Token 价格", "每美元对应 Token 数": "每美元对应 Token 数", "每隔多少分钟测试一次所有通道": "每隔多少分钟测试一次所有通道", "永不过期": "永不过期", @@ -2216,6 +2380,7 @@ "浅色模式": "浅色模式", "测活": "测活", "测试": "测试", + "测试 Webhook 公钥": "测试 Webhook 公钥", "测试中": "测试中", "测试中...": "测试中...", "测试单个渠道操作项目组": "测试单个渠道操作项目组", @@ -2225,6 +2390,8 @@ "测试所有渠道的最长响应时间": "测试所有渠道的最长响应时间", "测试所有通道": "测试所有通道", "测试模式": "测试模式", + "测试环境": "测试环境", + "测试环境 Webhook 验签公钥 Base64": "测试环境 Webhook 验签公钥 Base64", "测试连接": "测试连接", "测速": "测速", "消息优先级": "消息优先级", @@ -2256,6 +2423,11 @@ "添加密钥环境变量": "添加密钥环境变量", "添加成功": "添加成功", "添加提供商": "添加提供商", + "添加时间条件": "添加时间条件", + "添加时间规则": "添加时间规则", + "添加更多档位": "添加更多档位", + "添加条件": "添加条件", + "添加条件组": "添加条件组", "添加模型": "添加模型", "添加模型区域": "添加模型区域", "添加渠道": "添加渠道", @@ -2264,6 +2436,7 @@ "添加聊天配置": "添加聊天配置", "添加键值对": "添加键值对", "添加问答": "添加问答", + "添加阶梯": "添加阶梯", "添加额度": "添加额度", "清理不活跃缓存": "清理不活跃缓存", "清理失败": "清理失败", @@ -2329,9 +2502,12 @@ "状态筛选": "状态筛选", "状态页面Slug": "状态页面Slug", "环境变量": "环境变量", + "生产 Webhook 公钥": "生产 Webhook 公钥", + "生产环境": "生产环境", "生产环境 RSA 私钥 Base64 (PKCS#8 DER)": "生产环境 RSA 私钥 Base64 (PKCS#8 DER)", "生产环境 Waffo API 密钥": "生产环境 Waffo API 密钥", "生产环境 Waffo 公钥 Base64 (X.509 DER)": "生产环境 Waffo 公钥 Base64 (X.509 DER)", + "生产环境 Webhook 验签公钥 Base64": "生产环境 Webhook 验签公钥 Base64", "生成令牌": "生成令牌", "生成并填入": "生成并填入", "生成数量": "生成数量", @@ -2397,6 +2573,10 @@ "用户账户创建成功!": "用户账户创建成功!", "用户账户管理": "用户账户管理", "用时/首字": "用时/首字", + "用量分段计价,每一段各自按对应档位价格计费(类似电费阶梯)": "用量分段计价,每一段各自按对应档位价格计费(类似电费阶梯)", + "用量导出时区说明": "不填则按服务器本地时区划分自然月;填写后按该时区的自然月。", + "用量导出说明": "为用户 {{name}}(ID {{id}})按所选自然月导出 CSV(月账单为汇总,消费明细为逐条调用)。", + "用量范围": "用量范围", "由全站货币展示设置统一控制": "由全站货币展示设置统一控制", "由管理员分配,决定用户身份等级(如 default、vip)。": "由管理员分配,决定用户身份等级(如 default、vip)。", "由订阅抵扣": "由订阅抵扣", @@ -2406,6 +2586,7 @@ "留空则使用默认端点;支持 {path, method}": "留空则使用默认端点;支持 {path, method}", "留空则保持原有密钥": "留空则保持原有密钥", "留空则自动使用 服务器地址 + /api/waffo/webhook": "留空则自动使用 服务器地址 + /api/waffo/webhook", + "留空则自动使用当前站点的默认回调地址": "留空则自动使用当前站点的默认回调地址", "留空则默认使用服务器地址,注意不能携带http://或者https://": "留空则默认使用服务器地址,注意不能携带http://或者https://", "登 录": "登 录", "登录": "登录", @@ -2479,6 +2660,7 @@ "确认作废": "确认作废", "确认关闭提示": "确认关闭提示", "确认冲突项修改": "确认冲突项修改", + "确认切换": "确认切换", "确认删除": "确认删除", "确认删除模型": "确认删除模型", "确认删除该分组?": "确认删除该分组?", @@ -2486,7 +2668,6 @@ "确认删除该规则?": "确认删除该规则?", "确认取消密码登录": "确认取消密码登录", "确认启用": "确认启用", - "确认切换": "确认切换", "确认密码": "确认密码", "确认导入配置": "确认导入配置", "确认延长": "确认延长", @@ -2547,6 +2728,7 @@ "空": "空", "窗口处理": "窗口处理", "窗口等待": "窗口等待", + "立即充值": "立即充值", "立即签到": "立即签到", "立即订阅": "立即订阅", "站点所有额度将以原始 Token 数显示,不做货币换算": "站点所有额度将以原始 Token 数显示,不做货币换算", @@ -2571,6 +2753,8 @@ "第 {{line}} 条操作缺少目标路径": "第 {{line}} 条操作缺少目标路径", "第 {{line}} 条请求头透传格式无效": "第 {{line}} 条请求头透传格式无效", "第 {{line}} 条请求头透传缺少请求头名称": "第 {{line}} 条请求头透传缺少请求头名称", + "第 {{n}} 档": "第 {{n}} 档", + "第 {{n}} 组": "第 {{n}} 组", "第三方支付配置": "第三方支付配置", "第三方账户绑定状态(只读)": "第三方账户绑定状态(只读)", "等价金额:": "等价金额:", @@ -2651,6 +2835,7 @@ "纯字符串会直接覆盖整条请求头,或者点击“查看 JSON 示例”按 token 规则处理。": "纯字符串会直接覆盖整条请求头,或者点击“查看 JSON 示例”按 token 规则处理。", "累计签到": "累计签到", "累计获得": "累计获得", + "累进阶梯": "累进阶梯", "线路描述": "线路描述", "组列表": "组列表", "组名": "组名", @@ -2674,6 +2859,7 @@ "绘图任务记录": "绘图任务记录", "绘图日志": "绘图日志", "绘图设置": "绘图设置", + "统一定价": "统一定价", "统一的": "统一的", "统计Tokens": "统计Tokens", "统计已重置": "统计已重置", @@ -2689,10 +2875,17 @@ "缓存倍率": "缓存倍率", "缓存倍率 {{cacheRatio}}": "缓存倍率 {{cacheRatio}}", "缓存写": "缓存写", + "缓存创建": "缓存创建", "缓存创建 {{price}} / 1M tokens": "缓存创建 {{price}} / 1M tokens", "缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}": "缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}}", "缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})": "缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})", + "缓存创建 Token (cc)": "缓存创建 Token (cc)", "缓存创建 Tokens": "缓存创建 Tokens", + "缓存创建-1h": "缓存创建-1h", + "缓存创建-1小时": "缓存创建-1小时", + "缓存创建-1小时 (cc1h)": "缓存创建-1小时 (cc1h)", + "缓存创建-5分钟": "缓存创建-5分钟", + "缓存创建-5分钟 (cc5)": "缓存创建-5分钟 (cc5)", "缓存创建: {{cacheCreationRatio}}": "缓存创建: {{cacheCreationRatio}}", "缓存创建: 1h {{cacheCreationRatio1h}}": "缓存创建: 1h {{cacheCreationRatio1h}}", "缓存创建: 5m {{cacheCreationRatio5m}}": "缓存创建: 5m {{cacheCreationRatio5m}}", @@ -2700,8 +2893,12 @@ "缓存创建:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 缓存创建倍率 {{cacheCreationRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "缓存创建:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 缓存创建倍率 {{cacheCreationRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "缓存创建价格": "缓存创建价格", "缓存创建价格 {{symbol}}{{price}} / 1M tokens": "缓存创建价格 {{symbol}}{{price}} / 1M tokens", + "缓存创建价格-1小时": "缓存创建价格-1小时", + "缓存创建价格-5分钟": "缓存创建价格-5分钟", "缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})", "缓存创建价格:{{symbol}}{{price}} / 1M tokens": "缓存创建价格:{{symbol}}{{price}} / 1M tokens", + "缓存创建价格(1小时)": "缓存创建价格(1小时)", + "缓存创建价格(5分钟)": "缓存创建价格(5分钟)", "缓存创建价格合计:5m {{symbol}}{{five}} + 1h {{symbol}}{{one}} = {{symbol}}{{total}} / 1M tokens": "缓存创建价格合计:5m {{symbol}}{{five}} + 1h {{symbol}}{{one}} = {{symbol}}{{total}} / 1M tokens", "缓存创建倍率": "缓存创建倍率", "缓存创建倍率 {{cacheCreationRatio}}": "缓存创建倍率 {{cacheCreationRatio}}", @@ -2713,6 +2910,8 @@ "缓存目录磁盘空间": "缓存目录磁盘空间", "缓存读": "缓存读", "缓存读 {{price}} / 1M tokens": "缓存读 {{price}} / 1M tokens", + "缓存读取": "缓存读取", + "缓存读取 Token (cr)": "缓存读取 Token (cr)", "缓存读取:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 缓存倍率 {{cacheRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "缓存读取:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 缓存倍率 {{cacheRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "缓存读取价格": "缓存读取价格", "缓存读取价格 {{symbol}}{{price}} / 1M tokens": "缓存读取价格 {{symbol}}{{price}} / 1M tokens", @@ -2794,6 +2993,7 @@ "自用模式": "自用模式", "自适应列表": "自适应列表", "至": "至", + "节点名称": "节点名称", "节省": "节省", "花费": "花费", "花费时间": "花费时间", @@ -2848,10 +3048,13 @@ "补单成功": "补单成功", "表单引用错误,请刷新页面重试": "表单引用错误,请刷新页面重试", "表格视图": "表格视图", + "表达式编辑": "表达式编辑", + "表达式错误": "表达式错误", "覆盖": "覆盖", "覆盖模式:将完全替换现有的所有密钥": "覆盖模式:将完全替换现有的所有密钥", "覆盖模板": "覆盖模板", "覆盖现有密钥": "覆盖现有密钥", + "见上方动态计费详情": "见上方动态计费详情", "规则": "规则", "规则 JSON": "规则 JSON", "规则 JSON 格式不正确": "规则 JSON 格式不正确", @@ -2861,6 +3064,7 @@ "规则导航": "规则导航", "规则描述(可选)": "规则描述(可选)", "规则未找到,请刷新后重试": "规则未找到,请刷新后重试", + "规则版本": "规则版本", "角色": "角色", "解析响应数据时发生错误": "解析响应数据时发生错误", "解析密钥文件失败: {{msg}}": "解析密钥文件失败: {{msg}}", @@ -2877,6 +3081,7 @@ "计费开始": "计费开始", "计费摘要": "计费摘要", "计费方式": "计费方式", + "计费明细": "计费明细", "计费显示模式": "计费显示模式", "计费模式": "计费模式", "计费类型": "计费类型", @@ -2932,6 +3137,7 @@ "访问模型部署功能需要先启用 io.net 部署服务": "访问模型部署功能需要先启用 io.net 部署服务", "访问限制": "访问限制", "该供应商提供多种AI模型,适用于不同的应用场景。": "该供应商提供多种AI模型,适用于不同的应用场景。", + "该入口仅用于一次性余额充值": "该入口仅用于一次性余额充值", "该分类下没有可用模型": "该分类下没有可用模型", "该域名已存在于白名单中": "该域名已存在于白名单中", "该套餐未配置 Creem": "该套餐未配置 Creem", @@ -2978,6 +3184,7 @@ "请先输入密钥": "请先输入密钥", "请先选择一个作为模板的模型": "请先选择一个作为模板的模型", "请先选择一条规则": "请先选择一条规则", + "请先选择不低于最低额度的充值金额": "请先选择不低于最低额度的充值金额", "请先选择同步渠道": "请先选择同步渠道", "请先选择模型!": "请先选择模型!", "请先选择硬件类型": "请先选择硬件类型", @@ -3021,7 +3228,9 @@ "请求配置": "请求配置", "请求预扣费额度": "请求预扣费额度", "请点击我": "请点击我", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "请确认 Merchant、Store、Product 和所选环境密钥一致。", "请确认以下设置信息,点击\"初始化系统\"开始配置": "请确认以下设置信息,点击\"初始化系统\"开始配置", + "请确认商户和所选环境密钥一致。": "请确认商户和所选环境密钥一致。", "请确认您已了解禁用两步验证的后果": "请确认您已了解禁用两步验证的后果", "请确认管理员密码": "请确认管理员密码", "请稍后几秒重试,Turnstile 正在检查用户环境!": "请稍后几秒重试,Turnstile 正在检查用户环境!", @@ -3047,7 +3256,9 @@ "请输入 JSON 格式的 OAuth 凭据,例如:\n{\n \"access_token\": \"...\",\n \"account_id\": \"...\" \n}": "请输入 JSON 格式的 OAuth 凭据,例如:\n{\n \"access_token\": \"...\",\n \"account_id\": \"...\" \n}", "请输入 JSON 格式的密钥内容,例如:\n{\n \"type\": \"service_account\",\n \"project_id\": \"your-project-id\",\n \"private_key_id\": \"...\",\n \"private_key\": \"...\",\n \"client_email\": \"...\",\n \"client_id\": \"...\",\n \"auth_uri\": \"...\",\n \"token_uri\": \"...\",\n \"auth_provider_x509_cert_url\": \"...\",\n \"client_x509_cert_url\": \"...\"\n}": "请输入 JSON 格式的密钥内容,例如:\n{\n \"type\": \"service_account\",\n \"project_id\": \"your-project-id\",\n \"private_key_id\": \"...\",\n \"private_key\": \"...\",\n \"client_email\": \"...\",\n \"client_id\": \"...\",\n \"auth_uri\": \"...\",\n \"token_uri\": \"...\",\n \"auth_provider_x509_cert_url\": \"...\",\n \"client_x509_cert_url\": \"...\"\n}", "请输入 OIDC 的 Well-Known URL": "请输入 OIDC 的 Well-Known URL", + "请输入 Product ID": "请输入 Product ID", "请输入 Slug": "请输入 Slug", + "请输入 Store ID": "请输入 Store ID", "请输入 Token Endpoint": "请输入 Token Endpoint", "请输入 User Info Endpoint": "请输入 User Info Endpoint", "请输入6位验证码或8位备用码": "请输入6位验证码或8位备用码", @@ -3079,6 +3290,7 @@ "请输入原密码": "请输入原密码", "请输入原密码!": "请输入原密码!", "请输入名称": "请输入名称", + "请输入商户 ID": "请输入商户 ID", "请输入回答内容": "请输入回答内容", "请输入回答内容(支持 Markdown/HTML)": "请输入回答内容(支持 Markdown/HTML)", "请输入图标名称": "请输入图标名称", @@ -3101,6 +3313,7 @@ "请输入您的用户名或邮箱地址": "请输入您的用户名或邮箱地址", "请输入您的邮箱地址": "请输入您的邮箱地址", "请输入您的问题...": "请输入您的问题...", + "请输入支付方式名称": "请输入支付方式名称", "请输入数值": "请输入数值", "请输入数字": "请输入数字", "请输入新密码": "请输入新密码", @@ -3205,41 +3418,6 @@ "豆包": "豆包", "账单": "账单", "账户充值": "账户充值", - "Waffo Pancake 设置": "Waffo Pancake 设置", - "Waffo Pancake": "Waffo Pancake", - "启用 Waffo Pancake": "启用 Waffo Pancake", - "当前入口状态": "当前入口状态", - "生产环境": "生产环境", - "测试环境": "测试环境", - "支付方式颜色": "支付方式颜色", - "支付方式图标": "支付方式图标", - "可选,填写图片 URL": "可选,填写图片 URL", - "Store ID": "Store ID", - "Product ID": "Product ID", - "API 私钥": "API 私钥", - "Webhook 公钥": "Webhook 公钥", - "充值价格必须大于 0": "充值价格必须大于 0", - "最低充值数量必须大于 0": "最低充值数量必须大于 0", - "充值完成后跳回的页面": "充值完成后跳回的页面", - "启用后会按测试环境保存这组配置": "启用后会按测试环境保存这组配置", - "更新 Waffo Pancake 设置": "更新 Waffo Pancake 设置", - "一次性余额充值": "一次性余额充值", - "新支付方式": "新支付方式", - "付款完成后将自动回到账户页": "付款完成后将自动回到账户页", - "一次性支付,付款后自动返回": "一次性支付,付款后自动返回", - "选择金额后直接跳转到 Waffo Pancake 结账页,支付完成后会回到账户页。": "选择金额后直接跳转到 Waffo Pancake 结账页,支付完成后会回到账户页。", - "当前金额未达到 Waffo Pancake 的最低充值要求": "当前金额未达到 Waffo Pancake 的最低充值要求", - "请先选择不低于最低额度的充值金额": "请先选择不低于最低额度的充值金额", - "该入口仅用于一次性余额充值": "该入口仅用于一次性余额充值", - "立即充值": "立即充值", - "生产 Webhook 公钥": "生产 Webhook 公钥", - "测试 Webhook 公钥": "测试 Webhook 公钥", - "生产环境 Webhook 验签公钥 Base64": "生产环境 Webhook 验签公钥 Base64", - "测试环境 Webhook 验签公钥 Base64": "测试环境 Webhook 验签公钥 Base64", - "请输入支付方式名称": "请输入支付方式名称", - "请输入商户 ID": "请输入商户 ID", - "请输入 Store ID": "请输入 Store ID", - "请输入 Product ID": "请输入 Product ID", "账户已删除!": "账户已删除!", "账户已锁定": "账户已锁定", "账户数据": "账户数据", @@ -3258,15 +3436,19 @@ "费用信息": "费用信息", "费用预估": "费用预估", "资源消耗": "资源消耗", + "起": "起", "起始时间": "起始时间", "超级管理员": "超级管理员", "超级管理员未设置充值链接!": "超级管理员未设置充值链接!", + "超过 {{count}} 个": "超过 {{count}} 个", "超过阈值时拒绝新请求": "超过阈值时拒绝新请求", "跟随日志": "跟随日志", "跟随系统主题设置": "跟随系统主题设置", "跨分组": "跨分组", "跨分组特殊倍率": "跨分组特殊倍率", "跨分组重试": "跨分组重试", + "跨夜范围": "跨夜范围", + "跨阶梯": "跨阶梯", "路径正则": "路径正则", "路径正则(每行一个)": "路径正则(每行一个)", "跳转": "跳转", @@ -3284,6 +3466,13 @@ "输入 OIDC 的 Client ID": "输入 OIDC 的 Client ID", "输入 OIDC 的 Token Endpoint": "输入 OIDC 的 Token Endpoint", "输入 OIDC 的 Userinfo Endpoint": "输入 OIDC 的 Userinfo Endpoint", + "输入 Token": "输入 Token", + "输入 Token 定价": "输入 Token 定价", + "输入 Token 数": "输入 Token 数", + "输入 Token 数 (p)": "输入 Token 数 (p)", + "输入 Token 数量,查看按当前配置的预计费用。": "输入 Token 数量,查看按当前配置的预计费用。", + "输入 Token 数量,查看按当前阶梯配置的预计费用。": "输入 Token 数量,查看按当前阶梯配置的预计费用。", + "输入 Tokens 阶梯": "输入 Tokens 阶梯", "输入IP地址后回车,如:8.8.8.8": "输入IP地址后回车,如:8.8.8.8", "输入JSON对象": "输入JSON对象", "输入价格": "输入价格", @@ -3309,15 +3498,22 @@ "输入补全价格": "输入补全价格", "输入补全倍率": "输入补全倍率", "输入要添加的邮箱域名": "输入要添加的邮箱域名", + "输入计费表达式...": "输入计费表达式...", "输入认证器应用显示的6位数字验证码": "输入认证器应用显示的6位数字验证码", "输入邮箱地址": "输入邮箱地址", "输入金额": "输入金额", + "输入阶梯": "输入阶梯", "输入项目名称,按回车添加": "输入项目名称,按回车添加", "输入额度": "输入额度", "输入验证码": "输入验证码", "输入验证码完成设置": "输入验证码完成设置", "输出": "输出", "输出 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}}) * {{ratioType}} {{ratio}}": "输出 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}}) * {{ratioType}} {{ratio}}", + "输出 Token": "输出 Token", + "输出 Token 定价": "输出 Token 定价", + "输出 Token 数": "输出 Token 数", + "输出 Token 数 (c)": "输出 Token 数 (c)", + "输出 Tokens 阶梯": "输出 Tokens 阶梯", "输出:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 补全倍率 {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "输出:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 补全倍率 {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "输出:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 输出倍率 {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}": "输出:{{tokens}} / 1M * 模型倍率 {{modelRatio}} * 输出倍率 {{completionRatio}} * {{ratioType}} {{ratio}} = {{amount}}", "输出价格": "输出价格", @@ -3326,6 +3522,7 @@ "输出价格:{{symbol}}{{price}} / 1M tokens": "输出价格:{{symbol}}{{price}} / 1M tokens", "输出价格:{{symbol}}{{total}} / 1M tokens": "输出价格:{{symbol}}{{total}} / 1M tokens", "输出倍率 {{completionRatio}}": "输出倍率 {{completionRatio}}", + "输出阶梯": "输出阶梯", "边栏设置": "边栏设置", "过期于": "过期于", "过期时间": "过期时间", @@ -3346,6 +3543,7 @@ "这是基础金额,实际扣费 = 基础金额 x 系统分组倍率。": "这是基础金额,实际扣费 = 基础金额 x 系统分组倍率。", "这是重复键中的最后一个,其值将被使用": "这是重复键中的最后一个,其值将被使用", "这里直接编辑 JSON 对象。适合简单覆盖参数的场景。": "这里直接编辑 JSON 对象。适合简单覆盖参数的场景。", + "进入此档额外收费": "进入此档额外收费", "进度": "进度", "进行中": "进行中", "进行该操作时,可能导致渠道访问错误,请仅在数据库出现问题时使用": "进行该操作时,可能导致渠道访问错误,请仅在数据库出现问题时使用", @@ -3397,6 +3595,7 @@ "选择语言": "选择语言", "选择过期时间(可选,留空为永久)": "选择过期时间(可选,留空为永久)", "选择部署位置(可多选)": "选择部署位置(可多选)", + "选择金额后直接跳转到 Waffo Pancake 结账页,支付完成后会回到账户页。": "选择金额后直接跳转到 Waffo Pancake 结账页,支付完成后会回到账户页。", "选择预设...": "选择预设...", "选择预设模板(可选)": "选择预设模板(可选)", "透传请求体": "透传请求体", @@ -3404,6 +3603,7 @@ "递归": "递归", "递归策略": "递归策略", "通义千问": "通义千问", + "通用缓存": "通用缓存", "通用设置": "通用设置", "通知": "通知", "通知、价格和隐私相关设置": "通知、价格和隐私相关设置", @@ -3545,6 +3745,16 @@ "镜像配置": "镜像配置", "问题标题": "问题标题", "队列中": "队列中", + "阶": "阶", + "阶梯内 Token 数": "阶梯内 Token 数", + "阶梯判断依据": "阶梯判断依据", + "阶梯序号": "阶梯序号", + "阶梯累进": "阶梯累进", + "阶梯计费": "阶梯计费", + "阶梯计费(未匹配到对应阶梯)": "阶梯计费(未匹配到对应阶梯)", + "阶梯计费(表达式解析失败)": "阶梯计费(表达式解析失败)", + "阶梯计费详情": "阶梯计费详情", + "阶梯配置摘要": "阶梯配置摘要", "附加条件": "附加条件", "降低您账户的安全性": "降低您账户的安全性", "降级": "降级", @@ -3596,7 +3806,9 @@ "项目内容": "项目内容", "项目操作按钮组": "项目操作按钮组", "预估总费用": "预估总费用", + "预估环境": "预估环境", "预估费用仅供参考,实际费用可能略有差异": "预估费用仅供参考,实际费用可能略有差异", + "预估额度": "预估额度", "预填组管理": "预填组管理", "预扣": "预扣", "预览失败": "预览失败", @@ -3606,6 +3818,7 @@ "预览请求体": "预览请求体", "预计结束": "预计结束", "预计结果": "预计结果", + "预计费用": "预计费用", "预设模板": "预设模板", "预警阈值必须为正数": "预警阈值必须为正数", "频率惩罚,减少重复词汇的出现": "频率惩罚,减少重复词汇的出现", @@ -3665,119 +3878,6 @@ "默认折叠侧边栏": "默认折叠侧边栏", "默认测试模型": "默认测试模型", "默认用户消息": "你好", - "默认补全倍率": "默认补全倍率", - "缓存创建价格-5分钟": "缓存创建价格-5分钟", - "缓存创建价格-1小时": "缓存创建价格-1小时", - "缓存创建价格(5分钟)": "缓存创建价格(5分钟)", - "缓存创建价格(1小时)": "缓存创建价格(1小时)", - "分时缓存 (Claude)": "分时缓存 (Claude)", - "通用缓存": "通用缓存", - "缓存读取": "缓存读取", - "缓存创建": "缓存创建", - "缓存创建-5分钟": "缓存创建-5分钟", - "缓存创建-1小时": "缓存创建-1小时", - "缓存读取 Token (cr)": "缓存读取 Token (cr)", - "缓存创建 Token (cc)": "缓存创建 Token (cc)", - "缓存创建-5分钟 (cc5)": "缓存创建-5分钟 (cc5)", - "缓存创建-1小时 (cc1h)": "缓存创建-1小时 (cc1h)", - "阶梯计费": "阶梯计费", - "阶梯计费(表达式解析失败)": "阶梯计费(表达式解析失败)", - "阶梯计费(未匹配到对应阶梯)": "阶梯计费(未匹配到对应阶梯)", - "输入 Tokens 阶梯": "输入 Tokens 阶梯", - "输出 Tokens 阶梯": "输出 Tokens 阶梯", - "固定阶梯": "固定阶梯", - "累进阶梯": "累进阶梯", - "上限": "上限", - "单价": "单价", - "固定费": "固定费", - "Expr 预览": "Expr 预览", - "Token 估算器": "Token 估算器", - "预计费用": "预计费用", - "添加阶梯": "添加阶梯", - "无限": "无限", - "输入 Token 定价": "输入 Token 定价", - "输出 Token 定价": "输出 Token 定价", - "统一定价": "统一定价", - "阶梯累进": "阶梯累进", - "根据总用量落在哪个档位,所有 Token 都按该档价格计费": "根据总用量落在哪个档位,所有 Token 都按该档价格计费", - "用量分段计价,每一段各自按对应档位价格计费(类似电费阶梯)": "用量分段计价,每一段各自按对应档位价格计费(类似电费阶梯)", - "Token 用量范围": "Token 用量范围", - "所有 Token": "所有 Token", - "前 {{count}} 个": "前 {{count}} 个", - "超过 {{count}} 个": "超过 {{count}} 个", - "第 {{n}} 档": "第 {{n}} 档", - "最高档": "最高档", - "此档上限(Token 数)": "此档上限(Token 数)", - "每百万 Token 价格": "每百万 Token 价格", - "进入此档额外收费": "进入此档额外收费", - "可选,用量达到此档时加收的固定费用": "可选,用量达到此档时加收的固定费用", - "添加更多档位": "添加更多档位", - "输入 Token 数": "输入 Token 数", - "输出 Token 数": "输出 Token 数", - "输入 Token 数量,查看按当前阶梯配置的预计费用。": "输入 Token 数量,查看按当前阶梯配置的预计费用。", - "开发者": "开发者", - "阶梯计费详情": "阶梯计费详情", - "预估环境": "预估环境", - "实际环境": "实际环境", - "预估额度": "预估额度", - "实际额度": "实际额度", - "跨阶梯": "跨阶梯", - "计费明细": "计费明细", - "阶梯序号": "阶梯序号", - "Token 类型": "Token 类型", - "阶梯内 Token 数": "阶梯内 Token 数", - "小计": "小计", - "档位标签": "档位标签", - "用量范围": "用量范围", - "输入 Token": "输入 Token", - "输出 Token": "输出 Token", - "阶梯判断依据": "阶梯判断依据", - "根据哪个维度的 Token 数量决定落在哪一档": "根据哪个维度的 Token 数量决定落在哪一档", - "输入 Token 数 (p)": "输入 Token 数 (p)", - "输出 Token 数 (c)": "输出 Token 数 (c)", - "变量": "变量", - "函数": "函数", - "输入计费表达式...": "输入计费表达式...", - "表达式编辑": "表达式编辑", - "表达式错误": "表达式错误", - "命中档位": "命中档位", - "档": "档", - "输入 Token 数量,查看按当前配置的预计费用。": "输入 Token 数量,查看按当前配置的预计费用。", - "条件": "条件", - "添加条件": "添加条件", - "无条件(兜底档)": "无条件(兜底档)", - "兜底档": "兜底档", - "每个档位可设置 0~2 个条件(对 p 和 c),最后一档为兜底档无需条件。": "每个档位可设置 0~2 个条件(对 p 和 c),最后一档为兜底档无需条件。", - "阶梯配置摘要": "阶梯配置摘要", - "输入阶梯": "输入阶梯", - "输出阶梯": "输出阶梯", - "阶": "阶", - "规则版本": "规则版本", - "时间条件": "时间条件", - "星期": "星期", - "月份": "月份", - "日期": "日期", - "时区": "时区", - "跨夜范围": "跨夜范围", - "添加时间规则": "添加时间规则", - "起": "起", - "止": "止", - "值": "值", - "添加条件组": "添加条件组", - "添加时间条件": "添加时间条件", - "同时满足": "同时满足", - "新年促销": "新年促销", - "第 {{n}} 组": "第 {{n}} 组", - "0=周日 1=周一 2=周二 3=周三 4=周四 5=周五 6=周六": "0=周日 1=周一 2=周二 3=周三 4=周四 5=周五 6=周六", - "1=一月 ... 12=十二月": "1=一月 ... 12=十二月", - "动态计费": "动态计费", - "价格根据用量档位和请求条件动态调整": "价格根据用量档位和请求条件动态调整", - "分档价格表": "分档价格表", - "条件乘数": "条件乘数", - "将额外乘以上述价格": "将额外乘以上述价格", - "缓存创建-1h": "缓存创建-1h", - "见上方动态计费详情": "见上方动态计费详情", - "含时间条件": "含时间条件", - "含请求条件": "含请求条件" + "默认补全倍率": "默认补全倍率" } } diff --git a/web/classic/src/i18n/locales/zh-TW.json b/web/classic/src/i18n/locales/zh-TW.json index 98d8e892488e..f37070eaff17 100644 --- a/web/classic/src/i18n/locales/zh-TW.json +++ b/web/classic/src/i18n/locales/zh-TW.json @@ -12,14 +12,12 @@ ",点击更新": ",點擊更新", "(共 {{total}} 个,省略 {{omit}} 个)": "", "(共 {{total}} 个)": "", - "当前仅支持易支付接口,回调地址请在通用设置中配置。": "目前僅支援易支付接口,回調位址請在通用設定中配置。", - "请确认商户和所选环境密钥一致。": "請確認商戶與所選環境密鑰一致。", - "请确认 Merchant、Store、Product 和所选环境密钥一致。": "請確認 Merchant、Store、Product 與所選環境密鑰一致。", "(筛选后显示 {{count}} 条)_other": "(篩選後顯示 {{count}} 條)", "(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}": "(輸入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}", "(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}": "(輸入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音訊輸入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}", "(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}": "(輸入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 快取 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}", "(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}": "(輸入 {{nonImageInput}} tokens + 圖片輸入 {{imageInput}} tokens / 1M tokens * {{symbol}}{{price}}", + ") and choose a model name available on your account.": "),并选择你账户可用的模型名称。", "[最多请求次数]和[最多请求完成次数]的最大值为2147483647。": "[最多請求次數]和[最多請求完成次數]的最大值為2147483647。", "[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。": "[最多請求次數]必須大於等於0,[最多請求完成次數]必須大於等於1。", "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}": "{\n \"default\": [200, 100],\n \"vip\": [0, 1000]\n}", @@ -67,12 +65,20 @@ "5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})": "5m快取建立價格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m快取建立倍率: {{cacheCreationRatio5m}})", "5m缓存创建价格:{{symbol}}{{price}} / 1M tokens": "5m快取建立價格:{{symbol}}{{price}} / 1M tokens", "8 - 高": "8 - 高", + "Add a custom Anthropic provider or Claude model in Trae settings.": "在 Trae 设置中添加 Anthropic 自定义 Provider 或 Claude 模型。", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "在 OpenCode 中添加 FaceCloud 作为 OpenAI 兼容 Provider。", + "Add the FaceCloud provider configuration:": "添加 FaceCloud Provider 配置:", + "Add the following environment variables:": "添加以下环境变量:", + "Add the following variables:": "添加以下变量:", "AGPL v3.0协议": "AGPL v3.0協議", "AI 对话": "AI 對話", "AI模型测试环境": "AI模型測試環境", "AI模型配置": "AI模型設定", "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key": "AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "也可运行 opencode auth login 添加自定义 Provider:id 设为 facecloud,Base URL 设为 FaceCloud 的 /v1 端点,并按提示粘贴 API Key。", + "and your-model-name with your API key and desired model.": "和 your-model-name 替换为你的 API Key 与目标模型。", "anthropic-beta JSON 示例": "", + "Anthropic-compatible models": "Anthropic 兼容模型", "API Key": "API Key", "API Key 模式下不支持批量创建": "API Key 模式下不支援批量建立", "API Key 验证失败": "API Key 驗證失敗", @@ -97,11 +103,14 @@ "Bark推送URL必须以http://或https://开头": "Bark推送URL必須以http://或https://開頭", "Bark通知": "Bark通知", "Basic Auth 头": "Basic Auth 頭", + "Before you start": "开始之前", "Cached tokens": "", "Cached tokens 占比口径由后端返回:Claude 语义按 cached/(prompt+cached),其余按 cached/prompt。": "", "Changing batch type to:": "Changing batch type to:", "ChatCompletions→Responses 兼容配置": "", "ChatCompletions→Responses 兼容配置(Beta)": "ChatCompletions→Responses 兼容設定(Beta)", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code 从 ~/.claude/settings.json 读取配置。保存后请重启 CLI。", "Claude 强制 beta=true": "", "Claude会在原有请求头基础上追加这些值,不会覆盖已有同名请求头;重复值会自动忽略。": "Claude會在原有請求頭基礎上追加這些值,不會覆蓋已有同名請求頭;重複值會自動忽略。", "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Claude思考相容 BudgetTokens = MaxTokens * BudgetTokens 百分比", @@ -110,23 +119,39 @@ "Claude请求头追加": "Claude請求頭追加", "Client ID": "Client ID", "Client Secret": "Client Secret", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy 通过 CODEBUDDY_API_KEY 与 CODEBUDDY_BASE_URL 定位 API。请将 your-model-name 替换为你账户已启用的模型。", + "Codex": "Codex", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex 使用 ~/.codex/config.toml 配置,并从 FACEAPI_API_KEY 环境变量读取 API Key。", "Codex 授权": "", "Codex 渠道不支持批量创建": "", "common.changeLanguage": "common.changeLanguage", "Completion tokens": "", "Configuration": "", + "Configuration reference": "配置说明", + "Configure Codex": "配置 Codex", + "Configure environment": "配置环境变量", + "Configure FaceCloud": "配置 FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "配置 OpenAI Codex CLI,通过 OpenAI 兼容 Chat Completions 使用 FaceCloud。", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "为 Trae IDE / Trae Agent(Trace)配置完整 FaceCloud 端点路径以使用自定义模型。", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "通过环境变量或 settings.json 将腾讯 CodeBuddy CLI 接入 FaceCloud。", "context_int/context_string 从请求上下文读取;gjson 从入口请求的 JSON body 按 gjson path 读取。": "", "CPU 使用率超过此值时拒绝请求": "CPU 使用率超過此值時拒絕請求", "CPU 阈值 (%)": "CPU 閾值 (%)", + "Create or edit": "创建或编辑", + "Create the config directory if it does not exist:": "若目录不存在,请先创建:", "Creem API 密钥,敏感信息不显示": "Creem API 密鑰,敏感資訊不顯示", "Creem Setting Tips": "Creem 只支援預設的固定金額產品,這產品以及價格需要提前在Creem網站內建立設定,所以不支援自訂動態金額儲值。在Creem端設定產品的名字以及價格,獲取Product Id 後填到下面的產品,在new-api為該產品設定儲值額度,以及展示價格。", "Creem 介绍": "Creem 是一個簡單的支付處理平臺,支援固定金額產品銷售,以及訂閱銷售。", "Creem 充值": "Creem 儲值", "Creem 设置": "Creem 設定", + "Default model name for requests": "默认请求模型名称", "default 和 vip 只能由管理员在「用户管理」中分配给用户。适用于按用户等级定价、内部测试等不希望用户自主选择的场景。": "default 和 vip 只能由管理員在「使用者管理」中分配給使用者。適用於按使用者等級定價、內部測試等不希望使用者自主選擇的場景。", "default为默认设置,可单独设置每个分类的安全等级": "default為預設設定,可單獨設定每個分類的安全等級", "default为默认设置,可单独设置每个模型的版本": "default為預設設定,可單獨設定每個模型的版本", "Dify渠道只适配chatflow和agent,并且agent不支持图片!": "Dify管道只相容chatflow和agent,並且agent不支援圖片!", + "Disables attribution header when using a proxy": "使用代理时禁用归属请求头", + "Disables experimental beta headers for third-party gateways": "禁用实验性 Beta 请求头,便于第三方网关接入", "Discord": "Discord", "Discord Client ID": "Discord Client ID", "Discord Client Secret": "Discord Client Secret", @@ -134,11 +159,24 @@ "Discovery claims": "", "Discovery scopes": "", "Discovery 建议 scopes:": "", + "Edit opencode.json with the FaceCloud provider:": "在 opencode.json 中添加 FaceCloud Provider:", + "Endpoint reference": "端点参考", + "Environment variable holding your API key": "存放 API Key 的环境变量名", + "Environment variables": "环境变量", "EUR (欧元)": "EUR (歐元)", + "Export the following variables in your terminal or shell profile:": "在终端或 Shell 配置中导出以下变量:", + "FaceCloud gateway URL": "FaceCloud 网关地址", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini 兼容基础 URL", + "FaceCloud Integration Guides": "FaceCloud 集成教程", "false": "false", + "For model availability and pricing, visit the pricing page or dashboard.": "模型可用性与价格请查看定价页或控制台。", + "For OpenAI-compatible models, set the request URL to:": "OpenAI 兼容模型请将请求 URL 设为:", + "Full endpoint URL": "完整端点 URL", "GC 已执行": "GC 已執行", "GC 执行失败": "GC 執行失敗", "GC 次数": "GC 次數", + "Gemini CLI": "Gemini CLI", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI 默认从 ~/.env 加载环境变量,也可在 Shell 配置文件中导出。", "Gemini安全设置": "Gemini安全設定", "Gemini思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Gemini思考相容 BudgetTokens = MaxTokens * BudgetTokens 百分比", "Gemini思考适配设置": "Gemini思考相容設定", @@ -158,8 +196,17 @@ "Grok设置": "Grok設定", "Homepage URL 填": "Homepage URL 填", "ID": "ID", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "若 CodeBuddy 支持 settings.json 的 env 字段(类似 Claude Code),可持久化配置:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "若返回 404,请检查 Trae 中是否填写了完整路径,并确认 FaceCloud 已开放对应转发路由。", + "Important": "重要", + "in the examples below with your real key. API base URL:": "替换为你的真实 Key。API 基础地址:", + "in your home directory.": "(位于用户主目录)。", "include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护": "", "inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息": "inference_geo 字段用於控制 Claude 資料駐留推理區域。預設關閉以避免未經授權透傳地域資訊", + "Install Claude Code": "安装 Claude Code", + "Integration": "集成", + "Integration guides": "集成教程", + "Interactive login": "交互式登录", "IP": "IP", "IP白名单": "IP白名單", "IP白名单(支持CIDR表达式)": "IP白名單(支援CIDR表達式)", @@ -182,15 +229,19 @@ "Key 摘要": "Key 摘要", "Key 来源": "", "Key 来源类型": "", + "Launch OpenCode and verify that requests route through FaceCloud.": "启动 OpenCode 并确认请求经由 FaceCloud 转发。", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "了解如何将 FaceCloud 接入常用 AI 编程工具与 IDE。FaceCloud 作为统一 API 网关,只需一个 API Key 即可使用多种模型服务。", "Linux DO Client ID": "Linux DO Client ID", "Linux DO Client Secret": "Linux DO Client Secret", "LinuxDO": "LinuxDO", "LinuxDO ID": "LinuxDO ID", "Logo 图片地址": "Logo 圖片位址", + "Manual configuration": "手动配置", "Midjourney 任务记录": "Midjourney 任務記錄", "MIT许可证": "MIT許可證", "New API项目仓库地址:": "New API項目倉庫位址:", "NewAPI 默认不会将入口请求的 User-Agent 透传到上游渠道;该条件仅用于识别访问本站点的客户端。": "", + "Note": "说明", "OAuth Client ID": "", "OAuth Client Secret": "", "OAuth 登录失败:": "OAuth 登錄失敗:", @@ -200,6 +251,14 @@ "OIDC ID": "OIDC ID", "Ollama 模型管理": "Ollama 模型管理", "Ollama 版本信息": "Ollama 版本資訊", + "Open menu": "打开菜单", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "打开 Trae IDE 设置,进入自定义模型或 AI Provider 配置。", + "OpenAI-compatible base URL at {{url}}": "OpenAI 兼容基础 URL:{{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI 兼容端点:{{url}}", + "OpenAI-compatible models": "OpenAI 兼容模型", + "OpenCode": "OpenCode", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode 配置文件位于 ~/.config/opencode/opencode.json,也可通过 opencode auth login 交互式登录。", + "Overview": "概览", "Passkey": "Passkey", "Passkey 已解绑": "Passkey 已解綁", "Passkey 已重置": "Passkey 已重置", @@ -210,17 +269,30 @@ "Pay Method Name": "", "Pay Method Type": "", "Ping间隔(秒)": "Ping間隔(秒)", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "将 Google Gemini CLI 指向 FaceCloud 的 Gemini 兼容 API。", "POST 参数": "", + "Powered by": "技术支持", "price_xxx 的商品价格 ID,新建产品后可获得": "price_xxx 的商品價格 ID,新建產品後可獲得", "Prompt cache hit tokens": "", "Prompt tokens": "", + "Provider": "提供商", "Reasoning Effort": "Reasoning Effort", + "Reload your shell or run source on the file after exporting the variable.": "导出变量后请重新加载 Shell,或执行 source 使配置生效。", + "Replace": "将", "Request ID": "", "RSA 私钥 (沙盒)": "", "RSA 私钥 (生产)": "", + "Run claude in a new terminal session to verify the connection.": "在新终端中运行 claude 验证连接。", + "Run codebuddy from the same shell session to use FaceCloud.": "在同一 Shell 会话中运行 codebuddy 即可使用 FaceCloud。", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "运行 Gemini CLI 并发送测试请求以确认连接。", "safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私": "safety_identifier 字段用於幫助 OpenAI 識別可能違反使用政策的應用程式使用者。預設關閉以保護使用者隱私", "Scopes(可选)": "", "service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用": "service_tier 字段用於指定服務層級,允許透傳可能導致實際計費高於預期。預設關閉以避免額外費用", + "Set the API key to your FaceCloud key (": "API Key 填写 FaceCloud Key(", + "Set the messages endpoint to:": "将 messages 端点设为:", + "Set your API key": "设置 API Key", + "settings.json (optional)": "settings.json(可选)", + "Shell environment": "Shell 环境变量", "sk_xxx 或 rk_xxx 的 Stripe 密钥,敏感信息不显示": "sk_xxx 或 rk_xxx 的 Stripe 密鑰,敏感資訊不顯示", "SMTP 发送者邮箱": "SMTP 發送者信箱", "SMTP 服务器地址": "SMTP 伺服器位址", @@ -234,6 +306,7 @@ "SSRF防护设置": "SSRF防護設定", "SSRF防护详细说明": "SSRF防護可防止惡意使用者利用您的伺服器訪問內網資源。您可以設定受信任域名/IP的白名單,並限制允許的端口。適用於檔案下載、Webhook回調和通知功能。", "standard 已被移除,vip 用户看不到": "standard 已被移除,vip 使用者看不到", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "启动 Codex 并选择 FaceCloud Provider,将 model 改为你账户可用的模型。", "store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用": "store 字段用於授權 OpenAI 存儲請求數據以評估和優化產品。預設關閉,開啟後可能導致 Codex 無法正常使用", "Stripe 设置": "Stripe 設定", "Stripe/Creem 商品ID(可选)": "Stripe/Creem 商品ID(可選)", @@ -242,9 +315,12 @@ "Telegram Bot Token": "Telegram Bot Token", "Telegram Bot 名称": "Telegram Bot 名稱", "Telegram ID": "Telegram ID", + "Tip": "提示", "Token Endpoint": "Token Endpoint", "token 会按倍率换算成“额度/次数”,请求结束后再做差额结算(补扣/返还)。": "", "Total tokens": "", + "Trace (Trae IDE)": "Trace(Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae 需要填写完整 URL(含路径),不要只填域名,请使用下方所示的 /v1/chat/completions 或 /v1/messages。", "true": "true", "TTL(秒,0 表示默认)": "", "TTL(秒)": "", @@ -256,10 +332,14 @@ "URL 标识,只能包含小写字母、数字和连字符": "", "URL链接": "URL連結", "USD (美元)": "USD (美元)", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "在 Authorization 头中使用 Bearer 方式携带 FaceCloud API Key。", + "Use chat completions wire format": "使用 Chat Completions 协议", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "在终端中将 FaceCloud 配置为 Claude Code CLI 的 Anthropic API 端点。", "User Info Endpoint": "User Info Endpoint", "User-Agent include(每行一个,可不写)": "", "Value 正则": "", "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI 不支援 functionResponse.id 字段,開啟後將自動移除該字段", + "View guide": "查看教程", "Waffo API 参数,可空,例如:CREDITCARD,DEBITCARD(最多64位)": "", "Waffo API 参数,可空(最多64位)": "", "Waffo 充值": "", @@ -283,8 +363,12 @@ "Well-Known URL": "Well-Known URL", "Well-Known URL 必须以 http:// 或 https:// 开头": "Well-Known URL 必須以 http:// 或 https:// 開頭", "whsec_xxx 的 Webhook 签名密钥,敏感信息不显示": "whsec_xxx 的 Webhook 簽名密鑰,敏感資訊不顯示", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "替换为你的 FaceCloud API Key,并将 GEMINI_MODEL 设为你账户支持的模型。", + "with your FaceCloud API key.": "替换为你的 FaceCloud API Key。", "Worker地址": "Worker位址", "Worker密钥": "Worker密鑰", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "你需要一个 FaceCloud API Key。在控制台创建后,将示例中的", + "Your FaceCloud API key": "你的 FaceCloud API Key", "一个月": "一個月", "一天": "一天", "一小时": "一小時", @@ -499,6 +583,7 @@ "例如": "例如", "例如 /var/cache/new-api": "例如 /var/cache/new-api", "例如 €, £, Rp, ₩, ₹...": "例如 €, £, Rp, ₩, ₹...", + "例如 Asia/Shanghai": "例如 Asia/Shanghai", "例如 https://docs.newapi.pro": "例如 https://docs.newapi.pro", "例如 https://example.com/api/waffo/webhook": "", "例如 https://example.com/console/topup": "", @@ -729,7 +814,6 @@ "最低充值数量": "", "最低充值美元数量": "最低儲值美元數量", "最低充值美元数量必须大于 0": "最低儲值美元數量必須大於 0", - "留空则自动使用当前站点的默认回调地址": "留空則自動使用目前站點的預設回調位址", "最后使用时间": "最後使用時間", "最后更新": "最後更新", "最后请求": "最後請求", @@ -773,6 +857,9 @@ "切换为System角色": "切換為System角色", "切换为单密钥模式": "切換為單密鑰模式", "切换主题": "切換主題", + "切换到新版前端": "切換到新版前端", + "切换后页面会自动刷新,并进入新版前端。是否继续?": "切換後頁面會自動重新整理,並進入新版前端。是否繼續?", + "切换失败,请稍后重试": "切換失敗,請稍後重試", "划转到余额": "劃轉到餘額", "划转邀请额度": "劃轉邀請額度", "划转金额最低为": "劃轉金額最低為", @@ -911,9 +998,6 @@ "取消": "取消", "取消全选": "取消全選", "取消选择": "取消選擇", - "切换到新版前端": "切換到新版前端", - "切换后页面会自动刷新,并进入新版前端。是否继续?": "切換後頁面會自動重新整理,並進入新版前端。是否繼續?", - "切换失败,请稍后重试": "切換失敗,請稍後重試", "变换": "變換", "变更": "變更", "变焦": "變焦", @@ -1281,7 +1365,12 @@ "导入配置": "導入設定", "导入配置失败: ": "導入設定失敗: ", "导出": "導出", + "导出失败": "匯出失敗", "导出日志失败": "導出日誌失敗", + "导出月账单": "匯出月帳單", + "导出月账单和消费明细": "匯出月帳單和消費明細", + "导出消费明细": "匯出消費明細", + "导出用量CSV": "匯出用量 CSV", "导出配置": "導出設定", "导出配置失败: ": "導出設定失敗: ", "将 reasoning_content 转换为 标签拼接到内容中": "將 reasoning_content 轉換為 標籤拼接到內容中", @@ -1322,6 +1411,7 @@ "已分配内存": "已分配記憶體", "已切换为Assistant角色": "已切換為Assistant角色", "已切换为System角色": "已切換為System角色", + "已切换到新版前端,正在刷新页面": "已切換到新版前端,正在重新整理頁面", "已切换至最优倍率视图,每个模型使用其最低倍率分组": "已切換至最優倍率視圖,每個模型使用其最低倍率分組", "已初始化": "已初始化", "已删除": "", @@ -1337,7 +1427,6 @@ "已发起支付": "已發起支付", "已发送到 Fluent": "已發送到 Fluent", "已取消 Passkey 注册": "已取消 Passkey 註冊", - "已切换到新版前端,正在刷新页面": "已切換到新版前端,正在重新整理頁面", "已同步到渠道": "已同步到管道", "已启用": "已啟用", "已启用 Passkey,无需密码即可登录": "已啟用 Passkey,無需密碼即可登錄", @@ -1365,6 +1454,7 @@ "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型": "已將模型 {{name}} 的價格配置批量套用到 {{count}} 個模型", "已将模型 {{name}} 的价格配置批量应用到 {{count}} 个模型_other": "", "已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。": "已開啟全域請求透傳:參數覆寫、模型重定向、管道相容等 NewAPI 內置功能將失效,非最佳實踐;如因此產生問題,請勿提交 issue 回饋。", + "已开始下载": "已開始下載", "已忽略模型": "", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "已成功開始測試所有已啟用通道,請刷新頁面查看結果。", "已打开授权页面": "", @@ -1418,6 +1508,8 @@ "平均TPM": "平均TPM", "平移": "平移", "年": "", + "年份": "年份", + "年份无效": "年份無效", "应付金额": "應付金額", "应用": "", "应用同步": "應用同步", @@ -1473,6 +1565,7 @@ "当前 API 密钥已过期,请在设置中更新。": "當前 API 密鑰已過期,請在設定中更新。", "当前 Ollama 版本为 ${version}": "當前 Ollama 版本為 ${version}", "当前仅 OpenAI / Claude 语义支持缓存 token 统计,其他通道将隐藏 token 相关字段。": "", + "当前仅支持易支付接口,回调地址请在通用设置中配置。": "目前僅支援易支付接口,回調位址請在通用設定中配置。", "当前余额": "當前餘額", "当前值": "當前值", "当前值不是合法 JSON,无法格式化": "", @@ -1814,6 +1907,7 @@ "旧格式模板": "舊格式模板", "旧的备用码已失效,请保存新的备用码": "舊的備用碼已失效,請儲存新的備用碼", "早上好": "早安", + "时区(IANA,可选)": "時區(IANA,選填)", "时间": "時間", "时间信息": "時間資訊", "时间粒度": "時間粒度", @@ -1925,6 +2019,7 @@ "更新预填组": "更新預填組", "替换": "", "月": "", + "月份无效": "月份無效", "有 Reasoning": "有 Reasoning", "有序字符串数组": "有序字串陣列", "有效期": "有效期", @@ -1934,7 +2029,6 @@ "服务可用性": "服務可用性", "服务商": "服務商", "服务器IP": "伺服器IP", - "节点名称": "節點名稱", "服务器地址": "伺服器位址", "服务器日志功能未启用(未配置日志目录)": "伺服器日誌功能未啟用(未配置日誌目錄)", "服务器日志管理": "伺服器日誌管理", @@ -2407,6 +2501,8 @@ "用户账户创建成功!": "使用者帳號建立成功!", "用户账户管理": "使用者帳號管理", "用时/首字": "用時/首字", + "用量导出时区说明": "未填則依伺服器本地時區劃分曆月;填寫後依該 IANA 時區的曆月。", + "用量导出说明": "為使用者 {{name}}(ID {{id}})依所選曆月匯出 CSV(月帳單為彙總,消費明細為逐筆呼叫)。", "由全站货币展示设置统一控制": "由全站貨幣展示設定統一控制", "由管理员分配,决定用户身份等级(如 default、vip)。": "由管理員分配,決定使用者身份等級(如 default、vip)。", "由订阅抵扣": "由訂閱抵扣", @@ -2416,6 +2512,7 @@ "留空则使用默认端点;支持 {path, method}": "留空則使用預設端點;支援 {path, method}", "留空则保持原有密钥": "", "留空则自动使用 服务器地址 + /api/waffo/webhook": "", + "留空则自动使用当前站点的默认回调地址": "留空則自動使用目前站點的預設回調位址", "留空则默认使用服务器地址,注意不能携带http://或者https://": "留空則預設使用伺服器位址,注意不能攜帶http://或者https://", "登 录": "登 錄", "登录": "登錄", @@ -2489,6 +2586,7 @@ "确认作废": "確認作廢", "确认关闭提示": "確認關閉提示", "确认冲突项修改": "確認衝突項修改", + "确认切换": "確認切換", "确认删除": "確認刪除", "确认删除模型": "確認刪除模型", "确认删除该分组?": "確認刪除該分組?", @@ -2496,7 +2594,6 @@ "确认删除该规则?": "確認刪除該規則?", "确认取消密码登录": "確認取消密碼登錄", "确认启用": "", - "确认切换": "確認切換", "确认密码": "確認密碼", "确认导入配置": "確認導入設定", "确认延长": "確認延長", @@ -2804,6 +2901,7 @@ "自用模式": "自用模式", "自适应列表": "動態列表", "至": "至", + "节点名称": "節點名稱", "节省": "節省", "花费": "花費", "花费时间": "花費時間", @@ -3031,7 +3129,9 @@ "请求配置": "請求設定", "请求预扣费额度": "請求預扣費額度", "请点击我": "請點擊我", + "请确认 Merchant、Store、Product 和所选环境密钥一致。": "請確認 Merchant、Store、Product 與所選環境密鑰一致。", "请确认以下设置信息,点击\"初始化系统\"开始配置": "請確認以下設定資訊,點擊\"初始化系統\"開始設定", + "请确认商户和所选环境密钥一致。": "請確認商戶與所選環境密鑰一致。", "请确认您已了解禁用两步验证的后果": "請確認您已瞭解禁用兩步驗證的後果", "请确认管理员密码": "請確認管理員密碼", "请稍后几秒重试,Turnstile 正在检查用户环境!": "請稍後幾秒重試,Turnstile 正在檢查使用者環境!", @@ -3520,6 +3620,8 @@ "镜像配置": "鏡像設定", "问题标题": "問題標題", "队列中": "隊列中", + "阶梯计费(未匹配到对应阶梯)": "階梯計費(未匹配到對應階梯)", + "阶梯计费(表达式解析失败)": "階梯計費(表達式解析失敗)", "附加条件": "", "降低您账户的安全性": "降低您帳號的安全性", "降级": "降級", @@ -3640,8 +3742,6 @@ "默认折叠侧边栏": "預設摺疊側邊欄", "默认测试模型": "預設測試模型", "默认用户消息": "你好", - "默认补全倍率": "預設補全倍率", - "阶梯计费(表达式解析失败)": "階梯計費(表達式解析失敗)", - "阶梯计费(未匹配到对应阶梯)": "階梯計費(未匹配到對應階梯)" + "默认补全倍率": "預設補全倍率" } } diff --git a/web/classic/src/i18n/locales/zh.json b/web/classic/src/i18n/locales/zh.json index e23930f5e1d6..46fac73dff48 100644 --- a/web/classic/src/i18n/locales/zh.json +++ b/web/classic/src/i18n/locales/zh.json @@ -868,6 +868,9 @@ "导入配置": "导入配置", "导入配置失败: ": "导入配置失败: ", "导出": "导出", + "导出日志": "导出日志", + "导出成功": "导出成功", + "导出失败": "导出失败", "导出日志失败": "导出日志失败", "导出配置": "导出配置", "导出配置失败: ": "导出配置失败: ", @@ -1604,6 +1607,15 @@ "渠道的模型测试": "渠道的模型测试", "渠道的高级配置选项": "渠道的高级配置选项", "渠道管理": "渠道管理", + "渠道消费统计": "渠道消费统计", + "按用户筛选(可选)": "按用户筛选(可选)", + "应用用户筛选": "应用用户筛选", + "清除用户筛选": "清除用户筛选", + "请求总数": "请求总数", + "Token 总数": "Token 总数", + "渠道历史总消耗": "渠道历史总消耗", + "加载消费统计失败": "加载消费统计失败", + "用户ID无效": "用户ID无效", "渠道额外设置": "渠道额外设置", "源地址": "源地址", "演示站点": "演示站点", diff --git a/web/classic/src/pages/Docs/IntegrationClaudeCode.jsx b/web/classic/src/pages/Docs/IntegrationClaudeCode.jsx new file mode 100644 index 000000000000..663a4273590a --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationClaudeCode.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import ClaudeCodePage from '../../components/docs/integration/pages/ClaudeCodePage'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(ClaudeCodePage); diff --git a/web/classic/src/pages/Docs/IntegrationCodeBuddy.jsx b/web/classic/src/pages/Docs/IntegrationCodeBuddy.jsx new file mode 100644 index 000000000000..b10bae54ab2e --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationCodeBuddy.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import CodeBuddyPage from '../../components/docs/integration/pages/CodeBuddyPage'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(CodeBuddyPage); diff --git a/web/classic/src/pages/Docs/IntegrationCodex.jsx b/web/classic/src/pages/Docs/IntegrationCodex.jsx new file mode 100644 index 000000000000..696e5bf3eb44 --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationCodex.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import CodexPage from '../../components/docs/integration/pages/CodexPage'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(CodexPage); diff --git a/web/classic/src/pages/Docs/IntegrationGeminiCli.jsx b/web/classic/src/pages/Docs/IntegrationGeminiCli.jsx new file mode 100644 index 000000000000..a9c27f896e6a --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationGeminiCli.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import GeminiCliPage from '../../components/docs/integration/pages/GeminiCliPage'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(GeminiCliPage); diff --git a/web/classic/src/pages/Docs/IntegrationHome.jsx b/web/classic/src/pages/Docs/IntegrationHome.jsx new file mode 100644 index 000000000000..c5bfda590b87 --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationHome.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import IntegrationHome from '../../components/docs/integration/IntegrationHome'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(IntegrationHome); diff --git a/web/classic/src/pages/Docs/IntegrationOpenCode.jsx b/web/classic/src/pages/Docs/IntegrationOpenCode.jsx new file mode 100644 index 000000000000..e8fcc0e3b942 --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationOpenCode.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import OpenCodePage from '../../components/docs/integration/pages/OpenCodePage'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(OpenCodePage); diff --git a/web/classic/src/pages/Docs/IntegrationTrace.jsx b/web/classic/src/pages/Docs/IntegrationTrace.jsx new file mode 100644 index 000000000000..c5a9eb7767f3 --- /dev/null +++ b/web/classic/src/pages/Docs/IntegrationTrace.jsx @@ -0,0 +1,23 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import TracePage from '../../components/docs/integration/pages/TracePage'; +import withIntegrationLayout from './withIntegrationLayout'; + +export default withIntegrationLayout(TracePage); diff --git a/web/classic/src/pages/Docs/Redirect.jsx b/web/classic/src/pages/Docs/Redirect.jsx new file mode 100644 index 000000000000..efd863ffc480 --- /dev/null +++ b/web/classic/src/pages/Docs/Redirect.jsx @@ -0,0 +1,24 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import { Navigate } from 'react-router-dom'; + +const DocsRedirect = () => ; + +export default DocsRedirect; diff --git a/web/classic/src/pages/Docs/withIntegrationLayout.jsx b/web/classic/src/pages/Docs/withIntegrationLayout.jsx new file mode 100644 index 000000000000..05a03ae4a09f --- /dev/null +++ b/web/classic/src/pages/Docs/withIntegrationLayout.jsx @@ -0,0 +1,33 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import IntegrationLayout from '../../components/docs/integration/IntegrationLayout'; + +const withIntegrationLayout = (PageComponent) => { + const WrappedPage = () => ( + + + + ); + + return WrappedPage; +}; + +export default withIntegrationLayout; diff --git a/web/classic/src/pages/Home/index.jsx b/web/classic/src/pages/Home/index.jsx index c153c1b3da99..12a36430abb1 100644 --- a/web/classic/src/pages/Home/index.jsx +++ b/web/classic/src/pages/Home/index.jsx @@ -26,6 +26,7 @@ import { ScrollItem, } from '@douyinfe/semi-ui'; import { API, showError, copy, showSuccess } from '../../helpers'; +import { resolveDocsNavLink } from '../../helpers/docsNavLink'; import { useIsMobile } from '../../hooks/common/useIsMobile'; import { API_ENDPOINTS } from '../../constants/common.constant'; import { StatusContext } from '../../context/Status'; @@ -38,7 +39,7 @@ import { IconFile, IconCopy, } from '@douyinfe/semi-icons'; -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; import NoticeModal from '../../components/layout/NoticeModal'; import { Moonshot, @@ -67,6 +68,7 @@ const { Text } = Typography; const Home = () => { const { t, i18n } = useTranslation(); + const navigate = useNavigate(); const [statusState] = useContext(StatusContext); const actualTheme = useActualTheme(); const [homePageContentLoaded, setHomePageContentLoaded] = useState(false); @@ -244,7 +246,17 @@ const Home = () => { size={isMobile ? 'default' : 'large'} className='flex items-center !rounded-3xl px-6 py-2' icon={} - onClick={() => window.open(docsLink, '_blank')} + onClick={() => { + const { href, external } = resolveDocsNavLink( + docsLink, + statusState?.status?.server_address, + ); + if (external) { + window.open(href, '_blank'); + } else { + navigate(href); + } + }} > {t('文档')} diff --git a/web/default/public/home-custom.html b/web/default/public/home-custom.html new file mode 100644 index 000000000000..ad49aded5831 --- /dev/null +++ b/web/default/public/home-custom.html @@ -0,0 +1,1031 @@ + + + + + + + + 首页 · New API + + + +
+ +
+ +
+
+
+
+ + 企业级 · OpenAI 兼容 · 多渠道聚合 +
+

+ 企业级 AI 平台 + 面向团队与规模化生产:统一接入、权限与配额、可观测与计费,一站满足严肃业务上线要求。 +

+

+ 一站式 AI 接口聚合
+ 让调用大模型像调用 HTTP 一样简单 +

+

+ 企业级 AI 平台定位:提供快速、便捷的 大模型 API + 调用方案,打造稳定可靠、易于治理 + 的接口平台,一站式集成几乎所有AI大模型,支撑业务持续增长。 +

+
+

+ 更好的价格,更好的稳定性,只需要将模型基址替换为: +

+
+ + /v1/chat/completions + +
+
+ +

已经接入100+ 大模型

+
+ +
+
+

兼容生态与常见上游

+
+ OpenAI + Anthropic Claude + Google Gemini + Azure OpenAI + AWS Bedrock + DeepSeek + 通义·豆包·混元 + Dify · Open WebUI · Lobe Chat +
+
+
+
+ +
+
+
+

我们的优势

+

适配多种业务场景,驱动业务增长。

+
+
+
+ +

统一兼容路由

+

+ 一套 OpenAI 风格 API,对接多种上游渠道与模型别名,降低客户端改造成本。 +

+
+
+ +

密钥与权限

+

用户、分组与令牌管理,配合速率限制与路由策略,便于多团队协作。

+
+
+ +

用量与计费

+

日志、配额与计费表达式,支持按模型与业务维度做精细化结算。

+
+
+ +

可观测性

+

请求追踪与失败重试策略更清晰,便于排查上游抖动与限额问题。

+
+
+ +

服务保障

+

+ 稳定的网关能力与清晰的故障处理流程,配合监控与告警,降低业务中断风险。 +

+
+
+ +

透明计费

+

+ 计价规则与用量明细可追溯,结算逻辑可核对,避免「看不清、对不上」的账单困扰。 +

+
+
+
+
+ +
+
+
+

几分钟完成接入

+

+ 注册账号 → 配置上游渠道与模型 → 创建 API 密钥,即可在现有应用中替换基地址开始调用。 +

+ +
+
+
+
+ + + diff --git a/web/default/public/logo.png b/web/default/public/logo.png index 851556f62db5..02937172b371 100644 Binary files a/web/default/public/logo.png and b/web/default/public/logo.png differ diff --git a/web/default/src/features/channels/api.ts b/web/default/src/features/channels/api.ts index af58d3422dbf..a7175d51869a 100644 --- a/web/default/src/features/channels/api.ts +++ b/web/default/src/features/channels/api.ts @@ -520,6 +520,47 @@ export async function getOllamaVersion( return res.data } +// ============================================================================ +// Channel Consumption Statistics +// ============================================================================ + +export type GetChannelConsumptionParams = { + start_timestamp: number + end_timestamp: number + user_id?: number + username?: string +} + +export type ChannelConsumptionData = { + channel_id: number + channel_name: string + start_timestamp: number + end_timestamp: number + quota: number + request_count: number + prompt_tokens: number + completion_tokens: number + lifetime_used_quota: number + user_id?: number + username?: string +} + +export type ChannelConsumptionResponse = { + success: boolean + message?: string + data?: ChannelConsumptionData +} + +export async function getChannelConsumption( + channelId: number, + params: GetChannelConsumptionParams +): Promise { + const res = await api.get(`/api/channel/${channelId}/consumption`, { + params, + }) + return res.data +} + // ============================================================================ // Group Management // ============================================================================ diff --git a/web/default/src/features/channels/components/channels-dialogs.tsx b/web/default/src/features/channels/components/channels-dialogs.tsx index 4bc66ef73f28..4c2b54934895 100644 --- a/web/default/src/features/channels/components/channels-dialogs.tsx +++ b/web/default/src/features/channels/components/channels-dialogs.tsx @@ -1,5 +1,6 @@ import { useChannels } from './channels-provider' import { BalanceQueryDialog } from './dialogs/balance-query-dialog' +import { ChannelConsumptionDialog } from './dialogs/channel-consumption-dialog' import { ChannelTestDialog } from './dialogs/channel-test-dialog' import { CopyChannelDialog } from './dialogs/copy-channel-dialog' import { EditTagDialog } from './dialogs/edit-tag-dialog' @@ -34,6 +35,11 @@ export function ChannelsDialogs() { onOpenChange={(v) => !v && setOpen(null)} /> + !v && setOpen(null)} + /> + {/* Fetch Models Dialog */} diff --git a/web/default/src/features/channels/components/data-table-row-actions.tsx b/web/default/src/features/channels/components/data-table-row-actions.tsx index a15b17a074de..82cc6fdec951 100644 --- a/web/default/src/features/channels/components/data-table-row-actions.tsx +++ b/web/default/src/features/channels/components/data-table-row-actions.tsx @@ -8,6 +8,7 @@ import { TestTube, Gauge, DollarSign, + BarChart3, Download, Copy, Power, @@ -89,6 +90,11 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) { setOpen('balance-query') } + const handleViewConsumption = () => { + setCurrentRow(channel) + setOpen('channel-consumption') + } + const handleFetchModels = () => { setCurrentRow(channel) setOpen('fetch-models') @@ -205,6 +211,13 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) { + + {t('Channel Consumption')} + + + + + {/* Fetch Models */} {t('Fetch Models')} diff --git a/web/default/src/features/channels/components/dialogs/channel-consumption-dialog.tsx b/web/default/src/features/channels/components/dialogs/channel-consumption-dialog.tsx new file mode 100644 index 000000000000..0ae33302bc7a --- /dev/null +++ b/web/default/src/features/channels/components/dialogs/channel-consumption-dialog.tsx @@ -0,0 +1,287 @@ +import { useCallback, useEffect, useMemo, useState } from 'react' +import { useQuery } from '@tanstack/react-query' +import { BarChart3, Loader2, RefreshCw, User } from 'lucide-react' +import { useTranslation } from 'react-i18next' +import dayjs from '@/lib/dayjs' +import { formatLogQuota } from '@/lib/format' +import { computeTimeRange } from '@/lib/time' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { CompactDateTimeRangePicker } from '@/features/usage-logs/components/compact-date-time-range-picker' +import { getChannelConsumption } from '../../api' +import { useChannels } from '../channels-provider' + +type ChannelConsumptionDialogProps = { + open: boolean + onOpenChange: (open: boolean) => void +} + +function defaultMonthRange(): { start: Date; end: Date } { + const now = dayjs() + return { + start: now.startOf('month').toDate(), + end: now.endOf('day').toDate(), + } +} + +export function ChannelConsumptionDialog({ + open, + onOpenChange, +}: ChannelConsumptionDialogProps) { + const { t } = useTranslation() + const { currentRow } = useChannels() + const [range, setRange] = useState(defaultMonthRange) + const [userIdInput, setUserIdInput] = useState('') + const [usernameInput, setUsernameInput] = useState('') + const [appliedUserId, setAppliedUserId] = useState() + const [appliedUsername, setAppliedUsername] = useState() + + useEffect(() => { + if (!open) return + setRange(defaultMonthRange()) + setUserIdInput('') + setUsernameInput('') + setAppliedUserId(undefined) + setAppliedUsername(undefined) + }, [open, currentRow?.id]) + + const timeParams = useMemo(() => { + const { start_timestamp, end_timestamp } = computeTimeRange( + 30, + range.start, + range.end, + false + ) + return { start_timestamp, end_timestamp } + }, [range.end, range.start]) + + const { + data: consumption, + isLoading, + isFetching, + refetch, + error, + } = useQuery({ + queryKey: [ + 'channel-consumption', + currentRow?.id, + timeParams.start_timestamp, + timeParams.end_timestamp, + appliedUserId, + appliedUsername, + ], + queryFn: async () => { + if (!currentRow) throw new Error(t('No channel selected')) + const res = await getChannelConsumption(currentRow.id, { + ...timeParams, + user_id: appliedUserId, + username: appliedUsername, + }) + if (!res.success || !res.data) { + throw new Error(res.message || t('Failed to load consumption')) + } + return res.data + }, + enabled: open && !!currentRow?.id, + }) + + const applyUserFilter = useCallback(() => { + const trimmedUsername = usernameInput.trim() + const parsedUserId = Number.parseInt(userIdInput.trim(), 10) + if (userIdInput.trim()) { + if (!Number.isFinite(parsedUserId) || parsedUserId <= 0) { + setAppliedUserId(undefined) + setAppliedUsername(undefined) + return + } + setAppliedUserId(parsedUserId) + setAppliedUsername(undefined) + return + } + setAppliedUserId(undefined) + setAppliedUsername(trimmedUsername || undefined) + }, [userIdInput, usernameInput]) + + const clearUserFilter = () => { + setUserIdInput('') + setUsernameInput('') + setAppliedUserId(undefined) + setAppliedUsername(undefined) + } + + const totalTokens = useMemo(() => { + if (!consumption) return 0 + return ( + Number(consumption.prompt_tokens || 0) + + Number(consumption.completion_tokens || 0) + ) + }, [consumption]) + + if (!currentRow) return null + + const userFilterActive = appliedUserId != null || !!appliedUsername + + return ( + + + + + + {t('Channel Consumption')} + + + {currentRow.name} (#{currentRow.id}) + + + +
+
+ + + setRange({ + start: next.start ?? range.start, + end: next.end ?? range.end, + }) + } + /> +
+ +
+
+ + {t('Filter by user (optional)')} +
+
+
+ + setUserIdInput(e.target.value)} + placeholder='123' + className='h-8 font-mono text-xs' + /> +
+
+ + setUsernameInput(e.target.value)} + placeholder='alice' + className='h-8 text-xs' + /> +
+
+
+ + {userFilterActive && ( + + )} +
+ {userFilterActive && ( +

+ {appliedUserId != null + ? `${t('User ID')}: ${appliedUserId}` + : `${t('Username')}: ${appliedUsername}`} +

+ )} +
+ +
+ {isLoading ? ( +
+ + {t('Loading...')} +
+ ) : error ? ( +

+ {error instanceof Error ? error.message : t('Failed to load')} +

+ ) : ( +
+
+
{t('Usage')}
+
+ {formatLogQuota(Number(consumption?.quota || 0))} +
+
+
+
+ {t('Total requests')} +
+
+ {consumption?.request_count ?? 0} +
+
+
+
{t('Total tokens')}
+
{totalTokens}
+
+ {!userFilterActive && ( +
+
+ {t('Lifetime channel usage')} +
+
+ {formatLogQuota( + Number(consumption?.lifetime_used_quota || 0) + )} +
+
+ )} +
+ )} +
+
+ + + + + +
+
+ ) +} \ No newline at end of file diff --git a/web/default/src/features/dashboard/components/models/consumption-distribution-chart.tsx b/web/default/src/features/dashboard/components/models/consumption-distribution-chart.tsx index 42bdf0d0e054..7ac3e022627c 100644 --- a/web/default/src/features/dashboard/components/models/consumption-distribution-chart.tsx +++ b/web/default/src/features/dashboard/components/models/consumption-distribution-chart.tsx @@ -9,7 +9,10 @@ import { CONSUMPTION_DISTRIBUTION_CHART_OPTIONS, DEFAULT_TIME_GRANULARITY, } from '@/features/dashboard/constants' -import { processChartData } from '@/features/dashboard/lib' +import { + processChartData, + type ChartTimeRange, +} from '@/features/dashboard/lib' import type { ConsumptionDistributionChartType, QuotaDataItem, @@ -22,6 +25,7 @@ let themeManagerPromise: Promise< interface ConsumptionDistributionChartProps { data: QuotaDataItem[] loading?: boolean + chartTimeRange?: ChartTimeRange timeGranularity?: TimeGranularity defaultChartType?: ConsumptionDistributionChartType } @@ -70,8 +74,20 @@ export function ConsumptionDistributionChart( }, [resolvedTheme]) const chartData = useMemo( - () => processChartData(props.loading ? [] : props.data, timeGranularity, t), - [props.data, props.loading, timeGranularity, t] + () => + processChartData( + props.loading ? [] : props.data, + timeGranularity, + t, + props.chartTimeRange + ), + [ + props.chartTimeRange, + props.data, + props.loading, + timeGranularity, + t, + ] ) const spec = chartType === 'bar' ? chartData.spec_line : chartData.spec_area @@ -113,7 +129,7 @@ export function ConsumptionDistributionChart(
{themeReady && spec && ( = { interface ModelChartsProps { data: QuotaDataItem[] loading?: boolean + chartTimeRange?: ChartTimeRange timeGranularity?: TimeGranularity defaultChartTab?: ModelAnalyticsChartTab } @@ -70,8 +74,20 @@ export function ModelCharts(props: ModelChartsProps) { }, [resolvedTheme]) const chartData = useMemo( - () => processChartData(props.loading ? [] : props.data, timeGranularity, t), - [props.data, props.loading, timeGranularity, t] + () => + processChartData( + props.loading ? [] : props.data, + timeGranularity, + t, + props.chartTimeRange + ), + [ + props.chartTimeRange, + props.data, + props.loading, + timeGranularity, + t, + ] ) const spec = chartData[CHART_SPEC_KEYS[activeTab]] @@ -110,7 +126,7 @@ export function ModelCharts(props: ModelChartsProps) {
{themeReady && spec && ( { + const normalized = { ...filters } + if (normalized.start_timestamp) { + normalized.start_timestamp = getStartOfDay(normalized.start_timestamp) + } + if (normalized.end_timestamp) { + normalized.end_timestamp = getEndOfDay(normalized.end_timestamp) + } + setFilters(normalized) props.onFilterChange( cleanFilters( - filters as unknown as Record + normalized as unknown as Record ) as typeof filters ) setOpen(false) @@ -88,7 +101,7 @@ export function ModelsFilter(props: ModelsFilterProps) { const handleReset = () => { const days = props.preferences.defaultTimeRangeDays - const { start, end } = getRollingDateRange(days) + const { start, end } = getCalendarDayRangeInclusive(days) setFilters({ ...buildDefaultDashboardFilters(props.preferences), start_timestamp: start, @@ -109,7 +122,7 @@ export function ModelsFilter(props: ModelsFilterProps) { } const handleQuickRange = (days: number) => { - const { start, end } = getRollingDateRange(days) + const { start, end } = getCalendarDayRangeInclusive(days) setFilters((prev) => ({ ...prev, diff --git a/web/default/src/features/dashboard/constants.ts b/web/default/src/features/dashboard/constants.ts index 3d0c83b7f08d..8b0097b258c2 100644 --- a/web/default/src/features/dashboard/constants.ts +++ b/web/default/src/features/dashboard/constants.ts @@ -3,7 +3,7 @@ import type { DashboardChartPreferences, DashboardFilters } from './types' export const TIME_GRANULARITY_STORAGE_KEY = 'data_export_default_time' export const DASHBOARD_CHART_PREFERENCES_STORAGE_KEY = 'dashboard_models_chart_preferences' -export const DEFAULT_TIME_GRANULARITY = 'hour' as const +export const DEFAULT_TIME_GRANULARITY = 'day' as const export const MAX_CHART_TREND_POINTS = 7 export const DEFAULT_DASHBOARD_CHART_PREFERENCES: DashboardChartPreferences = { @@ -46,6 +46,6 @@ export const MODEL_ANALYTICS_CHART_OPTIONS = [ export const EMPTY_DASHBOARD_FILTERS: DashboardFilters = { start_timestamp: undefined, end_timestamp: undefined, - time_granularity: 'hour', + time_granularity: 'day', username: '', } diff --git a/web/default/src/features/dashboard/index.tsx b/web/default/src/features/dashboard/index.tsx index af7a4a398217..1bfae89e4048 100644 --- a/web/default/src/features/dashboard/index.tsx +++ b/web/default/src/features/dashboard/index.tsx @@ -1,4 +1,5 @@ import { useState, useCallback, useMemo, lazy, Suspense } from 'react' +import { computeTimeRange } from '@/lib/time' import { getRouteApi, useNavigate } from '@tanstack/react-router' import { useTranslation } from 'react-i18next' import { useAuthStore } from '@/stores/auth-store' @@ -13,6 +14,7 @@ import { } from '@/components/page-transition' import { buildDefaultDashboardFilters, + getDefaultDays, getSavedChartPreferences, saveChartPreferences, } from './lib' @@ -125,6 +127,20 @@ export function Dashboard() { buildDefaultDashboardFilters(getSavedChartPreferences()) ) + const modelChartTimeRange = useMemo( + () => + computeTimeRange( + getDefaultDays(modelFilters.time_granularity), + modelFilters.start_timestamp, + modelFilters.end_timestamp + ), + [ + modelFilters.start_timestamp, + modelFilters.end_timestamp, + modelFilters.time_granularity, + ] + ) + const handleFilterChange = useCallback((filters: DashboardFilters) => { setModelFilters(filters) }, []) @@ -248,6 +264,7 @@ export function Dashboard() { string + +/** Upper bound for generated axis buckets (e.g. ~1 year of daily points). */ +const MAX_CHART_AXIS_BUCKETS = 400 + +export type ChartTimeRange = { + start_timestamp: number + end_timestamp: number +} type TooltipLineItem = { key: string value: string | number @@ -49,7 +61,8 @@ function renderQuotaCompat(rawQuota: number, digits = 4): string { export function processChartData( data: QuotaDataItem[], timeGranularity: TimeGranularity = 'day', - t?: TFunction + t?: TFunction, + timeRange?: ChartTimeRange ): ProcessedChartData { const tt: TFunction = t ?? ((x) => x) const otherLabel = tt('Other') @@ -250,28 +263,55 @@ export function processChartData( range: modelColorRange, } - // Pad time points if too few (default 7 points) const MAX_TREND_POINTS = MAX_CHART_TREND_POINTS - const fillTimePoints = (times: string[]) => { - if (times.length >= MAX_TREND_POINTS) return times - const lastTime = Math.max( - ...data.map((item) => Number(item.created_at) || 0) - ) - const intervalSec = - timeGranularity === 'week' - ? 604800 - : timeGranularity === 'day' - ? 86400 - : 3600 - const padded = Array.from({ length: MAX_TREND_POINTS }, (_, i) => - formatChartTime( - lastTime - (MAX_TREND_POINTS - 1 - i) * intervalSec, - timeGranularity + const intervalSec = + timeGranularity === 'week' + ? 604800 + : timeGranularity === 'day' + ? 86400 + : 3600 + + /** + * Build X-axis time buckets aligned to the dashboard filter range when provided. + * Legacy behavior padded from the latest data timestamp, which ignored the selected period. + */ + const buildChartAxisTimes = (): string[] => { + if (timeRange) { + let cursor = + timeGranularity === 'hour' + ? Math.floor(timeRange.start_timestamp / 3600) * 3600 + : toStartOfDay(timeRange.start_timestamp) + const endTs = timeRange.end_timestamp + const buckets: string[] = [] + while (cursor <= endTs && buckets.length < MAX_CHART_AXIS_BUCKETS) { + buckets.push(formatChartTime(cursor, timeGranularity)) + cursor += intervalSec + } + if (buckets.length === 0) { + return sortedTimes.length > 0 ? sortedTimes : buckets + } + const merged = new Set([...buckets, ...sortedTimes]) + return Array.from(merged).sort((a, b) => a.localeCompare(b)) + } + + const fillTimePoints = (times: string[]) => { + if (times.length >= MAX_TREND_POINTS) return times + if (data.length === 0) return times + const lastTime = Math.max( + ...data.map((item) => Number(item.created_at) || 0) + ) + const padded = Array.from({ length: MAX_TREND_POINTS }, (_, i) => + formatChartTime( + lastTime - (MAX_TREND_POINTS - 1 - i) * intervalSec, + timeGranularity + ) ) - ) - return padded + return padded + } + return fillTimePoints(sortedTimes) } - const chartTimes = fillTimePoints(sortedTimes) + + const chartTimes = buildChartAxisTimes() const totalTimes = Array.from(modelTotalsMap.values()).reduce( (sum, x) => sum + (Number(x.count) || 0), diff --git a/web/default/src/features/dashboard/lib/filters.ts b/web/default/src/features/dashboard/lib/filters.ts index 6c4a1f01f3f2..5ce4669520f2 100644 --- a/web/default/src/features/dashboard/lib/filters.ts +++ b/web/default/src/features/dashboard/lib/filters.ts @@ -1,5 +1,5 @@ import type { TimeGranularity } from '@/lib/time' -import { getRollingDateRange } from '@/lib/time' +import { getCalendarDayRangeInclusive } from '@/lib/time' import { DASHBOARD_CHART_PREFERENCES_STORAGE_KEY, DEFAULT_DASHBOARD_CHART_PREFERENCES, @@ -128,7 +128,9 @@ export function getDefaultDays(granularity?: TimeGranularity): number { export function buildDefaultDashboardFilters( preferences: DashboardChartPreferences = getSavedChartPreferences() ): DashboardFilters { - const { start, end } = getRollingDateRange(preferences.defaultTimeRangeDays) + const { start, end } = getCalendarDayRangeInclusive( + preferences.defaultTimeRangeDays + ) return { ...EMPTY_DASHBOARD_FILTERS, start_timestamp: start, diff --git a/web/default/src/features/dashboard/lib/index.ts b/web/default/src/features/dashboard/lib/index.ts index bf9450212a17..8b47c0c6f4bb 100644 --- a/web/default/src/features/dashboard/lib/index.ts +++ b/web/default/src/features/dashboard/lib/index.ts @@ -14,6 +14,10 @@ export { openExternalSpeedTest, getDefaultPingStatus, } from './api-info' -export { processChartData, processUserChartData } from './charts' +export { + processChartData, + processUserChartData, + type ChartTimeRange, +} from './charts' export { safeDivide, calculateDashboardStats } from './stats' export { getPreviewText } from './text' diff --git a/web/default/src/features/docs/integration/components/doc-callout.tsx b/web/default/src/features/docs/integration/components/doc-callout.tsx new file mode 100644 index 000000000000..9099fd03ff65 --- /dev/null +++ b/web/default/src/features/docs/integration/components/doc-callout.tsx @@ -0,0 +1,33 @@ +import type { ReactNode } from 'react' +import { AlertTriangle, Info } from 'lucide-react' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { cn } from '@/lib/utils' + +type DocCalloutVariant = 'info' | 'warning' + +type DocCalloutProps = { + variant?: DocCalloutVariant + title: string + children: ReactNode + className?: string +} + +export function DocCallout(props: DocCalloutProps) { + const variant = props.variant ?? 'info' + const Icon = variant === 'warning' ? AlertTriangle : Info + + return ( + + + ) +} diff --git a/web/default/src/features/docs/integration/components/doc-code-block.tsx b/web/default/src/features/docs/integration/components/doc-code-block.tsx new file mode 100644 index 000000000000..17ddade1e086 --- /dev/null +++ b/web/default/src/features/docs/integration/components/doc-code-block.tsx @@ -0,0 +1,35 @@ +import { CopyButton } from '@/components/copy-button' +import { cn } from '@/lib/utils' + +type DocCodeBlockProps = { + code: string + language?: string + filename?: string + className?: string +} + +export function DocCodeBlock(props: DocCodeBlockProps) { + return ( +
+ {props.filename ? ( +
+ {props.filename} +
+ ) : null} + +
+        {props.code}
+      
+
+ ) +} diff --git a/web/default/src/features/docs/integration/components/doc-section.tsx b/web/default/src/features/docs/integration/components/doc-section.tsx new file mode 100644 index 000000000000..a28dfa3ec0fa --- /dev/null +++ b/web/default/src/features/docs/integration/components/doc-section.tsx @@ -0,0 +1,52 @@ +import type { ReactNode } from 'react' +import { cn } from '@/lib/utils' + +type DocStepListProps = { + steps: ReactNode[] + className?: string +} + +export function DocStepList(props: DocStepListProps) { + return ( +
    + {props.steps.map((step, index) => ( +
  1. + {step} +
  2. + ))} +
+ ) +} + +type DocSectionProps = { + title: string + children: ReactNode + id?: string +} + +export function DocSection(props: DocSectionProps) { + return ( +
+

+ {props.title} +

+
{props.children}
+
+ ) +} + +type DocPageHeaderProps = { + title: string + description: string +} + +export function DocPageHeader(props: DocPageHeaderProps) { + return ( +
+

{props.title}

+

+ {props.description} +

+
+ ) +} diff --git a/web/default/src/features/docs/integration/constants.ts b/web/default/src/features/docs/integration/constants.ts new file mode 100644 index 000000000000..2172087caab7 --- /dev/null +++ b/web/default/src/features/docs/integration/constants.ts @@ -0,0 +1,74 @@ +import type { LucideIcon } from 'lucide-react' +import { + Bot, + Code2, + Sparkles, + Terminal, + Workflow, + Wrench, +} from 'lucide-react' + +export const FACEAPI_BASE_URL = 'https://www.faceapi.ai' +export const FACEAPI_WEBSITE = 'https://www.faceapi.ai' +export const FACEAPI_BRAND = 'FaceCloud' + +export type IntegrationNavItem = { + id: string + path: string + titleKey: string + descriptionKey: string + icon: LucideIcon +} + +export const INTEGRATION_NAV_ITEMS: IntegrationNavItem[] = [ + { + id: 'claude-code', + path: '/docs/integration/claude-code', + titleKey: 'Claude Code', + descriptionKey: + 'Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.', + icon: Bot, + }, + { + id: 'codex', + path: '/docs/integration/codex', + titleKey: 'Codex', + descriptionKey: + 'Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.', + icon: Code2, + }, + { + id: 'gemini-cli', + path: '/docs/integration/gemini-cli', + titleKey: 'Gemini CLI', + descriptionKey: + 'Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.', + icon: Sparkles, + }, + { + id: 'open-code', + path: '/docs/integration/open-code', + titleKey: 'OpenCode', + descriptionKey: + 'Add FaceCloud as a custom provider in OpenCode configuration.', + icon: Workflow, + }, + { + id: 'trace', + path: '/docs/integration/trace', + titleKey: 'Trace (Trae IDE)', + descriptionKey: + 'Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.', + icon: Terminal, + }, + { + id: 'code-buddy', + path: '/docs/integration/code-buddy', + titleKey: 'Code Buddy', + descriptionKey: + 'Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.', + icon: Wrench, + }, +] + +export const INTEGRATION_HOME_PATH = '/docs/integration' diff --git a/web/default/src/features/docs/integration/index.tsx b/web/default/src/features/docs/integration/index.tsx new file mode 100644 index 000000000000..573a484fcac9 --- /dev/null +++ b/web/default/src/features/docs/integration/index.tsx @@ -0,0 +1,89 @@ +import { Link } from '@tanstack/react-router' +import { ArrowRight } from 'lucide-react' +import { useTranslation } from 'react-i18next' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { DocCallout } from './components/doc-callout' +import { + FACEAPI_BASE_URL, + FACEAPI_BRAND, + INTEGRATION_NAV_ITEMS, +} from './constants' + +export function IntegrationHome() { + const { t } = useTranslation() + + return ( +
+
+

+ {t('FaceCloud Integration Guides')} +

+

+ {t( + 'Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.' + )} +

+
+ + + {t('You need a FaceCloud API key. Create one in the dashboard, then replace')}{' '} + + sk-xxxx + {' '} + {t('in the examples below with your real key. API base URL:')}{' '} + + {FACEAPI_BASE_URL} + + + +
+ {INTEGRATION_NAV_ITEMS.map((item) => { + const Icon = item.icon + + return ( + + + +
+
+
+ {t(item.titleKey)} +
+ + {t(item.descriptionKey)} + +
+ + + {t('View guide')} + + + +
+ + ) + })} +
+ +

+ {t('Powered by')}{' '} + + {FACEAPI_BRAND} + + . {t('For model availability and pricing, visit the pricing page or dashboard.')} +

+
+ ) +} diff --git a/web/default/src/features/docs/integration/integration-layout.tsx b/web/default/src/features/docs/integration/integration-layout.tsx new file mode 100644 index 000000000000..d21a8f2f85af --- /dev/null +++ b/web/default/src/features/docs/integration/integration-layout.tsx @@ -0,0 +1,125 @@ +import { Link, Outlet, useRouterState } from '@tanstack/react-router' +import { Menu } from 'lucide-react' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { PublicLayout } from '@/components/layout' +import { Button } from '@/components/ui/button' +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetTrigger, +} from '@/components/ui/sheet' +import { cn } from '@/lib/utils' +import { + FACEAPI_BRAND, + FACEAPI_WEBSITE, + INTEGRATION_HOME_PATH, + INTEGRATION_NAV_ITEMS, +} from './constants' + +function IntegrationSidebar(props: { onNavigate?: () => void }) { + const { t } = useTranslation() + const routerState = useRouterState() + const pathname = routerState.location.pathname + + return ( + + ) +} + +export function IntegrationDocsShell() { + const { t } = useTranslation() + const [mobileOpen, setMobileOpen] = useState(false) + + return ( + +
+
+
+

{FACEAPI_BRAND}

+

{t('Integration')}

+
+ + + + + + + {t('Integration guides')} + +
+ setMobileOpen(false)} /> +
+
+
+
+
+ +
+
+ + +
+ +
+
+
+
+ ) +} diff --git a/web/default/src/features/docs/integration/pages/claude-code.tsx b/web/default/src/features/docs/integration/pages/claude-code.tsx new file mode 100644 index 000000000000..1d1315bfd121 --- /dev/null +++ b/web/default/src/features/docs/integration/pages/claude-code.tsx @@ -0,0 +1,105 @@ +import { useTranslation } from 'react-i18next' +import { DocCallout } from '../components/doc-callout' +import { DocCodeBlock } from '../components/doc-code-block' +import { DocPageHeader, DocSection, DocStepList } from '../components/doc-section' +import { FACEAPI_BASE_URL } from '../constants' + +const CLAUDE_SETTINGS = `{ + "env": { + "ANTHROPIC_BASE_URL": "${FACEAPI_BASE_URL}", + "ANTHROPIC_AUTH_TOKEN": "sk-xxxx", + "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1", + "CLAUDE_CODE_ATTRIBUTION_HEADER": "0" + } +}` + +export function ClaudeCodePage() { + const { t } = useTranslation() + + return ( +
+ + + + {t( + 'Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.' + )} + + + + + + + + +

+ {t('Create or edit')}{' '} + + ~/.claude/settings.json + + . +

+ , + <> +

{t('Add the following environment variables:')}

+ + , + <> +

+ {t('Replace')}{' '} + + sk-xxxx + {' '} + {t('with your FaceCloud API key.')} +

+ , +

{t('Run claude in a new terminal session to verify the connection.')}

, + ]} + /> +
+ + +
    +
  • + + ANTHROPIC_BASE_URL + {' '} + — {t('FaceCloud gateway URL')} +
  • +
  • + + ANTHROPIC_AUTH_TOKEN + {' '} + — {t('Your FaceCloud API key')} +
  • +
  • + + CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS + {' '} + — {t('Disables experimental beta headers for third-party gateways')} +
  • +
  • + + CLAUDE_CODE_ATTRIBUTION_HEADER + {' '} + — {t('Disables attribution header when using a proxy')} +
  • +
+
+
+ ) +} diff --git a/web/default/src/features/docs/integration/pages/code-buddy.tsx b/web/default/src/features/docs/integration/pages/code-buddy.tsx new file mode 100644 index 000000000000..38cd9ee2c3cb --- /dev/null +++ b/web/default/src/features/docs/integration/pages/code-buddy.tsx @@ -0,0 +1,90 @@ +import { useTranslation } from 'react-i18next' +import { DocCallout } from '../components/doc-callout' +import { DocCodeBlock } from '../components/doc-code-block' +import { DocPageHeader, DocSection, DocStepList } from '../components/doc-section' +import { FACEAPI_BASE_URL } from '../constants' + +const CODEBUDDY_SHELL = `export CODEBUDDY_API_KEY="sk-xxxx" +export CODEBUDDY_BASE_URL="${FACEAPI_BASE_URL}/v1" +codebuddy --model your-model-name` + +const CODEBUDDY_SETTINGS = `{ + "env": { + "CODEBUDDY_API_KEY": "sk-xxxx", + "CODEBUDDY_BASE_URL": "${FACEAPI_BASE_URL}/v1" + } +}` + +export function CodeBuddyPage() { + const { t } = useTranslation() + + return ( +
+ + + + {t( + 'CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.' + )} + + + + +

{t('Export the following variables in your terminal or shell profile:')}

+ + , + <> +

+ {t('Replace')}{' '} + + sk-xxxx + {' '} + {t('and your-model-name with your API key and desired model.')} +

+ , +

{t('Run codebuddy from the same shell session to use FaceCloud.')}

, + ]} + /> +
+ + +

+ {t( + 'If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:' + )} +

+ +
+ + +
    +
  • + + CODEBUDDY_API_KEY + {' '} + — {t('Your FaceCloud API key')} +
  • +
  • + + CODEBUDDY_BASE_URL + {' '} + — {t('OpenAI-compatible base URL at {{url}}', { + url: `${FACEAPI_BASE_URL}/v1`, + })} +
  • +
+
+
+ ) +} diff --git a/web/default/src/features/docs/integration/pages/codex.tsx b/web/default/src/features/docs/integration/pages/codex.tsx new file mode 100644 index 000000000000..1fe79ef8b226 --- /dev/null +++ b/web/default/src/features/docs/integration/pages/codex.tsx @@ -0,0 +1,90 @@ +import { useTranslation } from 'react-i18next' +import { DocCallout } from '../components/doc-callout' +import { DocCodeBlock } from '../components/doc-code-block' +import { DocPageHeader, DocSection, DocStepList } from '../components/doc-section' +import { FACEAPI_BASE_URL } from '../constants' + +const CODEX_CONFIG = `model = "o3" +model_provider = "openai-chat-completions" + +[model_providers.openai-chat-completions] +name = "FaceCloud" +base_url = "${FACEAPI_BASE_URL}/v1" +env_key = "FACEAPI_API_KEY" +wire_api = "chat"` + +const CODEX_ENV = `export FACEAPI_API_KEY="sk-xxxx"` + +export function CodexPage() { + const { t } = useTranslation() + + return ( +
+ + + + {t( + 'Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.' + )} + + + + +

+ {t('Reload your shell or run source on the file after exporting the variable.')} +

+
+ + + +

+ {t('Create or edit')}{' '} + + ~/.codex/config.toml + + . +

+ , + <> +

{t('Add the FaceCloud provider configuration:')}

+ + , +

+ {t('Start Codex and select the FaceCloud provider. Adjust model to one available on your account.')} +

, + ]} + /> +
+ + +
    +
  • + base_url —{' '} + {t('OpenAI-compatible endpoint at {{url}}', { + url: `${FACEAPI_BASE_URL}/v1`, + })} +
  • +
  • + env_key —{' '} + {t('Environment variable holding your API key')} +
  • +
  • + wire_api —{' '} + {t('Use chat completions wire format')} +
  • +
+
+
+ ) +} diff --git a/web/default/src/features/docs/integration/pages/gemini-cli.tsx b/web/default/src/features/docs/integration/pages/gemini-cli.tsx new file mode 100644 index 000000000000..45dfac626713 --- /dev/null +++ b/web/default/src/features/docs/integration/pages/gemini-cli.tsx @@ -0,0 +1,77 @@ +import { useTranslation } from 'react-i18next' +import { DocCallout } from '../components/doc-callout' +import { DocCodeBlock } from '../components/doc-code-block' +import { DocPageHeader, DocSection, DocStepList } from '../components/doc-section' +import { FACEAPI_BASE_URL } from '../constants' + +const GEMINI_ENV = `GOOGLE_GEMINI_BASE_URL=${FACEAPI_BASE_URL}/gemini +GEMINI_API_KEY=sk-xxxx +GEMINI_MODEL=gemini-2.5-flash` + +export function GeminiCliPage() { + const { t } = useTranslation() + + return ( +
+ + + + {t( + 'Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.' + )} + + + + +

+ {t('Create or edit')}{' '} + ~/.env{' '} + {t('in your home directory.')} +

+ , + <> +

{t('Add the following variables:')}

+ + , + <> +

+ {t('Replace')}{' '} + + sk-xxxx + {' '} + {t('with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.')} +

+ , +

{t('Run the Gemini CLI and send a test prompt to confirm connectivity.')}

, + ]} + /> +
+ + +
    +
  • + + GOOGLE_GEMINI_BASE_URL + {' '} + — {t('FaceCloud Gemini-compatible base URL')} +
  • +
  • + GEMINI_API_KEY —{' '} + {t('Your FaceCloud API key')} +
  • +
  • + GEMINI_MODEL —{' '} + {t('Default model name for requests')} +
  • +
+
+
+ ) +} diff --git a/web/default/src/features/docs/integration/pages/open-code.tsx b/web/default/src/features/docs/integration/pages/open-code.tsx new file mode 100644 index 000000000000..54e25fdf13e3 --- /dev/null +++ b/web/default/src/features/docs/integration/pages/open-code.tsx @@ -0,0 +1,81 @@ +import { useTranslation } from 'react-i18next' +import { DocCallout } from '../components/doc-callout' +import { DocCodeBlock } from '../components/doc-code-block' +import { DocPageHeader, DocSection, DocStepList } from '../components/doc-section' +import { FACEAPI_BASE_URL } from '../constants' + +const OPENCODE_CONFIG = `{ + "providers": { + "facecloud": { + "baseURL": "${FACEAPI_BASE_URL}/v1", + "apiKey": "sk-xxxx" + } + }, + "defaultProvider": "facecloud" +}` + +export function OpenCodePage() { + const { t } = useTranslation() + + return ( +
+ + + + {t( + 'OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.' + )} + + + + +

+ {t('Create the config directory if it does not exist:')}{' '} + + ~/.config/opencode/ + +

+ , + <> +

{t('Edit opencode.json with the FaceCloud provider:')}

+ + , + <> +

+ {t('Replace')}{' '} + + sk-xxxx + {' '} + {t('with your FaceCloud API key.')} +

+ , +

{t('Launch OpenCode and verify that requests route through FaceCloud.')}

, + ]} + /> +
+ + +

+ {t( + 'Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.' + )} +

+ +
+
+ ) +} diff --git a/web/default/src/features/docs/integration/pages/trace.tsx b/web/default/src/features/docs/integration/pages/trace.tsx new file mode 100644 index 000000000000..f838ae931c18 --- /dev/null +++ b/web/default/src/features/docs/integration/pages/trace.tsx @@ -0,0 +1,96 @@ +import { useTranslation } from 'react-i18next' +import { DocCallout } from '../components/doc-callout' +import { DocCodeBlock } from '../components/doc-code-block' +import { DocPageHeader, DocSection, DocStepList } from '../components/doc-section' +import { FACEAPI_BASE_URL } from '../constants' + +const OPENAI_ENDPOINT = `${FACEAPI_BASE_URL}/v1/chat/completions` +const ANTHROPIC_ENDPOINT = `${FACEAPI_BASE_URL}/v1/messages` + +export function TracePage() { + const { t } = useTranslation() + + return ( +
+ + + + {t( + 'Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.' + )} + + + + + {t('Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.')} +

, + <> +

{t('For OpenAI-compatible models, set the request URL to:')}

+ + , + <> +

+ {t('Set the API key to your FaceCloud key (')}{' '} + sk-xxxx + {t(') and choose a model name available on your account.')} +

+ , + ]} + /> +
+ + + + {t('Add a custom Anthropic provider or Claude model in Trae settings.')} +

, + <> +

{t('Set the messages endpoint to:')}

+ + , +

+ {t('Use Bearer authentication with your FaceCloud API key in the Authorization header.')} +

, + ]} + /> +
+ + +
+
+ + + + + + + + + + + + + + + + +
{t('Provider')}{t('Full endpoint URL')}
OpenAI{OPENAI_ENDPOINT}
Anthropic{ANTHROPIC_ENDPOINT}
+ +
+ + + {t( + 'If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.' + )} + +
+ ) +} diff --git a/web/default/src/features/playground/constants.ts b/web/default/src/features/playground/constants.ts index 3787a261dfd2..402f97b53d7a 100644 --- a/web/default/src/features/playground/constants.ts +++ b/web/default/src/features/playground/constants.ts @@ -38,8 +38,8 @@ export const DEFAULT_CONFIG: PlaygroundConfig = { } export const DEFAULT_PARAMETER_ENABLED: ParameterEnabled = { - temperature: true, - top_p: true, + temperature: false, + top_p: false, max_tokens: false, frequency_penalty: true, presence_penalty: true, diff --git a/web/default/src/features/playground/hooks/use-playground-state.ts b/web/default/src/features/playground/hooks/use-playground-state.ts index c90ae95587bd..a63627e15bd8 100644 --- a/web/default/src/features/playground/hooks/use-playground-state.ts +++ b/web/default/src/features/playground/hooks/use-playground-state.ts @@ -7,6 +7,8 @@ import { saveParameterEnabled, loadMessages, saveMessages, + applyParameterEnabledUpdate, + normalizeSamplingParameters, } from '../lib' import type { Message, @@ -29,7 +31,10 @@ export function usePlaygroundState() { const [parameterEnabled, setParameterEnabled] = useState( () => { const saved = loadParameterEnabled() - return { ...DEFAULT_PARAMETER_ENABLED, ...saved } + return normalizeSamplingParameters({ + ...DEFAULT_PARAMETER_ENABLED, + ...saved, + }) } ) @@ -56,7 +61,7 @@ export function usePlaygroundState() { const updateParameterEnabled = useCallback( (key: keyof ParameterEnabled, value: boolean) => { setParameterEnabled((prev) => { - const updated = { ...prev, [key]: value } + const updated = applyParameterEnabledUpdate(prev, key, value) saveParameterEnabled(updated) return updated }) diff --git a/web/default/src/features/playground/lib/index.ts b/web/default/src/features/playground/lib/index.ts index 1247e1bd8e2d..e727c33305af 100644 --- a/web/default/src/features/playground/lib/index.ts +++ b/web/default/src/features/playground/lib/index.ts @@ -1,4 +1,5 @@ export * from './message-utils' +export * from './parameter-enabled' export * from './payload-builder' export * from './storage' export * from './message-styles' diff --git a/web/default/src/features/playground/lib/parameter-enabled.ts b/web/default/src/features/playground/lib/parameter-enabled.ts new file mode 100644 index 000000000000..fb39c99e46d7 --- /dev/null +++ b/web/default/src/features/playground/lib/parameter-enabled.ts @@ -0,0 +1,32 @@ +import type { ParameterEnabled } from '../types' + +/** Temperature and top_p cannot both be enabled. */ +export function normalizeSamplingParameters( + enabled: ParameterEnabled +): ParameterEnabled { + if (enabled.temperature && enabled.top_p) { + return { ...enabled, top_p: false } + } + return enabled +} + +export function applyParameterEnabledUpdate( + prev: ParameterEnabled, + key: keyof ParameterEnabled, + value: boolean +): ParameterEnabled { + const updated = { ...prev, [key]: value } + if (value && key === 'temperature') { + updated.top_p = false + } else if (value && key === 'top_p') { + updated.temperature = false + } + return normalizeSamplingParameters(updated) +} + +export function toggleParameterEnabled( + prev: ParameterEnabled, + key: keyof ParameterEnabled +): ParameterEnabled { + return applyParameterEnabledUpdate(prev, key, !prev[key]) +} diff --git a/web/default/src/features/usage-logs/api.ts b/web/default/src/features/usage-logs/api.ts index 550384908959..d9b6a67c0343 100644 --- a/web/default/src/features/usage-logs/api.ts +++ b/web/default/src/features/usage-logs/api.ts @@ -91,3 +91,5 @@ export const getAllTaskLogs = (params: GetTaskLogsParams) => export const getUserTaskLogs = (params: GetTaskLogsParams) => fetchLogs('/api/task', params, false) + +export { downloadUsageLogsExport } from './lib/export' diff --git a/web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx b/web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx index b48c180faf65..5b30d289b60f 100644 --- a/web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx +++ b/web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx @@ -1,7 +1,16 @@ import { useState, useEffect, useCallback, type ReactNode } from 'react' import { useNavigate, getRouteApi } from '@tanstack/react-router' import { useQueryClient, useIsFetching } from '@tanstack/react-query' -import { ChevronDown, Eye, EyeOff, Loader2, RotateCcw, Search } from 'lucide-react' +import { + ChevronDown, + Download, + Eye, + EyeOff, + Loader2, + RotateCcw, + Search, +} from 'lucide-react' +import { toast } from 'sonner' import { useTranslation } from 'react-i18next' import { cn } from '@/lib/utils' import { useIsAdmin } from '@/hooks/use-admin' @@ -15,8 +24,9 @@ import { SelectValue, } from '@/components/ui/select' import { LOG_TYPES } from '../constants' +import { downloadUsageLogsExport } from '../api' import { buildSearchParams } from '../lib/filter' -import { getDefaultTimeRange } from '../lib/utils' +import { buildApiParams, getDefaultTimeRange } from '../lib/utils' import type { CommonLogFilters } from '../types' import { CompactDateTimeRangePicker } from './compact-date-time-range-picker' import { useUsageLogsContext } from './usage-logs-provider' @@ -53,6 +63,7 @@ export function CommonLogsFilterBar({ return { startTime: start, endTime: end } }) const [logType, setLogType] = useState('') + const [exporting, setExporting] = useState(false) useEffect(() => { const next: Partial = {} @@ -134,6 +145,32 @@ export function CommonLogsFilterBar({ [handleApply] ) + const handleExport = useCallback(async () => { + setExporting(true) + try { + const filterParams = buildSearchParams(filters, 'common') + const apiParams = buildApiParams({ + page: 1, + pageSize: 1, + searchParams: { + ...filterParams, + ...(logType ? { type: [logType] } : {}), + }, + columnFilters: [], + isAdmin, + }) + const { p: _p, page_size: _ps, ...exportParams } = apiParams + await downloadUsageLogsExport(exportParams, isAdmin) + toast.success(t('Export completed')) + } catch (error) { + toast.error( + error instanceof Error ? error.message : t('Export failed') + ) + } finally { + setExporting(false) + } + }, [filters, isAdmin, logType, t]) + const hasExpandedFilters = !!filters.token || !!filters.username || @@ -282,6 +319,20 @@ export function CommonLogsFilterBar({ {t('Reset')} + + + + + + + ) +} diff --git a/web/default/src/hooks/use-top-nav-links.ts b/web/default/src/hooks/use-top-nav-links.ts index 75380fbbded8..073f744f6eb1 100644 --- a/web/default/src/hooks/use-top-nav-links.ts +++ b/web/default/src/hooks/use-top-nav-links.ts @@ -1,5 +1,6 @@ import { useMemo } from 'react' import { useTranslation } from 'react-i18next' +import { resolveDocsNavLink } from '@/lib/docs-nav-link' import { useAuthStore } from '@/stores/auth-store' import { useStatus } from '@/hooks/use-status' @@ -52,6 +53,7 @@ export function useTopNavLinks(): TopNavLink[] { // Documentation link (may be external) const docsLink: string | undefined = status?.docs_link as string | undefined + const serverAddress = status?.server_address as string | undefined const isAuthed = !!auth?.user @@ -74,10 +76,15 @@ export function useTopNavLinks(): TopNavLink[] { links.push({ title: t('Model Square'), href: '/pricing', disabled }) } - // Docs (supports external links) + // Docs (supports external links; same-site URLs stay in-app) if (modules?.docs !== false) { if (docsLink) { - links.push({ title: t('Docs'), href: docsLink, external: true }) + const resolved = resolveDocsNavLink(docsLink, serverAddress) + links.push({ + title: t('Docs'), + href: resolved.href, + external: resolved.external, + }) } else { links.push({ title: t('Docs'), href: '/docs' }) } diff --git a/web/default/src/i18n/locales/_reports/_sync-report.json b/web/default/src/i18n/locales/_reports/_sync-report.json index 9596d7c4c613..fc961a39d9e6 100644 --- a/web/default/src/i18n/locales/_reports/_sync-report.json +++ b/web/default/src/i18n/locales/_reports/_sync-report.json @@ -9,33 +9,33 @@ }, "fr": { "file": "fr.json", - "missingCount": 0, + "missingCount": 85, "extrasCount": 0, - "untranslatedCount": 0 + "untranslatedCount": 45 }, "ja": { "file": "ja.json", - "missingCount": 0, + "missingCount": 85, "extrasCount": 0, - "untranslatedCount": 85 + "untranslatedCount": 178 }, "ru": { "file": "ru.json", - "missingCount": 0, + "missingCount": 85, "extrasCount": 0, - "untranslatedCount": 89 + "untranslatedCount": 182 }, "vi": { "file": "vi.json", - "missingCount": 0, + "missingCount": 85, "extrasCount": 0, - "untranslatedCount": 0 + "untranslatedCount": 45 }, "zh": { "file": "zh.json", "missingCount": 0, "extrasCount": 0, - "untranslatedCount": 96 + "untranslatedCount": 98 } } } diff --git a/web/default/src/i18n/locales/_reports/fr.untranslated.json b/web/default/src/i18n/locales/_reports/fr.untranslated.json index 0bae8f23c71c..23c2409d1398 100644 --- a/web/default/src/i18n/locales/_reports/fr.untranslated.json +++ b/web/default/src/i18n/locales/_reports/fr.untranslated.json @@ -1,5 +1,47 @@ { - "Go to Settings": "Go to Settings", - "Failed to adjust quota": "Failed to adjust quota", - "Select an operation mode and enter the amount": "Select an operation mode and enter the amount" + ") and choose a model name available on your account.": ") and choose a model name available on your account.", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Failed to load consumption": "Failed to load consumption", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace" } diff --git a/web/default/src/i18n/locales/_reports/ja.untranslated.json b/web/default/src/i18n/locales/_reports/ja.untranslated.json index cf803a766e96..815df181b09f 100644 --- a/web/default/src/i18n/locales/_reports/ja.untranslated.json +++ b/web/default/src/i18n/locales/_reports/ja.untranslated.json @@ -1,26 +1,75 @@ { + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "/status/": "/status/", "/your/endpoint": "/your/endpoint", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AIGC2D": "AIGC2D", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "API URL": "API URL", "API2GPT": "API2GPT", + "Apply user filter": "Apply user filter", "AZURE_OPENAI_ENDPOINT *": "AZURE_OPENAI_ENDPOINT *", + "Before you start": "Before you start", + "Channel Consumption": "Channel Consumption", "checkout.session.completed": "checkout.session.completed", "checkout.session.expired": "checkout.session.expired", "Claude": "Claude", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", + "Clear user filter": "Clear user filter", "Cloudflare": "Cloudflare", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", + "Configuration reference": "Configuration reference", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "DeepSeek": "DeepSeek", + "Default model name for requests": "Default model name for requests", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "DoubaoVideo": "DoubaoVideo", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", "edit_this": "edit_this", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", + "Export completed": "Export completed", + "Export logs": "Export logs", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", + "Failed to load consumption": "Failed to load consumption", "FastGPT": "FastGPT", + "Filter by user (optional)": "Filter by user (optional)", "footer.columns.related.links.midjourney": "Midjourney-Proxy", "footer.columns.related.links.neko": "neko-api-key-tool", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "GitHub": "GitHub", "gpt-3.5-turbo": "gpt-3.5-turbo", @@ -45,10 +94,23 @@ "https://wechat-server.example.com": "https://wechat-server.example.com", "https://worker.example.workers.dev": "https://worker.example.workers.dev", "https://your-server.example.com": "https://your-server.example.com", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "Jimeng": "Jimeng", "JustSong": "JustSong", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", + "Lifetime channel usage": "Lifetime channel usage", "LingYiWanWu": "LingYiWanWu", "LinuxDO": "LinuxDO", + "Manual configuration": "Manual configuration", "Midjourney": "Midjourney", "MidjourneyPlus": "MidjourneyPlus", "MiniMax": "MiniMax", @@ -61,27 +123,58 @@ "noreply@example.com": "noreply@example.com", "OhMyGPT": "OhMyGPT", "Ollama": "Ollama", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "OpenRouter": "OpenRouter", "org-...": "org-...", "Passkey": "Passkey", "Perplexity": "Perplexity", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", + "Powered by": "Powered by", "price_xxx": "price_xxx", "QuantumNous": "QuantumNous", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Replicate": "Replicate", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "SiliconFlow": "SiliconFlow", "smtp.example.com": "smtp.example.com", "socks5://user:pass@host:port": "socks5://user:pass@host:port", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Stripe": "Stripe", "Submodel": "Submodel", "SunoAPI": "SunoAPI", "Telegram": "Telegram", + "Total requests": "Total requests", + "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Vertex AI": "Vertex AI", + "View guide": "View guide", "VolcEngine": "VolcEngine", "Webhook URL": "Webhook URL", "Webhook URL:": "Webhook URL:", "whsec_xxx": "whsec_xxx", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Xinference": "Xinference", - "Xunfei": "Xunfei" + "Xunfei": "Xunfei", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key" } diff --git a/web/default/src/i18n/locales/_reports/ru.untranslated.json b/web/default/src/i18n/locales/_reports/ru.untranslated.json index 20c9dc77ad8f..c29c10e3fdb2 100644 --- a/web/default/src/i18n/locales/_reports/ru.untranslated.json +++ b/web/default/src/i18n/locales/_reports/ru.untranslated.json @@ -1,30 +1,79 @@ { "\"default\": \"us-central1\", \"claude-3-5-sonnet-20240620\": \"europe-west1\"": "\"default\": \"us-central1\", \"claude-3-5-sonnet-20240620\": \"europe-west1\"", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\"original-model\": \"replacement-model\"}", "/status/": "/status/", "/your/endpoint": "/your/endpoint", "AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "AI Proxy": "AI Proxy", "AIGC2D": "AIGC2D", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "API2GPT": "API2GPT", + "Apply user filter": "Apply user filter", "AZURE_OPENAI_ENDPOINT *": "AZURE_OPENAI_ENDPOINT *", "Baidu V2": "Baidu V2", + "Before you start": "Before you start", + "Channel Consumption": "Channel Consumption", "checkout.session.completed": "checkout.session.completed", "checkout.session.expired": "checkout.session.expired", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", + "Clear user filter": "Clear user filter", "Cloudflare": "Cloudflare", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", + "Configuration reference": "Configuration reference", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", + "Configure environment": "Configure environment", + "Configure FaceCloud": "Configure FaceCloud", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "DeepSeek": "DeepSeek", + "Default model name for requests": "Default model name for requests", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Discord": "Discord", "DoubaoVideo": "DoubaoVideo", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Endpoint reference": "Endpoint reference", + "Environment variable holding your API key": "Environment variable holding your API key", "example.com blocked-site.com": "example.com blocked-site.com", "example.com company.com": "example.com company.com", + "Export completed": "Export completed", + "Export logs": "Export logs", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", + "Failed to load consumption": "Failed to load consumption", "FastGPT": "FastGPT", + "Filter by user (optional)": "Filter by user (optional)", "footer.columns.related.links.midjourney": "Midjourney-Proxy", "footer.columns.related.links.neko": "neko-api-key-tool", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "Full endpoint URL": "Full endpoint URL", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "GitHub": "GitHub", "gpt-3.5-turbo": "gpt-3.5-turbo", @@ -49,10 +98,23 @@ "https://wechat-server.example.com": "https://wechat-server.example.com", "https://worker.example.workers.dev": "https://worker.example.workers.dev", "https://your-server.example.com": "https://your-server.example.com", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "Important": "Important", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", + "Install Claude Code": "Install Claude Code", + "Integration": "Integration", + "Integration guides": "Integration guides", + "Interactive login": "Interactive login", "Jimeng": "Jimeng", "JustSong": "JustSong", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", + "Lifetime channel usage": "Lifetime channel usage", "LingYiWanWu": "LingYiWanWu", "LinuxDO": "LinuxDO", + "Manual configuration": "Manual configuration", "Midjourney": "Midjourney", "MidjourneyPlus": "MidjourneyPlus", "MiniMax": "MiniMax", @@ -65,27 +127,58 @@ "OAuth Client Secret": "OAuth Client Secret", "OhMyGPT": "OhMyGPT", "Ollama": "Ollama", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "OpenRouter": "OpenRouter", "Passkey": "Passkey", "Perplexity": "Perplexity", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", + "Powered by": "Powered by", "price_xxx": "price_xxx", "QuantumNous": "QuantumNous", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Replicate": "Replicate", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Set your API key": "Set your API key", + "settings.json (optional)": "settings.json (optional)", + "Shell environment": "Shell environment", "SiliconFlow": "SiliconFlow", "smtp.example.com": "smtp.example.com", "socks5://user:pass@host:port": "socks5://user:pass@host:port", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Stripe": "Stripe", "Submodel": "Submodel", "SunoAPI": "SunoAPI", "Telegram": "Telegram", "Tencent": "Tencent", + "Total requests": "Total requests", + "Total tokens": "Total tokens", + "Trace (Trae IDE)": "Trace (Trae IDE)", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Vertex AI": "Vertex AI", + "View guide": "View guide", "VolcEngine": "VolcEngine", "WeChat": "WeChat", "whsec_xxx": "whsec_xxx", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Xinference": "Xinference", "Xunfei": "Xunfei", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", + "Your FaceCloud API key": "Your FaceCloud API key", "Zhipu V4": "Zhipu V4" } diff --git a/web/default/src/i18n/locales/_reports/vi.untranslated.json b/web/default/src/i18n/locales/_reports/vi.untranslated.json index 0bae8f23c71c..23c2409d1398 100644 --- a/web/default/src/i18n/locales/_reports/vi.untranslated.json +++ b/web/default/src/i18n/locales/_reports/vi.untranslated.json @@ -1,5 +1,47 @@ { - "Go to Settings": "Go to Settings", - "Failed to adjust quota": "Failed to adjust quota", - "Select an operation mode and enter the amount": "Select an operation mode and enter the amount" + ") and choose a model name available on your account.": ") and choose a model name available on your account.", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", + "Create or edit": "Create or edit", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Failed to load consumption": "Failed to load consumption", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the messages endpoint to:": "Set the messages endpoint to:", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace" } diff --git a/web/default/src/i18n/locales/_reports/zh.untranslated.json b/web/default/src/i18n/locales/_reports/zh.untranslated.json index 78ee1e36a823..e1863601ec85 100644 --- a/web/default/src/i18n/locales/_reports/zh.untranslated.json +++ b/web/default/src/i18n/locales/_reports/zh.untranslated.json @@ -14,9 +14,11 @@ "checkout.session.completed": "checkout.session.completed", "checkout.session.expired": "checkout.session.expired", "Claude": "Claude", + "Claude Code": "Claude Code", "Client ID": "Client ID", "Client Secret": "Client Secret", "Cloudflare": "Cloudflare", + "Code Buddy": "Code Buddy", "Cohere": "Cohere", "DeepSeek": "DeepSeek", "Discord": "Discord", diff --git a/web/default/src/i18n/locales/en.json b/web/default/src/i18n/locales/en.json index eaf3e23121ff..d25689fe63bb 100644 --- a/web/default/src/i18n/locales/en.json +++ b/web/default/src/i18n/locales/en.json @@ -15,6 +15,7 @@ "(Optional: redirect model names)": "(Optional: redirect model names)", "(Override all channels' groups)": "(Override all channels' groups)", "(Override all channels' models)": "(Override all channels' models)", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\"original-model\": \"replacement-model\"}", @@ -109,6 +110,7 @@ "Actual Model:": "Actual Model:", "Add": "Add", "Add {{title}}": "Add {{title}}", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", "Add a group identifier to the auto assignment list.": "Add a group identifier to the auto assignment list.", "Add a new API key by providing necessary info.": "Add a new API key by providing necessary info.", "Add a new channel by providing the necessary information.": "Add a new channel by providing the necessary information.", @@ -127,6 +129,8 @@ "Add custom model(s), comma-separated": "Add custom model(s), comma-separated", "Add discount tier": "Add discount tier", "Add each model or tag you want to include.": "Add each model or tag you want to include.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", "Add FAQ": "Add FAQ", "Add from available models...": "Add from available models...", "Add Funds": "Add Funds", @@ -156,6 +160,9 @@ "Add selectable group": "Add selectable group", "Add subscription": "Add subscription", "Add tags...": "Add tags...", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "Add tier": "Add tier", "Add time condition": "Add time condition", "Add time rule group": "Add time rule group", @@ -256,6 +263,7 @@ "Allowed Origins": "Allowed Origins", "Allowed Ports": "Allowed Ports", "Already have an account?": "Already have an account?", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", "Always matches (default tier).": "Always matches (default tier).", "Amount": "Amount", "Amount cannot be changed when editing.": "Amount cannot be changed when editing.", @@ -268,6 +276,7 @@ "Amount to pay:": "Amount to pay:", "An unexpected error occurred": "An unexpected error occurred", "and": "and", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Announcement added. Click \"Save Settings\" to apply.": "Announcement added. Click \"Save Settings\" to apply.", "Announcement content": "Announcement content", "Announcement deleted. Click \"Save Settings\" to apply.": "Announcement deleted. Click \"Save Settings\" to apply.", @@ -278,6 +287,7 @@ "Announcements saved successfully": "Announcements saved successfully", "Answer": "Answer", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "Any Match (OR)": "Any Match (OR)", "API Access": "API Access", "API Addresses": "API Addresses", @@ -327,6 +337,7 @@ "Apply IP Filter to Resolved Domains": "Apply IP Filter to Resolved Domains", "Apply Overwrite": "Apply Overwrite", "Apply Sync": "Apply Sync", + "Apply user filter": "Apply user filter", "Applying...": "Applying...", "Approx.": "Approx.", "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.": "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.", @@ -428,6 +439,7 @@ "Base amount. Actual deduction = base amount × system group rate.": "Base amount. Actual deduction = base amount × system group rate.", "Base Limits": "Base Limits", "Base multipliers applied when users select specific groups.": "Base multipliers applied when users select specific groups.", + "Base Price": "Base Price", "Base rate limit windows for this account.": "Base rate limit windows for this account.", "Base URL": "Base URL", "Base URL of your Uptime Kuma instance": "Base URL of your Uptime Kuma instance", @@ -447,6 +459,7 @@ "Batch enable failed": "Batch enable failed", "Batch processing failed": "Batch processing failed", "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed", + "Before you start": "Before you start", "Best for single-tenant deployments. Pricing and billing options stay hidden.": "Best for single-tenant deployments. Pricing and billing options stay hidden.", "Billing": "Billing", "Billing currency": "Billing currency", @@ -485,7 +498,6 @@ "Broadcast a global banner to users. Markdown is supported.": "Broadcast a global banner to users. Markdown is supported.", "Broadcast short system notices on the dashboard": "Broadcast short system notices on the dashboard", "Browse and compare": "Browse and compare", - "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.": "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.": "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.", "Budget Tokens Ratio": "Budget Tokens Ratio", @@ -544,6 +556,7 @@ "Channel Affinity": "Channel Affinity", "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.", "Channel Affinity: Upstream Cache Hit": "Channel Affinity: Upstream Cache Hit", + "Channel Consumption": "Channel Consumption", "Channel copied successfully": "Channel copied successfully", "Channel created successfully": "Channel created successfully", "Channel deleted successfully": "Channel deleted successfully", @@ -608,6 +621,8 @@ "Classic (Legacy Frontend)": "Classic (Legacy Frontend)", "Claude": "Claude", "Claude CLI Header Passthrough": "Claude CLI Header Passthrough", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Clean history logs": "Clean history logs", "Clean logs": "Clean logs", "Clean up inactive cache": "Clean up inactive cache", @@ -628,6 +643,7 @@ "Clear search": "Clear search", "Clear selection": "Clear selection", "Clear selection (Escape)": "Clear selection (Escape)", + "Clear user filter": "Clear user filter", "Cleared": "Cleared", "Cleared all models": "Cleared all models", "Click \"Create Plan\" to create your first subscription plan": "Click \"Create Plan\" to create your first subscription plan", @@ -655,12 +671,15 @@ "CNY": "CNY", "CNY per USD": "CNY per USD", "Code": "Code", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", "Codes copied!": "Codes copied!", "Codex": "Codex", "Codex Account & Usage": "Codex Account & Usage", "Codex Authorization": "Codex Authorization", "Codex channels use an OAuth JSON credential as the key.": "Codex channels use an OAuth JSON credential as the key.", "Codex CLI Header Passthrough": "Codex CLI Header Passthrough", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", "Collapse": "Collapse", "Collapse All": "Collapse All", @@ -701,6 +720,7 @@ "Configuration for Creem payment integration": "Configuration for Creem payment integration", "Configuration for Epay payment integration": "Configuration for Epay payment integration", "Configuration for Stripe payment integration": "Configuration for Stripe payment integration", + "Configuration reference": "Configuration reference", "Configuration required": "Configuration required", "Configure": "Configure", "Configure a Creem product for user recharge options.": "Configure a Creem product for user recharge options.", @@ -715,17 +735,22 @@ "Configure available payment methods. Provide a JSON array.": "Configure available payment methods. Provide a JSON array.", "Configure basic system information and branding": "Configure basic system information and branding", "Configure channel affinity (sticky routing) rules": "Configure channel affinity (sticky routing) rules", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", "Configure Creem products. Provide a JSON array.": "Configure Creem products. Provide a JSON array.", "Configure custom OAuth providers for user authentication": "Configure custom OAuth providers for user authentication", "Configure daily check-in rewards for users": "Configure daily check-in rewards for users", "Configure discount rates based on recharge amounts": "Configure discount rates based on recharge amounts", + "Configure environment": "Configure environment", "Configure experimental data export for the dashboard": "Configure experimental data export for the dashboard", + "Configure FaceCloud": "Configure FaceCloud", "Configure Gemini safety behavior, version overrides, and thinking adapter": "Configure Gemini safety behavior, version overrides, and thinking adapter", "Configure in your Creem dashboard": "Configure in your Creem dashboard", "Configure io.net API key for model deployments": "Configure io.net API key for model deployments", "Configure keyword filtering for prompts and responses.": "Configure keyword filtering for prompts and responses.", "Configure model, caching, and group ratios used for billing": "Configure model, caching, and group ratios used for billing", "Configure monitoring status page groups for the dashboard": "Configure monitoring status page groups for the dashboard", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", "Configure outgoing email server for notifications": "Configure outgoing email server for notifications", "Configure Passkey (WebAuthn) login settings": "Configure Passkey (WebAuthn) login settings", "Configure password-based login and registration": "Configure password-based login and registration", @@ -739,6 +764,8 @@ "Configure system-wide behavior and defaults": "Configure system-wide behavior and defaults", "Configure the ratio for this group.": "Configure the ratio for this group.", "Configure third-party authentication providers": "Configure third-party authentication providers", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", "Configure upstream providers and routing.": "Configure upstream providers and routing.", "Configure upstream worker or proxy service for outbound requests": "Configure upstream worker or proxy service for outbound requests", "Configure user quota allocation and rewards": "Configure user quota allocation and rewards", @@ -774,6 +801,8 @@ "Confirm your identity with Two-factor Authentication before registering a Passkey.": "Confirm your identity with Two-factor Authentication before registering a Passkey.", "Conflict": "Conflict", "Connect": "Connect", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", "Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Connect through OpenAI, Claude, Gemini, and other compatible API routes", "Connected to io.net service normally.": "Connected to io.net service normally.", "Connection error": "Connection error", @@ -871,6 +900,7 @@ "Create multiple channels from multiple keys": "Create multiple channels from multiple keys", "Create multiple redemption codes at once (1-100)": "Create multiple redemption codes at once (1-100)", "Create new subscription plan": "Create New Subscription Plan", + "Create or edit": "Create or edit", "Create or update frequently asked questions for users": "Create or update frequently asked questions for users", "Create or update system announcements for the dashboard": "Create or update system announcements for the dashboard", "Create Plan": "Create Plan", @@ -881,6 +911,7 @@ "Create request parameter override rules without editing raw JSON.": "Create request parameter override rules without editing raw JSON.", "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.": "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.", "Create succeeded": "Create succeeded", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Create Vendor": "Create Vendor", "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.", "Create, revoke, and audit API tokens.": "Create, revoke, and audit API tokens.", @@ -962,6 +993,7 @@ "Default consumption chart": "Default consumption chart", "Default Max Tokens": "Default Max Tokens", "Default model call chart": "Default model call chart", + "Default model name for requests": "Default model name for requests", "Default range": "Default range", "Default Responses API version, if empty, will use the API version above": "Default Responses API version, if empty, will use the API version above", "Default system prompt for this channel": "Default system prompt for this channel", @@ -1059,6 +1091,8 @@ "Disabled all channels with tag: {{tag}}": "Disabled all channels with tag: {{tag}}", "Disabled Reason": "Disabled Reason", "Disabled Time": "Disabled Time", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Disabling...": "Disabling...", "Discord": "Discord", "Discount": "Discount", @@ -1069,6 +1103,7 @@ "Discount Rate:": "Discount Rate:", "Discount ratio for cache hits.": "Discount ratio for cache hits.", "Discouraged": "Discouraged", + "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.", "Discovering...": "Discovering...", "Disk cache cleared": "Disk cache cleared", "Disk Cache Settings": "Disk Cache Settings", @@ -1106,6 +1141,7 @@ "DoubaoVideo": "DoubaoVideo", "Double check the configuration below. Your system will be locked until initialization is complete.": "Double check the configuration below. Your system will be locked until initialization is complete.", "Download": "Download", + "Download started": "Download started", "Draw": "Draw", "Drawing": "Drawing", "Drawing logs": "Drawing logs", @@ -1121,6 +1157,7 @@ "e.g. ¥ or HK$": "e.g. ¥ or HK$", "e.g. 401, 403, 429, 500-599": "e.g. 401, 403, 429, 500-599", "e.g. 8 means 1 USD = 8 units": "e.g. 8 means 1 USD = 8 units", + "e.g. Asia/Shanghai": "e.g. Asia/Shanghai", "e.g. Basic Plan": "e.g. Basic Plan", "e.g. Clean tool parameters to avoid upstream validation errors": "e.g. Clean tool parameters to avoid upstream validation errors", "e.g. example.com": "e.g. example.com", @@ -1179,6 +1216,7 @@ "Edit model": "Edit model", "Edit Model": "Edit Model", "Edit OAuth Provider": "Edit OAuth Provider", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", "Edit payment method": "Edit payment method", "Edit Prefill Group": "Edit Prefill Group", "Edit product": "Edit product", @@ -1254,6 +1292,7 @@ "Endpoint": "Endpoint", "Endpoint config": "Endpoint config", "Endpoint Configuration": "Endpoint Configuration", + "Endpoint reference": "Endpoint reference", "Endpoint Type": "Endpoint Type", "Endpoint:": "Endpoint:", "Endpoints": "Endpoints", @@ -1333,6 +1372,7 @@ "Enterprise-grade security with comprehensive permission management": "Enterprise-grade security with comprehensive permission management", "Entrypoint (space separated)": "Entrypoint (space separated)", "Env (JSON object)": "Env (JSON object)", + "Environment variable holding your API key": "Environment variable holding your API key", "Environment variables": "Environment variables", "Environment variables (JSON)": "Environment variables (JSON)", "Epay endpoint": "Epay endpoint", @@ -1371,6 +1411,15 @@ "Expired at": "Expired at", "Expired time cannot be earlier than current time": "Expired time cannot be earlier than current time", "Expires": "Expires", + "Export completed": "Export completed", + "Export consumption details": "Export consumption details", + "Export failed": "Export failed", + "Export logs": "Export logs", + "Export monthly bill": "Export monthly bill", + "Export monthly bill and consumption details": "Export monthly bill and consumption details", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Export usage CSV": "Export usage CSV", + "Export usage CSV for user {{name}} (ID {{id}})": "Export usage CSV for user {{name}} (ID {{id}})", "Expose grouped Uptime Kuma status pages directly on the dashboard": "Expose grouped Uptime Kuma status pages directly on the dashboard", "Expose ratio API": "Expose ratio API", "Exposes the pricing/models catalog in the top navigation.": "Exposes the pricing/models catalog in the top navigation.", @@ -1388,6 +1437,9 @@ "External Speed Test": "External Speed Test", "Extra": "Extra", "Extra Notes (Optional)": "Extra Notes (Optional)", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "Fail Reason": "Fail Reason", "Fail Reason Details": "Fail Reason Details", "Failed": "Failed", @@ -1450,6 +1502,7 @@ "Failed to load": "Failed to load", "Failed to load API keys": "Failed to load API keys", "Failed to load billing history": "Failed to load billing history", + "Failed to load consumption": "Failed to load consumption", "Failed to load home page content": "Failed to load home page content", "Failed to load image": "Failed to load image", "Failed to load logs": "Failed to load logs", @@ -1557,6 +1610,7 @@ "Filter by request ID": "Filter by request ID", "Filter by task ID": "Filter by task ID", "Filter by token name": "Filter by token name", + "Filter by user (optional)": "Filter by user (optional)", "Filter by username": "Filter by username", "Filter by username, name or email...": "Filter by username, name or email...", "Filter Dashboard Models": "Filter Dashboard Models", @@ -1595,6 +1649,8 @@ "footer.defaultCopyright": "All rights reserved.", "footer.new\u0061pi.projectAttributionSuffix": "All rights reserved. Designed and developed by the project contributors.", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", "For private deployments, format: https://fastgpt.run/api/openapi": "For private deployments, format: https://fastgpt.run/api/openapi", "Force AUTH LOGIN": "Force AUTH LOGIN", "Force Format": "Force Format", @@ -1623,11 +1679,13 @@ "Full API Key": "Full API Key", "Full Base URL (supports": "Full Base URL (supports", "Full Code": "Full Code", + "Full endpoint URL": "Full endpoint URL", "Functions": "Functions", "GC Count": "GC Count", "GC executed": "GC executed", "GC execution failed": "GC execution failed", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.": "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.", "General": "General", @@ -1779,7 +1837,9 @@ "ID": "ID", "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.": "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.", "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.": "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing": "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.", "Ignored upstream models": "Ignored upstream models", "Image": "Image", @@ -1792,7 +1852,10 @@ "Image to Video": "Image to Video", "Image Tokens": "Image Tokens", "Import to CC Switch": "Import to CC Switch", + "Important": "Important", "In Progress": "In Progress", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "In:": "In:", "Include Group": "Include Group", "Include Model": "Include Model", @@ -1811,13 +1874,17 @@ "Input tokens": "Input tokens", "Input Tokens": "Input Tokens", "Inspect user prompts": "Inspect user prompts", + "Install Claude Code": "Install Claude Code", "Instance": "Instance", + "Integration": "Integration", + "Integration guides": "Integration guides", "Integrations": "Integrations", "Inter-group overrides": "Inter-group overrides", "Inter-group ratio overrides": "Inter-group ratio overrides", + "Interactive login": "Interactive login", + "Interface Language": "Interface Language", "Internal Notes": "Internal Notes", "Internal notes (not shown to users)": "Internal notes (not shown to users)", - "Interface Language": "Interface Language", "Internal Server Error!": "Internal Server Error!", "Invalid chat link. Please contact the administrator.": "Invalid chat link. Please contact the administrator.", "Invalid chat link. Please contact your administrator.": "Invalid chat link. Please contact your administrator.", @@ -1828,6 +1895,7 @@ "Invalid JSON in parameter override template": "Invalid JSON in parameter override template", "Invalid JSON string.": "Invalid JSON string.", "Invalid model mapping format": "Invalid model mapping format", + "Invalid month": "Invalid month", "Invalid Passkey registration response": "Invalid Passkey registration response", "Invalid Passkey response": "Invalid Passkey response", "Invalid payment redirect URL": "Invalid payment redirect URL", @@ -1835,6 +1903,7 @@ "Invalid reset link, please request a new password reset.": "Invalid reset link, please request a new password reset.", "Invalid rules JSON format": "Invalid rules JSON format", "Invalid status code mapping entries: {{entries}}": "Invalid status code mapping entries: {{entries}}", + "Invalid year": "Invalid year", "Invalidate": "Invalidate", "Invalidated": "Invalidated", "Invert match": "Invert match", @@ -1894,8 +1963,8 @@ "Kling": "Kling", "Knowledge Base ID *": "Knowledge Base ID *", "Landing page with system overview.": "Landing page with system overview.", - "Language Preferences": "Language Preferences", "Language preference saved": "Language preference saved", + "Language Preferences": "Language Preferences", "Language preferences sync across your signed-in devices and affect API error messages.": "Language preferences sync across your signed-in devices and affect API error messages.", "Last check time": "Last check time", "Last detected addable models": "Last detected addable models", @@ -1905,7 +1974,9 @@ "Last updated:": "Last updated:", "Last Used": "Last Used", "Last used:": "Last used:", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", "Layout": "Layout", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Learn more": "Learn more", "Learn more:": "Learn more:", "Leave": "Leave", @@ -1928,6 +1999,7 @@ "Less": "Less", "Less Than": "Less Than", "Less Than or Equal": "Less Than or Equal", + "Lifetime channel usage": "Lifetime channel usage", "Light": "Light", "Lightning Fast": "Lightning Fast", "Limit period": "Limit period", @@ -1999,6 +2071,7 @@ "Manage your API keys for accessing the service": "Manage your API keys for accessing the service", "Manage your balance and payment methods": "Manage your balance and payment methods", "Manage your security settings and account access": "Manage your security settings and account access", + "Manual configuration": "Manual configuration", "Manual Disabled": "Manual Disabled", "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).": "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).", "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.": "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.", @@ -2125,6 +2198,7 @@ "Monitor": "Monitor", "Monitoring & Alerts": "Monitoring & Alerts", "Month": "Month", + "Month range uses server local time unless a timezone is set.": "Month range uses server local time unless a timezone is set.", "Monthly": "Monthly", "months": "months", "Moonshot": "Moonshot", @@ -2337,6 +2411,7 @@ "Not Submitted": "Not Submitted", "Not tested": "Not tested", "Not used yet": "Not used yet", + "Note": "Note", "Notice": "Notice", "Notification Email": "Notification Email", "Notification Method": "Notification Method", @@ -2400,13 +2475,18 @@ "Open Source": "Open Source", "Open the io.net console API Keys page": "Open the io.net console API Keys page", "Open theme settings": "Open theme settings", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", "OpenAI Compatible": "OpenAI Compatible", "OpenAI Organization": "OpenAI Organization", "OpenAI Organization ID (optional)": "OpenAI Organization ID (optional)", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAI, Anthropic, etc.": "OpenAI, Anthropic, etc.", "OpenAI, Anthropic, Google, etc.": "OpenAI, Anthropic, Google, etc.", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opened authorization page": "Opened authorization page", "OpenRouter": "OpenRouter", "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.", @@ -2617,6 +2697,8 @@ "Please try again later.": "Please try again later.", "Please upload key file(s)": "Please upload key file(s)", "Please wait a moment, human check is initializing...": "Please wait a moment, human check is initializing...", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "Policy JSON": "Policy JSON", "Polling": "Polling", "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded": "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded", @@ -2627,6 +2709,7 @@ "PostgreSQL detected": "PostgreSQL detected", "PostgreSQL offers advanced reliability and data integrity for production workloads.": "PostgreSQL offers advanced reliability and data integrity for production workloads.", "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.": "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.", + "Powered by": "Powered by", "Powerful API Management Platform": "Powerful API Management Platform", "Pre-Consume for Free Models": "Pre-Consume for Free Models", "Pre-consumed": "Pre-consumed", @@ -2660,7 +2743,6 @@ "Previous": "Previous", "Previous branch": "Previous branch", "Previous page": "Previous page", - "Base Price": "Base Price", "Price": "Price", "Price ($/1K calls)": "Price ($/1K calls)", "Price (local currency / USD)": "Price (local currency / USD)", @@ -2848,6 +2930,7 @@ "Registry username": "Registry username", "Reject Reason": "Reject Reason", "Release details": "Release details", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Relying Party Display Name": "Relying Party Display Name", "Relying Party ID": "Relying Party ID", "Remaining": "Remaining", @@ -2998,8 +3081,11 @@ "Rules": "Rules", "Rules JSON": "Rules JSON", "Rules JSON must be an array": "Rules JSON must be an array", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", "Run GC": "Run GC", "Run tests for the selected models": "Run tests for the selected models", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "Running": "Running", "s": "s", "Safety Settings": "Safety Settings", @@ -3111,8 +3197,8 @@ "Select groups (leave empty to keep current)": "Select groups (leave empty to keep current)", "Select items...": "Select items...", "Select key format": "Select key format", - "Select Language": "Select Language", "Select language": "Select language", + "Select Language": "Select Language", "Select layout style": "Select layout style", "Select locations": "Select locations", "Select Model": "Select Model", @@ -3176,20 +3262,25 @@ "Set quota amount and limits": "Set quota amount and limits", "Set Request Header": "Set Request Header", "Set runtime request header: override entire value, or manipulate comma-separated tokens": "Set runtime request header: override entire value, or manipulate comma-separated tokens", - "Set the language used across the interface": "Set the language used across the interface", "Set Tag": "Set Tag", "Set tag for selected channels": "Set tag for selected channels", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the language used across the interface": "Set the language used across the interface", + "Set the messages endpoint to:": "Set the messages endpoint to:", "Set the user's role (cannot be Root)": "Set the user's role (cannot be Root)", + "Set your API key": "Set your API key", "Setting saved": "Setting saved", "Setting up 2FA...": "Setting up 2FA...", "Setting updated successfully": "Setting updated successfully", "Settings": "Settings", "Settings & Preferences": "Settings & Preferences", "Settings updated successfully": "Settings updated successfully", + "settings.json (optional)": "settings.json (optional)", "Setup Instructions": "Setup Instructions", "Setup Two-Factor Authentication": "Setup Two-Factor Authentication", "Share your link and earn rewards": "Share your link and earn rewards", "Shared configuration for all payment gateways": "Shared configuration for all payment gateways", + "Shell environment": "Shell environment", "Shorten": "Shorten", "Show": "Show", "Show All": "Show All", @@ -3256,6 +3347,7 @@ "Standard": "Standard", "Start": "Start", "Start a conversation to see messages here": "Start a conversation to see messages here", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Start for free with generous limits. No credit card required.": "Start for free with generous limits. No credit card required.", "Start Time": "Start Time", "Static page describing the platform.": "Static page describing the platform.", @@ -3487,7 +3579,9 @@ "Timed cache (1h)": "Timed cache (1h)", "Timeline": "Timeline", "times": "times", + "Timezone (IANA, optional)": "Timezone (IANA, optional)", "Timing": "Timing", + "Tip": "Tip", "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.": "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.", "to access this resource.": "to access this resource.", "to confirm": "to confirm", @@ -3550,15 +3644,19 @@ "Total invitation revenue": "Total invitation revenue", "Total Log Size": "Total Log Size", "Total Quota": "Total Quota", + "Total requests": "Total requests", "Total requests allowed per period. 0 = unlimited.": "Total requests allowed per period. 0 = unlimited.", "Total requests made": "Total requests made", + "Total tokens": "Total tokens", "Total Tokens": "Total Tokens", "Total Usage": "Total Usage", "Total:": "Total:", "TPM": "TPM", + "Trace (Trae IDE)": "Trace (Trae IDE)", "Track per-request consumption to power usage analytics. Keeping this on increases database writes.": "Track per-request consumption to power usage analytics. Keeping this on increases database writes.", "Track usage, costs and performance with real-time analytics": "Track usage, costs and performance with real-time analytics", "Tracks current account base limits and additional metered usage on Codex upstream.": "Tracks current account base limits and additional metered usage on Codex upstream.", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "Transfer": "Transfer", "Transfer Amount": "Transfer Amount", "Transfer failed": "Transfer failed", @@ -3683,7 +3781,11 @@ "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.": "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.", "Use authenticator code": "Use authenticator code", "Use backup code": "Use backup code", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", "Use disk cache when request body exceeds this size": "Use disk cache when request body exceeds this size", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Use our unified OpenAI-compatible endpoint in your applications": "Use our unified OpenAI-compatible endpoint in your applications", "Use Passkey to sign in without entering your password.": "Use Passkey to sign in without entering your password.", "Use secure connection when sending emails": "Use secure connection when sending emails", @@ -3778,6 +3880,7 @@ "View detailed information about this user including balance, usage statistics, and invitation details.": "View detailed information about this user including balance, usage statistics, and invitation details.", "View details": "View details", "View document": "View document", + "View guide": "View guide", "View logs": "View logs", "View mode": "View mode", "View model call count analytics and charts": "View model call count analytics and charts", @@ -3870,6 +3973,8 @@ "whsec_xxx": "whsec_xxx", "Window:": "Window:", "with conflicts": "with conflicts", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Without additional conditions, only the type above is used for pruning.": "Without additional conditions, only the type above is used for pruning.", "Worker Access Key": "Worker Access Key", "Worker Proxy": "Worker Proxy", @@ -3880,6 +3985,7 @@ "xAI": "xAI", "Xinference": "Xinference", "Xunfei": "Xunfei", + "Year": "Year", "years": "years", "You are about to delete {{count}} API key(s).": "You are about to delete {{count}} API key(s).", "You are running the latest version ({{version}}).": "You are running the latest version ({{version}}).", @@ -3889,6 +3995,7 @@ "You don't have necessary permission": "You don't have necessary permission", "You have unsaved changes": "You have unsaved changes", "You have unsaved changes. Are you sure you want to leave?": "You have unsaved changes. Are you sure you want to leave?", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", "You Pay": "You Pay", "You save": "You save", "You will be redirected to Telegram to complete the binding process.": "You will be redirected to Telegram to complete the binding process.", @@ -3899,6 +4006,7 @@ "Your Cloudflare Account ID": "Your Cloudflare Account ID", "Your Discord OAuth Client ID": "Your Discord OAuth Client ID", "Your Discord OAuth Client Secret": "Your Discord OAuth Client Secret", + "Your FaceCloud API key": "Your FaceCloud API key", "Your GitHub OAuth Client ID": "Your GitHub OAuth Client ID", "Your GitHub OAuth Client Secret": "Your GitHub OAuth Client Secret", "Your new backup codes are ready": "Your new backup codes are ready", diff --git a/web/default/src/i18n/locales/fr.json b/web/default/src/i18n/locales/fr.json index f6b6657db937..5f69db45de43 100644 --- a/web/default/src/i18n/locales/fr.json +++ b/web/default/src/i18n/locales/fr.json @@ -15,6 +15,7 @@ "(Optional: redirect model names)": "(Facultatif : rediriger les noms de modèles)", "(Override all channels' groups)": "(Remplacer les groupes de tous les canaux)", "(Override all channels' models)": "(Remplacer les modèles de tous les canaux)", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\"original-model\": \"replacement-model\"}", @@ -109,6 +110,7 @@ "Actual Model:": "Modèle réel :", "Add": "Ajouter", "Add {{title}}": "Ajouter {{title}}", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", "Add a group identifier to the auto assignment list.": "Ajouter un identifiant de groupe à la liste d'affectation automatique.", "Add a new API key by providing necessary info.": "Ajoutez une nouvelle clé API en fournissant les informations nécessaires.", "Add a new channel by providing the necessary information.": "Ajoutez un nouveau canal en fournissant les informations nécessaires.", @@ -127,6 +129,8 @@ "Add custom model(s), comma-separated": "Ajouter un ou plusieurs modèles personnalisés, séparés par des virgules", "Add discount tier": "Ajouter un niveau de réduction", "Add each model or tag you want to include.": "Ajoutez chaque modèle ou étiquette que vous souhaitez inclure.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", "Add FAQ": "Ajouter une FAQ", "Add from available models...": "Ajouter à partir des modèles disponibles...", "Add Funds": "Ajouter des fonds", @@ -156,6 +160,9 @@ "Add selectable group": "Ajouter un groupe sélectionnable", "Add subscription": "Ajouter un abonnement", "Add tags...": "Ajouter des étiquettes...", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "Add tier": "Ajouter un palier", "Add time condition": "Ajouter une condition temporelle", "Add time rule group": "Ajouter un groupe de règles temporelles", @@ -256,6 +263,7 @@ "Allowed Origins": "Origines autorisées", "Allowed Ports": "Ports autorisés", "Already have an account?": "Vous avez déjà un compte ?", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", "Always matches (default tier).": "Toujours appliqué (palier par défaut).", "Amount": "Montant", "Amount cannot be changed when editing.": "Le montant ne peut pas être modifié lors de la modification.", @@ -268,6 +276,7 @@ "Amount to pay:": "Montant à payer :", "An unexpected error occurred": "Une erreur inattendue est survenue", "and": "et", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Announcement added. Click \"Save Settings\" to apply.": "Annonce ajoutée. Cliquez sur \"Enregistrer les paramètres\" pour appliquer.", "Announcement content": "Contenu de l'annonce", "Announcement deleted. Click \"Save Settings\" to apply.": "Annonce supprimée. Cliquez sur \"Enregistrer les paramètres\" pour appliquer.", @@ -278,6 +287,7 @@ "Announcements saved successfully": "Annonces enregistrées avec succès", "Answer": "Réponse", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "Any Match (OR)": "N'importe laquelle (OR)", "API Access": "Accès API", "API Addresses": "Adresses API", @@ -327,6 +337,7 @@ "Apply IP Filter to Resolved Domains": "Appliquer le filtre IP aux domaines résolus", "Apply Overwrite": "Appliquer l'écrasement", "Apply Sync": "Appliquer la synchronisation", + "Apply user filter": "Apply user filter", "Applying...": "Application en cours...", "Approx.": "Environ.", "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.": "sont également listés ici. Supprimez-les des Modèles pour que la réponse `/v1/models` reste conviviale et pour masquer les noms spécifiques aux fournisseurs.", @@ -428,6 +439,7 @@ "Base amount. Actual deduction = base amount × system group rate.": "Montant de base. Déduction réelle = montant de base × taux du groupe système.", "Base Limits": "Limites de base", "Base multipliers applied when users select specific groups.": "Multiplicateurs de base appliqués lorsque les utilisateurs sélectionnent des groupes spécifiques.", + "Base Price": "Prix de base", "Base rate limit windows for this account.": "Fenêtres de limitation de débit de base pour ce compte.", "Base URL": "URL de base", "Base URL of your Uptime Kuma instance": "URL de base de votre instance Uptime Kuma", @@ -447,6 +459,7 @@ "Batch enable failed": "Échec de l'activation par lots", "Batch processing failed": "Échec du traitement par lot", "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Mises à jour par lot des modèles en amont appliquées : {{channels}} canaux, {{added}} ajoutés, {{removed}} supprimés, {{fails}} échoués", + "Before you start": "Before you start", "Best for single-tenant deployments. Pricing and billing options stay hidden.": "Idéal pour les déploiements mono-utilisateur. Les options de tarification et de facturation restent masquées.", "Billing": "Facturation", "Billing currency": "Devise de facturation", @@ -485,7 +498,6 @@ "Broadcast a global banner to users. Markdown is supported.": "Diffuser une bannière globale aux utilisateurs. Le Markdown est pris en charge.", "Broadcast short system notices on the dashboard": "Diffuser de courtes notifications système sur le tableau de bord", "Browse and compare": "Parcourir et comparer", - "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Découvrez une sélection de modèles IA, comparez les tarifs et les capacités, et choisissez le modèle adapté à chaque scénario.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.": "Jetons budgétaires = jetons max × ratio. Accepte un nombre décimal entre 0,002 et 1. Il est recommandé de rester aligné avec la facturation en amont.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.": "Jetons budgétaires = jetons max × ratio. Accepte un nombre décimal entre 0,1 et 1.", "Budget Tokens Ratio": "Ratio de jetons budgétaires", @@ -544,6 +556,7 @@ "Channel Affinity": "Affinité de canal", "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "L'affinité de canal réutilise le dernier canal ayant réussi, en se basant sur les clés extraites du contexte de la requête ou du corps JSON.", "Channel Affinity: Upstream Cache Hit": "Affinité de canal : hit de cache en amont", + "Channel Consumption": "Channel Consumption", "Channel copied successfully": "Canal copié avec succès", "Channel created successfully": "Canal créé avec succès", "Channel deleted successfully": "Canal supprimé avec succès", @@ -608,6 +621,8 @@ "Classic (Legacy Frontend)": "Classique (Ancien frontend)", "Claude": "Claude", "Claude CLI Header Passthrough": "Passthrough en-tête Claude CLI", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Clean history logs": "Nettoyer les journaux d'historique", "Clean logs": "Nettoyer les logs", "Clean up inactive cache": "Nettoyer le cache inactif", @@ -628,6 +643,7 @@ "Clear search": "Effacer la recherche", "Clear selection": "Effacer la sélection", "Clear selection (Escape)": "Effacer la sélection (Échap)", + "Clear user filter": "Clear user filter", "Cleared": "Vidé", "Cleared all models": "Tous les modèles effacés", "Click \"Create Plan\" to create your first subscription plan": "Cliquez sur « Créer un plan » pour créer votre premier abonnement", @@ -655,12 +671,15 @@ "CNY": "CNY", "CNY per USD": "CNY par USD", "Code": "Code", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", "Codes copied!": "Codes copiés !", "Codex": "Codex", "Codex Account & Usage": "Compte et utilisation Codex", "Codex Authorization": "Autorisation Codex", "Codex channels use an OAuth JSON credential as the key.": "Les canaux Codex utilisent un identifiant OAuth JSON comme clé.", "Codex CLI Header Passthrough": "Passthrough en-tête Codex CLI", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", "Collapse": "Réduire", "Collapse All": "Tout réduire", @@ -701,6 +720,7 @@ "Configuration for Creem payment integration": "Configuration pour l'intégration de paiement Creem", "Configuration for Epay payment integration": "Configuration pour l'intégration de paiement Epay", "Configuration for Stripe payment integration": "Configuration pour l'intégration de paiement Stripe", + "Configuration reference": "Configuration reference", "Configuration required": "Configuration requise", "Configure": "Configurer", "Configure a Creem product for user recharge options.": "Configurez un produit Creem pour les options de recharge utilisateur.", @@ -715,17 +735,22 @@ "Configure available payment methods. Provide a JSON array.": "Configurer les méthodes de paiement disponibles. Fournir un tableau JSON.", "Configure basic system information and branding": "Configurer les informations système de base et l'image de marque", "Configure channel affinity (sticky routing) rules": "Configurer les règles d'affinité de canal (routage persistant)", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", "Configure Creem products. Provide a JSON array.": "Configurez les produits Creem. Fournissez un tableau JSON.", "Configure custom OAuth providers for user authentication": "Configurer des fournisseurs OAuth personnalisés pour l'authentification des utilisateurs", "Configure daily check-in rewards for users": "Configurer les récompenses de connexion quotidienne pour les utilisateurs", "Configure discount rates based on recharge amounts": "Configurer les taux de réduction basés sur les montants de recharge", + "Configure environment": "Configure environment", "Configure experimental data export for the dashboard": "Configurer l'exportation de données expérimentales pour le tableau de bord", + "Configure FaceCloud": "Configure FaceCloud", "Configure Gemini safety behavior, version overrides, and thinking adapter": "Configurer le comportement de sécurité Gemini, les remplacements de version et l'adaptateur de réflexion", "Configure in your Creem dashboard": "Configurez dans votre tableau de bord Creem", "Configure io.net API key for model deployments": "Configurer la clé API io.net pour les déploiements de modèles", "Configure keyword filtering for prompts and responses.": "Configurer le filtrage par mots-clés pour les invites et les réponses.", "Configure model, caching, and group ratios used for billing": "Configurer les ratios de modèle, de mise en cache et de groupe utilisés pour la facturation", "Configure monitoring status page groups for the dashboard": "Configurer les groupes de pages d'état de surveillance pour le tableau de bord", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", "Configure outgoing email server for notifications": "Configurer le serveur de messagerie sortant pour les notifications", "Configure Passkey (WebAuthn) login settings": "Configurer les paramètres de connexion Passkey (WebAuthn)", "Configure password-based login and registration": "Configurer la connexion et l'inscription basées sur un mot de passe", @@ -739,6 +764,8 @@ "Configure system-wide behavior and defaults": "Configurer le comportement et les valeurs par défaut à l'échelle du système", "Configure the ratio for this group.": "Configurer le ratio pour ce groupe.", "Configure third-party authentication providers": "Configurer les fournisseurs d'authentification tiers", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", "Configure upstream providers and routing.": "Configurer les fournisseurs en amont et le routage.", "Configure upstream worker or proxy service for outbound requests": "Configurer le service de travailleur en amont ou de proxy pour les requêtes sortantes", "Configure user quota allocation and rewards": "Configurer l'allocation de quotas utilisateur et les récompenses", @@ -774,6 +801,8 @@ "Confirm your identity with Two-factor Authentication before registering a Passkey.": "Confirmez votre identité avec l’authentification à deux facteurs avant d’enregistrer une Passkey.", "Conflict": "Conflit", "Connect": "Connecter", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", "Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Connectez-vous via OpenAI, Claude, Gemini et d'autres routes API compatibles", "Connected to io.net service normally.": "Connexion au service io.net réussie.", "Connection error": "Erreur de connexion", @@ -871,6 +900,7 @@ "Create multiple channels from multiple keys": "Créer plusieurs canaux à partir de plusieurs clés", "Create multiple redemption codes at once (1-100)": "Créer plusieurs codes de rachat à la fois (1-100)", "Create new subscription plan": "Créer un nouveau plan d'abonnement", + "Create or edit": "Create or edit", "Create or update frequently asked questions for users": "Créer ou mettre à jour les questions fréquemment posées aux utilisateurs", "Create or update system announcements for the dashboard": "Créer ou mettre à jour les annonces système pour le tableau de bord", "Create Plan": "Créer un plan", @@ -881,6 +911,7 @@ "Create request parameter override rules without editing raw JSON.": "Créez des règles de remplacement des paramètres de requête sans modifier le JSON brut.", "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.": "Créez des ensembles réutilisables de modèles, de balises, de points de terminaison et de groupes d'utilisateurs pour accélérer la configuration ailleurs dans la console.", "Create succeeded": "Création réussie", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Create Vendor": "Créer un fournisseur", "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Créez votre premier groupe pour réutiliser les sélections de modèles, de balises ou de points de terminaison n'importe où dans le tableau de bord.", "Create, revoke, and audit API tokens.": "Créer, révoquer et auditer les jetons API.", @@ -962,6 +993,7 @@ "Default consumption chart": "Graphique de consommation par défaut", "Default Max Tokens": "Jetons max par défaut", "Default model call chart": "Graphique d'appels de modèle par défaut", + "Default model name for requests": "Default model name for requests", "Default range": "Plage par défaut", "Default Responses API version, if empty, will use the API version above": "Version API des réponses par défaut, si vide, utilisera la version API ci-dessus", "Default system prompt for this channel": "Invite système par défaut pour ce canal", @@ -1059,6 +1091,8 @@ "Disabled all channels with tag: {{tag}}": "Tous les canaux avec le tag {{tag}} ont été désactivés", "Disabled Reason": "Raison de la désactivation", "Disabled Time": "Heure de désactivation", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Disabling...": "Désactivation en cours...", "Discord": "Discord", "Discount": "Remise", @@ -1069,6 +1103,7 @@ "Discount Rate:": "Taux de réduction :", "Discount ratio for cache hits.": "Ratio de réduction pour les accès au cache.", "Discouraged": "Déconseillé", + "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Découvrez une sélection de modèles IA, comparez les tarifs et les capacités, et choisissez le modèle adapté à chaque scénario.", "Discovering...": "Découverte en cours...", "Disk cache cleared": "Cache disque vidé", "Disk Cache Settings": "Paramètres du cache disque", @@ -1106,6 +1141,7 @@ "DoubaoVideo": "DoubaoVideo", "Double check the configuration below. Your system will be locked until initialization is complete.": "Vérifiez la configuration ci-dessous. Votre système sera verrouillé jusqu'à ce que l'initialisation soit terminée.", "Download": "Télécharger", + "Download started": "Téléchargement démarré", "Draw": "Dessin", "Drawing": "Dessin", "Drawing logs": "Journaux de dessin", @@ -1121,6 +1157,7 @@ "e.g. ¥ or HK$": "par ex. ¥ ou HK$", "e.g. 401, 403, 429, 500-599": "ex. 401, 403, 429, 500-599", "e.g. 8 means 1 USD = 8 units": "par ex. 8 signifie 1 USD = 8 unités", + "e.g. Asia/Shanghai": "p. ex. Asia/Shanghai", "e.g. Basic Plan": "ex. Plan de base", "e.g. Clean tool parameters to avoid upstream validation errors": "ex. Nettoyer les paramètres d'outils pour éviter les erreurs de validation en amont", "e.g. example.com": "par ex. example.com", @@ -1179,6 +1216,7 @@ "Edit model": "Modifier le modèle", "Edit Model": "Modifier le modèle", "Edit OAuth Provider": "Modifier le fournisseur OAuth", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", "Edit payment method": "Modifier le mode de paiement", "Edit Prefill Group": "Modifier le groupe de préremplissage", "Edit product": "Modifier le produit", @@ -1254,6 +1292,7 @@ "Endpoint": "Point d'accès", "Endpoint config": "Configuration de l'endpoint", "Endpoint Configuration": "Configuration du point de terminaison", + "Endpoint reference": "Endpoint reference", "Endpoint Type": "Type de point de terminaison", "Endpoint:": "Point de terminaison :", "Endpoints": "Points de terminaison", @@ -1333,6 +1372,7 @@ "Enterprise-grade security with comprehensive permission management": "Sécurité de niveau entreprise avec gestion complète des autorisations", "Entrypoint (space separated)": "Point d'entrée (séparés par des espaces)", "Env (JSON object)": "Env (objet JSON)", + "Environment variable holding your API key": "Environment variable holding your API key", "Environment variables": "Variables d'environnement", "Environment variables (JSON)": "Variables d'environnement (JSON)", "Epay endpoint": "Endpoint Epay", @@ -1371,6 +1411,15 @@ "Expired at": "Expiré le", "Expired time cannot be earlier than current time": "L'heure d'expiration ne peut pas être antérieure à l'heure actuelle", "Expires": "Expire", + "Export completed": "Export completed", + "Export consumption details": "Exporter le détail de consommation", + "Export failed": "Échec de l'export", + "Export logs": "Export logs", + "Export monthly bill": "Exporter la facture mensuelle", + "Export monthly bill and consumption details": "Exporter la facture mensuelle et le détail de consommation", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Export usage CSV": "Exporter l'usage (CSV)", + "Export usage CSV for user {{name}} (ID {{id}})": "Exporter l'usage CSV pour l'utilisateur {{name}} (ID {{id}})", "Expose grouped Uptime Kuma status pages directly on the dashboard": "Exposer les pages d'état groupées d'Uptime Kuma directement sur le tableau de bord", "Expose ratio API": "Exposer l'API de ratio", "Exposes the pricing/models catalog in the top navigation.": "Expose le catalogue des prix/modèles dans la navigation supérieure.", @@ -1388,6 +1437,9 @@ "External Speed Test": "Test de vitesse externe", "Extra": "Supplémentaire", "Extra Notes (Optional)": "Notes supplémentaires (facultatif)", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "Fail Reason": "Raison de l'échec", "Fail Reason Details": "Détails de la raison de l'échec", "Failed": "Échec", @@ -1450,6 +1502,7 @@ "Failed to load": "Échec du chargement", "Failed to load API keys": "Échec du chargement des Clés API", "Failed to load billing history": "Échec du chargement de l'historique de facturation", + "Failed to load consumption": "Failed to load consumption", "Failed to load home page content": "Échec du chargement du contenu de la page d'accueil", "Failed to load image": "Échec du chargement de l'image", "Failed to load logs": "Échec du chargement des journaux", @@ -1557,6 +1610,7 @@ "Filter by request ID": "Filtrer par ID de requête", "Filter by task ID": "Filtrer par ID de tâche", "Filter by token name": "Filtrer par nom de jeton", + "Filter by user (optional)": "Filter by user (optional)", "Filter by username": "Filtrer par nom d'utilisateur", "Filter by username, name or email...": "Filtrer par nom d'utilisateur, nom ou e-mail...", "Filter Dashboard Models": "Filtrer les modèles du tableau de bord", @@ -1595,6 +1649,8 @@ "footer.defaultCopyright": "Tous droits réservés.", "footer.new\u0061pi.projectAttributionSuffix": "Tous droits réservés. Conçu et développé par les contributeurs du projet.", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "Pour les canaux ajoutés après le 10 mai 2025, pas besoin de supprimer \".\" des noms de modèles lors du déploiement", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", "For private deployments, format: https://fastgpt.run/api/openapi": "Pour les déploiements privés, format : https://fastgpt.run/api/openapi", "Force AUTH LOGIN": "Forcer AUTH LOGIN", "Force Format": "Forcer le format", @@ -1623,11 +1679,13 @@ "Full API Key": "Clé API complète", "Full Base URL (supports": "URL de base complète (prend en charge", "Full Code": "Code complet", + "Full endpoint URL": "Full endpoint URL", "Functions": "Fonctions", "GC Count": "Nombre de GC", "GC executed": "GC exécuté", "GC execution failed": "Échec de l'exécution du GC", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.": "Gemini continuera à détecter automatiquement le mode de pensée même avec l'adaptateur désactivé. Activez ceci uniquement lorsque vous avez besoin d'un contrôle plus fin sur la tarification et le budget.", "General": "Général", @@ -1779,7 +1837,9 @@ "ID": "ID", "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.": "Si une erreur en amont contient l'un de ces mots-clés (insensible à la casse), le canal sera désactivé automatiquement.", "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.": "Si l'autorisation réussit, le JSON généré sera inséré dans le champ clé. Vous devez encore enregistrer le canal pour le conserver.", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing": "Si vous vous connectez à des projets de relais One API ou New API en amont, utilisez le type OpenAI à la place sauf si vous savez ce que vous faites", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "Si le canal affinitaire échoue et qu'une nouvelle tentative réussit sur un autre canal, mettre à jour l'affinité vers le canal ayant réussi.", "Ignored upstream models": "Modèles amont ignorés", "Image": "Image", @@ -1792,7 +1852,10 @@ "Image to Video": "Image vers vidéo", "Image Tokens": "Tokens image", "Import to CC Switch": "Importer vers CC Switch", + "Important": "Important", "In Progress": "En cours", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "In:": "Entrée :", "Include Group": "Inclure le groupe", "Include Model": "Inclure le modèle", @@ -1811,13 +1874,17 @@ "Input tokens": "Jetons d’entrée", "Input Tokens": "Tokens d'entrée", "Inspect user prompts": "Inspecter les invites utilisateur", + "Install Claude Code": "Install Claude Code", "Instance": "Instance", + "Integration": "Integration", + "Integration guides": "Integration guides", "Integrations": "Intégrations", "Inter-group overrides": "Dérogations inter-groupes", "Inter-group ratio overrides": "Dérogations de ratio inter-groupes", + "Interactive login": "Interactive login", + "Interface Language": "Langue de l'interface", "Internal Notes": "Notes internes", "Internal notes (not shown to users)": "Notes internes (non visibles par les utilisateurs)", - "Interface Language": "Langue de l'interface", "Internal Server Error!": "Erreur interne du serveur !", "Invalid chat link. Please contact the administrator.": "Lien de chat invalide. Veuillez contacter l'administrateur.", "Invalid chat link. Please contact your administrator.": "Lien de chat invalide. Veuillez contacter votre administrateur.", @@ -1828,6 +1895,7 @@ "Invalid JSON in parameter override template": "JSON invalide dans le modèle de remplacement de paramètres", "Invalid JSON string.": "Chaîne JSON invalide.", "Invalid model mapping format": "Format de mappage de modèle invalide", + "Invalid month": "Mois invalide", "Invalid Passkey registration response": "Réponse d'enregistrement de passe-clé invalide", "Invalid Passkey response": "Réponse Passkey invalide", "Invalid payment redirect URL": "URL de redirection de paiement non valide", @@ -1835,6 +1903,7 @@ "Invalid reset link, please request a new password reset.": "Lien de réinitialisation invalide, veuillez demander une nouvelle réinitialisation du mot de passe.", "Invalid rules JSON format": "Format JSON des règles invalide", "Invalid status code mapping entries: {{entries}}": "Entrées de mappage de code d'état invalides : {{entries}}", + "Invalid year": "Année invalide", "Invalidate": "Invalider", "Invalidated": "Invalidé", "Invert match": "Inverser la correspondance", @@ -1894,8 +1963,8 @@ "Kling": "Kling", "Knowledge Base ID *": "ID de la base de connaissances *", "Landing page with system overview.": "Page d'accueil avec aperçu du système.", - "Language Preferences": "Préférences de langue", "Language preference saved": "Préférence de langue enregistrée", + "Language Preferences": "Préférences de langue", "Language preferences sync across your signed-in devices and affect API error messages.": "Les préférences de langue se synchronisent sur vos appareils connectés et affectent les messages d'erreur de l'API.", "Last check time": "Dernière vérification", "Last detected addable models": "Derniers modèles ajoutables détectés", @@ -1905,7 +1974,9 @@ "Last updated:": "Dernière mise à jour :", "Last Used": "Dernière utilisation", "Last used:": "Dernière utilisation :", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", "Layout": "Disposition", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Learn more": "En savoir plus", "Learn more:": "En savoir plus :", "Leave": "Quitter", @@ -1928,6 +1999,7 @@ "Less": "Moins", "Less Than": "Inférieur à", "Less Than or Equal": "Inférieur ou égal", + "Lifetime channel usage": "Lifetime channel usage", "Light": "Clair", "Lightning Fast": "Extrêmement rapide", "Limit period": "Période de limite", @@ -1999,6 +2071,7 @@ "Manage your API keys for accessing the service": "Gérer vos clés API pour accéder au service", "Manage your balance and payment methods": "Gérer votre solde et vos méthodes de paiement", "Manage your security settings and account access": "Gérer vos paramètres de sécurité et l'accès à votre compte", + "Manual configuration": "Manual configuration", "Manual Disabled": "Désactivé manuellement", "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).": "Mapper les champs de la réponse des informations utilisateur vers les attributs utilisateur locaux. Supporte les chemins imbriqués (par exemple ocs.data.id).", "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.": "Mapper les identifiants de modèle aux versions de l'API Gemini. Une entrée `default` s'applique lorsqu'aucune correspondance spécifique n'est trouvée.", @@ -2125,6 +2198,7 @@ "Monitor": "Surveiller", "Monitoring & Alerts": "Surveillance & Alertes", "Month": "Mois", + "Month range uses server local time unless a timezone is set.": "Sans fuseau, le mois civil suit l'heure locale du serveur ; avec un fuseau IANA, le mois civil suit ce fuseau.", "Monthly": "Mensuel", "months": "mois", "Moonshot": "Moonshot", @@ -2337,6 +2411,7 @@ "Not Submitted": "Non soumis", "Not tested": "Non testé", "Not used yet": "Pas encore utilisé", + "Note": "Note", "Notice": "Avis", "Notification Email": "E-mail de notification", "Notification Method": "Méthode de notification", @@ -2400,13 +2475,18 @@ "Open Source": "Open source", "Open the io.net console API Keys page": "Ouvrir la page Clés API de la console io.net", "Open theme settings": "Ouvrir les paramètres du thème", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", "OpenAI Compatible": "Compatible OpenAI", "OpenAI Organization": "Organisation OpenAI", "OpenAI Organization ID (optional)": "Identifiant d'organisation OpenAI (optionnel)", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAI, Anthropic, etc.": "OpenAI, Anthropic, etc.", "OpenAI, Anthropic, Google, etc.": "OpenAI, Anthropic, Google, etc.", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opened authorization page": "Page d'autorisation ouverte", "OpenRouter": "OpenRouter", "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "s'ouvre dans un client externe. Déclenchez-le depuis la barre latérale ou les actions de clé API pour lancer l'application configurée.", @@ -2617,6 +2697,8 @@ "Please try again later.": "Veuillez réessayer plus tard.", "Please upload key file(s)": "Veuillez télécharger le (s) fichier(s) clé (s)", "Please wait a moment, human check is initializing...": "Veuillez patienter un instant, la vérification humaine s'initialise...", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "Policy JSON": "JSON de stratégie", "Polling": "Sondage", "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded": "Le mode d'interrogation nécessite Redis et un cache mémoire, sinon les performances seront considérablement dégradées", @@ -2627,6 +2709,7 @@ "PostgreSQL detected": "PostgreSQL détecté", "PostgreSQL offers advanced reliability and data integrity for production workloads.": "PostgreSQL offre une fiabilité avancée et une intégrité des données pour les charges de travail en production.", "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.": "PostgreSQL offre de solides garanties de fiabilité. Vérifiez votre fenêtre de maintenance et vos politiques de rétention avant la mise en production.", + "Powered by": "Powered by", "Powerful API Management Platform": "Plateforme puissante de gestion d'API", "Pre-Consume for Free Models": "Pré-consommation pour les modèles gratuits", "Pre-consumed": "Pré-consommé", @@ -2660,7 +2743,6 @@ "Previous": "Précédent", "Previous branch": "Branche précédente", "Previous page": "Page précédente", - "Base Price": "Prix de base", "Price": "Prix", "Price ($/1K calls)": "Prix ($/1K appels)", "Price (local currency / USD)": "Prix (devise locale / USD)", @@ -2848,6 +2930,7 @@ "Registry username": "Nom d'utilisateur du registre", "Reject Reason": "Raison du rejet", "Release details": "Détails de la version", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Relying Party Display Name": "Nom d'affichage de la partie de confiance", "Relying Party ID": "ID de la partie de confiance", "Remaining": "Restant", @@ -2998,8 +3081,11 @@ "Rules": "Règles", "Rules JSON": "Règles JSON", "Rules JSON must be an array": "Le JSON des règles doit être un tableau", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", "Run GC": "Exécuter le GC", "Run tests for the selected models": "Exécuter les tests pour les modèles sélectionnés", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "Running": "En cours", "s": "s", "Safety Settings": "Paramètres de sécurité", @@ -3111,8 +3197,8 @@ "Select groups (leave empty to keep current)": "Sélectionner les groupes (laisser vide pour conserver les groupes actuels)", "Select items...": "Sélectionner des éléments...", "Select key format": "Sélectionner le format de clé", - "Select Language": "Sélectionner la langue", "Select language": "Sélectionner une langue", + "Select Language": "Sélectionner la langue", "Select layout style": "Sélectionner le style de mise en page", "Select locations": "Sélectionner des emplacements", "Select Model": "Sélectionner le modèle", @@ -3176,20 +3262,25 @@ "Set quota amount and limits": "Définir le quota et les limites", "Set Request Header": "Définir un en-tête de requête", "Set runtime request header: override entire value, or manipulate comma-separated tokens": "Définir l'en-tête de requête : remplacer la valeur ou manipuler les tokens séparés par des virgules", - "Set the language used across the interface": "Définir la langue utilisée dans l'interface", "Set Tag": "Définir un tag", "Set tag for selected channels": "Définir un tag pour les canaux sélectionnés", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the language used across the interface": "Définir la langue utilisée dans l'interface", + "Set the messages endpoint to:": "Set the messages endpoint to:", "Set the user's role (cannot be Root)": "Définir le rôle de l'utilisateur (ne peut pas être Root)", + "Set your API key": "Set your API key", "Setting saved": "Paramètre sauvegardé", "Setting up 2FA...": "Configuration de la 2FA...", "Setting updated successfully": "Paramètre mis à jour avec succès", "Settings": "Paramètres", "Settings & Preferences": "Paramètres et préférences", "Settings updated successfully": "Paramètres mis à jour avec succès", + "settings.json (optional)": "settings.json (optional)", "Setup Instructions": "Instructions de configuration", "Setup Two-Factor Authentication": "Configurer l'authentification à deux facteurs", "Share your link and earn rewards": "Partagez votre lien et gagnez des récompenses", "Shared configuration for all payment gateways": "Configuration partagée pour toutes les passerelles de paiement", + "Shell environment": "Shell environment", "Shorten": "Raccourcir", "Show": "Afficher", "Show All": "Tout afficher", @@ -3256,6 +3347,7 @@ "Standard": "Standard", "Start": "Début", "Start a conversation to see messages here": "Démarrez une conversation pour voir les messages ici", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Start for free with generous limits. No credit card required.": "Commencez gratuitement avec des limites généreuses. Aucune carte de crédit requise.", "Start Time": "Heure de début", "Static page describing the platform.": "Page statique décrivant la plateforme.", @@ -3487,7 +3579,9 @@ "Timed cache (1h)": "Cache limité (1h)", "Timeline": "Chronologie", "times": "Fois", + "Timezone (IANA, optional)": "Fuseau horaire (IANA, optionnel)", "Timing": "Durée", + "Tip": "Tip", "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.": "Conseil : La clé générée est un identifiant JSON incluant access_token / refresh_token / account_id.", "to access this resource.": "pour accéder à cette ressource.", "to confirm": "pour confirmer", @@ -3550,15 +3644,19 @@ "Total invitation revenue": "Revenu total des invitations", "Total Log Size": "Taille totale des journaux", "Total Quota": "Quota total", + "Total requests": "Total requests", "Total requests allowed per period. 0 = unlimited.": "Total des requêtes autorisées par période. 0 = illimité.", "Total requests made": "Requêtes totales effectuées", + "Total tokens": "Total tokens", "Total Tokens": "Jetons totaux", "Total Usage": "Utilisation totale", "Total:": "Total :", "TPM": "TPM", + "Trace (Trae IDE)": "Trace (Trae IDE)", "Track per-request consumption to power usage analytics. Keeping this on increases database writes.": "Suivre la consommation par requête pour l'analyse de l'utilisation. Garder ceci activé augmente les écritures en base de données.", "Track usage, costs and performance with real-time analytics": "Suivez l'utilisation, les coûts et les performances avec des analyses en temps réel", "Tracks current account base limits and additional metered usage on Codex upstream.": "Affiche les limites de base et l’utilisation supplémentaire (metered) du compte auprès de Codex en amont.", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "Transfer": "Transférer", "Transfer Amount": "Montant du transfert", "Transfer failed": "Transfert échoué", @@ -3683,7 +3781,11 @@ "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.": "Utilisez un navigateur ou un appareil compatible avec l'authentification biométrique ou une clé de sécurité pour enregistrer une clé d'accès (Passkey).", "Use authenticator code": "Utiliser le code de l'authentificateur", "Use backup code": "Utiliser un code de secours", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", "Use disk cache when request body exceeds this size": "Utiliser le cache disque quand le corps de requête dépasse cette taille", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Use our unified OpenAI-compatible endpoint in your applications": "Utilisez notre point de terminaison unifié compatible OpenAI dans vos applications", "Use Passkey to sign in without entering your password.": "Utilisez une clé d'accès (Passkey) pour vous connecter sans saisir votre mot de passe.", "Use secure connection when sending emails": "Utiliser une connexion sécurisée lors de l'envoi d'e-mails", @@ -3778,6 +3880,7 @@ "View detailed information about this user including balance, usage statistics, and invitation details.": "Afficher des informations détaillées sur cet utilisateur, y compris le solde, les statistiques d'utilisation et les détails d'invitation.", "View details": "Voir les détails", "View document": "Afficher le document", + "View guide": "View guide", "View logs": "Voir les logs", "View mode": "Mode d'affichage", "View model call count analytics and charts": "Afficher les analyses et graphiques du nombre d'appels par modèle", @@ -3870,6 +3973,8 @@ "whsec_xxx": "whsec_xxx", "Window:": "Fenêtre :", "with conflicts": "avec des conflits", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Without additional conditions, only the type above is used for pruning.": "Sans conditions supplémentaires, seul le type ci-dessus est utilisé pour le nettoyage.", "Worker Access Key": "Clé d'accès du Worker", "Worker Proxy": "Proxy Worker", @@ -3880,6 +3985,7 @@ "xAI": "xAI", "Xinference": "Xinference", "Xunfei": "Xunfei", + "Year": "Année", "years": "ans", "You are about to delete {{count}} API key(s).": "Vous êtes sur le point de supprimer {{count}} clé(s) API.", "You are running the latest version ({{version}}).": "Vous utilisez la dernière version ({{version}}).", @@ -3889,6 +3995,7 @@ "You don't have necessary permission": "Vous n'avez pas la permission nécessaire", "You have unsaved changes": "Vous avez des modifications non enregistrées", "You have unsaved changes. Are you sure you want to leave?": "Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir quitter ?", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", "You Pay": "Vous payez", "You save": "Vous économisez", "You will be redirected to Telegram to complete the binding process.": "Vous serez redirigé vers Telegram pour terminer le processus de liaison.", @@ -3899,6 +4006,7 @@ "Your Cloudflare Account ID": "Votre ID de compte Cloudflare", "Your Discord OAuth Client ID": "Votre ID client OAuth Discord", "Your Discord OAuth Client Secret": "Votre secret client OAuth Discord", + "Your FaceCloud API key": "Your FaceCloud API key", "Your GitHub OAuth Client ID": "Votre ID Client OAuth GitHub", "Your GitHub OAuth Client Secret": "Votre Secret Client OAuth GitHub", "Your new backup codes are ready": "Vos nouveaux codes de secours sont prêts", diff --git a/web/default/src/i18n/locales/ja.json b/web/default/src/i18n/locales/ja.json index b62d4dabe711..3289aa0103d5 100644 --- a/web/default/src/i18n/locales/ja.json +++ b/web/default/src/i18n/locales/ja.json @@ -15,6 +15,7 @@ "(Optional: redirect model names)": "(オプション: モデル名をリダイレクト)", "(Override all channels' groups)": "(全チャンネルのグループを上書き)", "(Override all channels' models)": "(全チャンネルのモデルを上書き)", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\" original - model \":\" replacement - model \"}", @@ -109,6 +110,7 @@ "Actual Model:": "実際のモデル:", "Add": "追加", "Add {{title}}": "{{title}}を追加", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", "Add a group identifier to the auto assignment list.": "自動割り当てリストにグループ識別子を追加します。", "Add a new API key by providing necessary info.": "必要な情報を提供して新しいAPIキーを追加。", "Add a new channel by providing the necessary information.": "必要な情報を提供して新しいチャンネルを追加。", @@ -127,6 +129,8 @@ "Add custom model(s), comma-separated": "カスタムモデルを追加 (コンマ区切り)", "Add discount tier": "割引ティアを追加", "Add each model or tag you want to include.": "含めたい各モデルまたはタグを追加。", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", "Add FAQ": "FAQ追加", "Add from available models...": "利用可能なモデルから追加...", "Add Funds": "残高チャージ", @@ -156,6 +160,9 @@ "Add selectable group": "選択可能なグループを追加", "Add subscription": "サブスクリプションを追加", "Add tags...": "タグを追加...", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "Add tier": "ティアを追加", "Add time condition": "時間条件を追加", "Add time rule group": "時間ルールグループを追加", @@ -256,6 +263,7 @@ "Allowed Origins": "許可するオリジン", "Allowed Ports": "許可するポート", "Already have an account?": "アカウントをお持ちの方?", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", "Always matches (default tier).": "常に一致(デフォルト ティア)。", "Amount": "金額", "Amount cannot be changed when editing.": "編集時は金額を変更できません。", @@ -268,6 +276,7 @@ "Amount to pay:": "支払い金額:", "An unexpected error occurred": "予期せぬエラーが発生しました", "and": "および", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Announcement added. Click \"Save Settings\" to apply.": "お知らせが追加されました。\"設定を保存\" をクリックして適用してください。", "Announcement content": "お知らせの内容", "Announcement deleted. Click \"Save Settings\" to apply.": "お知らせが削除されました。\"設定を保存\" をクリックして適用してください。", @@ -278,6 +287,7 @@ "Announcements saved successfully": "お知らせが正常に保存されました", "Answer": "回答", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "Any Match (OR)": "いずれか一致(OR)", "API Access": "API アクセス", "API Addresses": "APIアドレス", @@ -327,6 +337,7 @@ "Apply IP Filter to Resolved Domains": "解決されたドメインにIPフィルターを適用", "Apply Overwrite": "上書き適用", "Apply Sync": "同期を適用", + "Apply user filter": "Apply user filter", "Applying...": "適用中...", "Approx.": "約", "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.": "もここにリストされています。`/v1/models` レスポンスをユーザーフレンドリーに保ち、ベンダー固有の名前を隠すために、Models からこれらを削除します。", @@ -428,6 +439,7 @@ "Base amount. Actual deduction = base amount × system group rate.": "基本金額。実際の控除 = 基本金額 × システムグループ倍率。", "Base Limits": "基本枠", "Base multipliers applied when users select specific groups.": "ユーザーが特定のグループを選択したときに適用される基本乗数。", + "Base Price": "基本価格", "Base rate limit windows for this account.": "このアカウント向けの基本レート制限ウィンドウ。", "Base URL": "ベースURL", "Base URL of your Uptime Kuma instance": "Uptime KumaインスタンスのベースURL", @@ -447,6 +459,7 @@ "Batch enable failed": "一括有効化に失敗しました", "Batch processing failed": "一括処理に失敗しました", "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "一括上流モデル更新を処理しました:{{channels}} チャネル、{{added}} 個追加、{{removed}} 個削除、{{fails}} 個失敗", + "Before you start": "Before you start", "Best for single-tenant deployments. Pricing and billing options stay hidden.": "シングルテナント環境に最適です。料金設定や請求オプションは非表示になります。", "Billing": "請求", "Billing currency": "請求通貨", @@ -485,7 +498,6 @@ "Broadcast a global banner to users. Markdown is supported.": "ユーザーにグローバルバナーをブロードキャストします。Markdownがサポートされています。", "Broadcast short system notices on the dashboard": "ダッシュボードに短いシステム通知をブロードキャストします", "Browse and compare": "参照と比較", - "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "厳選された AI モデルを見つけ、価格と機能を比較し、あらゆるシナリオに適したモデルを選択できます。", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.": "予算トークン = 最大トークン × 比率。0.002から1までの小数を指定できます。アップストリームの請求と一致させることを推奨します。", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.": "予算トークン = 最大トークン × 比率。0.1から1までの小数を指定できます。", "Budget Tokens Ratio": "予算トークン比率", @@ -544,6 +556,7 @@ "Channel Affinity": "チャネルアフィニティ", "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "チャネルアフィニティは、リクエストコンテキストまたは JSON Body から抽出したキーに基づいて、前回成功したチャネルを優先的に再利用します。", "Channel Affinity: Upstream Cache Hit": "チャネルアフィニティ:上流キャッシュヒット", + "Channel Consumption": "Channel Consumption", "Channel copied successfully": "チャンネルが正常にコピーされました", "Channel created successfully": "チャンネルが正常に作成されました", "Channel deleted successfully": "チャンネルが正常に削除されました", @@ -608,6 +621,8 @@ "Classic (Legacy Frontend)": "クラシック(旧フロントエンド)", "Claude": "Claude", "Claude CLI Header Passthrough": "Claude CLI ヘッダーパススルー", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Clean history logs": "履歴ログをクリーンアップ", "Clean logs": "ログをクリア", "Clean up inactive cache": "非アクティブキャッシュをクリーンアップ", @@ -628,6 +643,7 @@ "Clear search": "検索をクリア", "Clear selection": "選択をクリア", "Clear selection (Escape)": "選択をクリア (Escape)", + "Clear user filter": "Clear user filter", "Cleared": "クリア済み", "Cleared all models": "すべてのモデルをクリアしました", "Click \"Create Plan\" to create your first subscription plan": "「プラン作成」をクリックして最初のプランを作成してください", @@ -655,12 +671,15 @@ "CNY": "CNY", "CNY per USD": "1 USD あたりの CNY", "Code": "コード", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", "Codes copied!": "コードをコピーしました!", "Codex": "Codex", "Codex Account & Usage": "Codex アカウントと使用量", "Codex Authorization": "Codex認証", "Codex channels use an OAuth JSON credential as the key.": "CodexチャンネルはOAuth JSON認証情報をキーとして使用します。", "Codex CLI Header Passthrough": "Codex CLI ヘッダーパススルー", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", "Collapse": "折りたたむ", "Collapse All": "すべて折りたたむ", @@ -701,6 +720,7 @@ "Configuration for Creem payment integration": "Creem決済統合の設定", "Configuration for Epay payment integration": "Epay決済連携のための設定", "Configuration for Stripe payment integration": "Stripe決済連携のための設定", + "Configuration reference": "Configuration reference", "Configuration required": "設定が必要です", "Configure": "設定", "Configure a Creem product for user recharge options.": "ユーザー チャージオプション用の Creem 製品を設定。", @@ -715,17 +735,22 @@ "Configure available payment methods. Provide a JSON array.": "利用可能な支払い方法を設定します。JSON配列を提供してください。", "Configure basic system information and branding": "基本的なシステム情報とブランディングを設定", "Configure channel affinity (sticky routing) rules": "チャネルアフィニティ(スティッキールーティング)ルールの設定", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", "Configure Creem products. Provide a JSON array.": "Creem製品を設定。JSON配列を提供してください。", "Configure custom OAuth providers for user authentication": "ユーザー認証のためのカスタムOAuthプロバイダーを設定", "Configure daily check-in rewards for users": "ユーザーの毎日のチェックイン報酬を設定する", "Configure discount rates based on recharge amounts": "チャージ金額に基づいた割引率を設定", + "Configure environment": "Configure environment", "Configure experimental data export for the dashboard": "ダッシュボード用の実験的なデータエクスポートを設定", + "Configure FaceCloud": "Configure FaceCloud", "Configure Gemini safety behavior, version overrides, and thinking adapter": "Geminiの安全動作、バージョン上書き、および思考アダプターを設定", "Configure in your Creem dashboard": "Creem ダッシュボードで設定", "Configure io.net API key for model deployments": "モデルデプロイ用の io.net API キーを設定します", "Configure keyword filtering for prompts and responses.": "プロンプトと応答のキーワードフィルタリングを設定します。", "Configure model, caching, and group ratios used for billing": "請求に使用されるモデル、キャッシュ、およびグループ比率を設定します。", "Configure monitoring status page groups for the dashboard": "ダッシュボードの監視ステータスページグループを設定します。", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", "Configure outgoing email server for notifications": "通知用の送信メールサーバーを設定します。", "Configure Passkey (WebAuthn) login settings": "パスキー (WebAuthn) ログイン設定を設定", "Configure password-based login and registration": "パスワードベースのログインと登録を設定します。", @@ -739,6 +764,8 @@ "Configure system-wide behavior and defaults": "システム全体の動作とデフォルトを設定します。", "Configure the ratio for this group.": "このグループの比率を設定します。", "Configure third-party authentication providers": "サードパーティの認証プロバイダーを設定します。", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", "Configure upstream providers and routing.": "アップストリームプロバイダーとルーティングを設定。", "Configure upstream worker or proxy service for outbound requests": "アウトバウンドリクエストのアップストリームワーカーまたはプロキシサービスを設定します。", "Configure user quota allocation and rewards": "ユーザーのクォータ割り当てと報酬を設定します。", @@ -774,6 +801,8 @@ "Confirm your identity with Two-factor Authentication before registering a Passkey.": "パスキーを登録する前に、二要素認証で本人確認を行ってください。", "Conflict": "競合", "Connect": "接続", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", "Connect through OpenAI, Claude, Gemini, and other compatible API routes": "OpenAI、Claude、Gemini、その他の互換APIルートから接続", "Connected to io.net service normally.": "io.net サービスに正常に接続しました。", "Connection error": "接続エラー", @@ -871,6 +900,7 @@ "Create multiple channels from multiple keys": "複数のキーから複数のチャンネルを作成", "Create multiple redemption codes at once (1-100)": "複数の引き換えコードを一度に作成します (1-100)", "Create new subscription plan": "新しいサブスクリプションプランを作成", + "Create or edit": "Create or edit", "Create or update frequently asked questions for users": "ユーザー向けのよくある質問を作成または更新します", "Create or update system announcements for the dashboard": "ダッシュボードのシステムアナウンスを作成または更新します", "Create Plan": "プラン作成", @@ -881,6 +911,7 @@ "Create request parameter override rules without editing raw JSON.": "生の JSON を編集せずにリクエストパラメータ上書きルールを作成します。", "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.": "モデル、タグ、エンドポイント、およびユーザーグループの再利用可能なバンドルを作成し、コンソールの他の場所での設定を高速化します。", "Create succeeded": "作成に成功しました", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Create Vendor": "ベンダーを作成", "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "ダッシュボードのどこでもモデル、タグ、またはエンドポイントの選択を再利用するために、最初のグループを作成します。", "Create, revoke, and audit API tokens.": "APIトークンを作成、取り消し、監査。", @@ -962,6 +993,7 @@ "Default consumption chart": "デフォルトの消費チャート", "Default Max Tokens": "デフォルトの最大トークン", "Default model call chart": "デフォルトのモデル呼び出しチャート", + "Default model name for requests": "Default model name for requests", "Default range": "デフォルト範囲", "Default Responses API version, if empty, will use the API version above": "デフォルトの応答APIバージョン。空の場合、上記のAPIバージョンが使用されます", "Default system prompt for this channel": "このチャンネルのデフォルトのシステムプロンプト", @@ -1059,6 +1091,8 @@ "Disabled all channels with tag: {{tag}}": "タグ「{{tag}}」の全チャネルを無効にしました", "Disabled Reason": "無効化の理由", "Disabled Time": "無効化された時刻", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Disabling...": "無効化中...", "Discord": "Discord", "Discount": "特典", @@ -1069,6 +1103,7 @@ "Discount Rate:": "割引率:", "Discount ratio for cache hits.": "キャッシュヒットに対する割引率。", "Discouraged": "非推奨", + "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "厳選された AI モデルを見つけ、価格と機能を比較し、あらゆるシナリオに適したモデルを選択できます。", "Discovering...": "検出中...", "Disk cache cleared": "ディスクキャッシュをクリアしました", "Disk Cache Settings": "ディスクキャッシュ設定", @@ -1106,6 +1141,7 @@ "DoubaoVideo": "DoubaoVideo", "Double check the configuration below. Your system will be locked until initialization is complete.": "下記の設定を再確認してください。初期化が完了するまでシステムはロックされます。", "Download": "ダウンロード", + "Download started": "ダウンロードを開始しました", "Draw": "描画", "Drawing": "画像生成", "Drawing logs": "描画ログ", @@ -1121,6 +1157,7 @@ "e.g. ¥ or HK$": "例: ¥ または HK$", "e.g. 401, 403, 429, 500-599": "例:401, 403, 429, 500-599", "e.g. 8 means 1 USD = 8 units": "例: 8 は 1 USD = 8 単位 を意味します", + "e.g. Asia/Shanghai": "例: Asia/Shanghai", "e.g. Basic Plan": "例:ベーシックプラン", "e.g. Clean tool parameters to avoid upstream validation errors": "例:ツールパラメータを整理して上流の検証エラーを回避", "e.g. example.com": "例: example.com", @@ -1179,6 +1216,7 @@ "Edit model": "モデルを編集", "Edit Model": "モデルを編集", "Edit OAuth Provider": "OAuthプロバイダーを編集", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", "Edit payment method": "決済方法を編集", "Edit Prefill Group": "プリフィルグループを編集", "Edit product": "製品を編集", @@ -1254,6 +1292,7 @@ "Endpoint": "エンドポイント", "Endpoint config": "エンドポイント設定", "Endpoint Configuration": "エンドポイント設定", + "Endpoint reference": "Endpoint reference", "Endpoint Type": "エンドポイントタイプ", "Endpoint:": "エンドポイント:", "Endpoints": "エンドポイント", @@ -1333,6 +1372,7 @@ "Enterprise-grade security with comprehensive permission management": "包括的な権限管理を備えたエンタープライズグレードのセキュリティ", "Entrypoint (space separated)": "Entrypoint (スペース区切り)", "Env (JSON object)": "Env (JSON オブジェクト)", + "Environment variable holding your API key": "Environment variable holding your API key", "Environment variables": "環境変数", "Environment variables (JSON)": "環境変数(JSON)", "Epay endpoint": "Epayエンドポイント", @@ -1371,6 +1411,15 @@ "Expired at": "有効期限", "Expired time cannot be earlier than current time": "有効期限は現在時刻より早く設定できません", "Expires": "有効期限", + "Export completed": "Export completed", + "Export consumption details": "利用明細をエクスポート", + "Export failed": "エクスポートに失敗しました", + "Export logs": "Export logs", + "Export monthly bill": "月次請求サマリーをエクスポート", + "Export monthly bill and consumption details": "月次請求サマリーと利用明細をエクスポート", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Export usage CSV": "利用状況をCSVでエクスポート", + "Export usage CSV for user {{name}} (ID {{id}})": "ユーザー {{name}}(ID {{id}})の利用状況をCSVでエクスポート", "Expose grouped Uptime Kuma status pages directly on the dashboard": "グループ化されたUptime Kumaステータスページをダッシュボードに直接公開する", "Expose ratio API": "倍率APIを公開", "Exposes the pricing/models catalog in the top navigation.": "価格/モデルカタログをトップナビゲーションに表示します。", @@ -1388,6 +1437,9 @@ "External Speed Test": "外部スピードテスト", "Extra": "追加", "Extra Notes (Optional)": "追加のメモ (オプション)", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "Fail Reason": "失敗理由", "Fail Reason Details": "失敗理由の詳細", "Failed": "失敗", @@ -1450,6 +1502,7 @@ "Failed to load": "読み込みに失敗しました", "Failed to load API keys": "APIキーの読み込みに失敗しました", "Failed to load billing history": "請求履歴の読み込みに失敗しました", + "Failed to load consumption": "Failed to load consumption", "Failed to load home page content": "ホームページの内容の読み込みに失敗しました", "Failed to load image": "画像の読み込みに失敗しました", "Failed to load logs": "ログの読み込みに失敗しました", @@ -1557,6 +1610,7 @@ "Filter by request ID": "リクエストIDで絞り込み", "Filter by task ID": "タスクIDでフィルター", "Filter by token name": "トークン名でフィルター", + "Filter by user (optional)": "Filter by user (optional)", "Filter by username": "ユーザー名でフィルター", "Filter by username, name or email...": "ユーザー名、名前またはメールアドレスでフィルター...", "Filter Dashboard Models": "ダッシュボードモデルをフィルタリング", @@ -1595,6 +1649,8 @@ "footer.defaultCopyright": "すべての権利を留保します。", "footer.new\u0061pi.projectAttributionSuffix": "すべての権利を留保します。プロジェクトコントリビューターにより設計・開発されています。", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "2025 年 5 月 10 日以降に追加されたチャネルの場合、デプロイ時にモデル名から「.」を削除する必要はありません", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", "For private deployments, format: https://fastgpt.run/api/openapi": "プライベートデプロイメントの場合、形式: https://fastgpt.run/api/openapi", "Force AUTH LOGIN": "AUTH LOGINを強制", "Force Format": "強制フォーマット", @@ -1623,11 +1679,13 @@ "Full API Key": "完全なAPIキー", "Full Base URL (supports": "完全なベースURL (サポート", "Full Code": "完全なコード", + "Full endpoint URL": "Full endpoint URL", "Functions": "関数", "GC Count": "GC 回数", "GC executed": "GC 実行完了", "GC execution failed": "GC 実行失敗", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.": "アダプターが無効になっていても、Geminiは思考モードを自動検出します。価格設定と予算編成をより細かく制御する必要がある場合にのみ、これを有効にしてください。", "General": "一般", @@ -1779,7 +1837,9 @@ "ID": "ID", "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.": "アップストリームエラーにこれらのキーワードのいずれかが含まれている場合 (大文字と小文字を区別しない)、チャネルは自動的に無効になります。", "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.": "認証が成功すると、生成されたJSONがキー欄に挿入されます。保存するにはチャンネルを保存してください。", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing": "上流の One API または New API リレープロジェクトに接続する場合、知っている場合を除き OpenAI タイプを使用してください", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "アフィニティチャネルが失敗し、別のチャネルでリトライが成功した場合、アフィニティを成功したチャネルに更新します。", "Ignored upstream models": "無視する上流モデル", "Image": "画像", @@ -1792,7 +1852,10 @@ "Image to Video": "画像から動画", "Image Tokens": "画像トークン", "Import to CC Switch": "CC Switch にインポート", + "Important": "Important", "In Progress": "処理中", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "In:": "入力:", "Include Group": "グループを含む", "Include Model": "モデルを含む", @@ -1811,13 +1874,17 @@ "Input tokens": "入力トークン", "Input Tokens": "入力トークン", "Inspect user prompts": "ユーザープロンプトの検査", + "Install Claude Code": "Install Claude Code", "Instance": "インスタンス", + "Integration": "Integration", + "Integration guides": "Integration guides", "Integrations": "統合", "Inter-group overrides": "グループ間上書き", "Inter-group ratio overrides": "グループ間比率上書き", + "Interactive login": "Interactive login", + "Interface Language": "インターフェース言語", "Internal Notes": "内部メモ", "Internal notes (not shown to users)": ":内部メモ(ユーザーには表示されません)", - "Interface Language": "インターフェース言語", "Internal Server Error!": "内部サーバーエラー!", "Invalid chat link. Please contact the administrator.": "無効なチャットリンクです。管理者に連絡してください。", "Invalid chat link. Please contact your administrator.": "無効なチャットリンクです。管理者に連絡してください。", @@ -1828,6 +1895,7 @@ "Invalid JSON in parameter override template": "パラメータオーバーライドテンプレートのJSONが無効です", "Invalid JSON string.": "無効な JSON 文字列です。", "Invalid model mapping format": "無効なモデルマッピング形式", + "Invalid month": "月が無効です", "Invalid Passkey registration response": "無効なパスキー登録応答", "Invalid Passkey response": "無効なパスキー応答", "Invalid payment redirect URL": "無効な支払いリダイレクトURL", @@ -1835,6 +1903,7 @@ "Invalid reset link, please request a new password reset.": "無効なリセットリンクです。新しいパスワードリセットをリクエストしてください。", "Invalid rules JSON format": "ルール JSON の形式が不正です", "Invalid status code mapping entries: {{entries}}": "無効なステータスコードマッピング:{{entries}}", + "Invalid year": "年が無効です", "Invalidate": "無効化", "Invalidated": "無効化済み", "Invert match": "一致を反転", @@ -1894,8 +1963,8 @@ "Kling": "Kling", "Knowledge Base ID *": "ナレッジベースID *", "Landing page with system overview.": "システム概要付きランディングページ。", - "Language Preferences": "言語設定", "Language preference saved": "言語設定を保存しました", + "Language Preferences": "言語設定", "Language preferences sync across your signed-in devices and affect API error messages.": "言語設定はログイン中のすべてのデバイスで同期され、API のエラーメッセージ言語にも反映されます。", "Last check time": "最終チェック時刻", "Last detected addable models": "最後に検出された追加可能モデル", @@ -1905,7 +1974,9 @@ "Last updated:": "最終更新日:", "Last Used": "最終使用", "Last used:": "最終使用日:", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", "Layout": "レイアウト", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Learn more": "詳細はこちら", "Learn more:": "詳細はこちら:", "Leave": "退出", @@ -1928,6 +1999,7 @@ "Less": "少ない", "Less Than": "より小さい", "Less Than or Equal": "以下", + "Lifetime channel usage": "Lifetime channel usage", "Light": "ライト", "Lightning Fast": "超高速", "Limit period": "制限期間", @@ -1999,6 +2071,7 @@ "Manage your API keys for accessing the service": "サービスにアクセスするためのAPIキーを管理する", "Manage your balance and payment methods": "残高と支払い方法を管理する", "Manage your security settings and account access": "セキュリティ設定とアカウントアクセスを管理する", + "Manual configuration": "Manual configuration", "Manual Disabled": "手動無効", "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).": "ユーザー情報レスポンスのフィールドをローカルユーザー属性にマッピングします。ネストされたパスをサポートします (例: ocs.data.id)。", "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.": "モデル識別子をGemini APIバージョンにマッピングします。特定の一致が見つからない場合は、`default`エントリが適用されます。", @@ -2125,6 +2198,7 @@ "Monitor": "モニタリング", "Monitoring & Alerts": "監視とアラート", "Month": "月", + "Month range uses server local time unless a timezone is set.": "未指定の場合はサーバーのローカル時間で暦月を区切ります。IANAタイムゾーンを指定すると、そのタイムゾーンの暦月で区切ります。", "Monthly": "毎月", "months": "ヶ月", "Moonshot": "Moonshot", @@ -2337,6 +2411,7 @@ "Not Submitted": "未送信", "Not tested": "未テスト", "Not used yet": "未使用", + "Note": "Note", "Notice": "通知", "Notification Email": "通知メール", "Notification Method": "通知方法", @@ -2400,13 +2475,18 @@ "Open Source": "オープンソース", "Open the io.net console API Keys page": "io.netコンソールAPIキーページを開く", "Open theme settings": "テーマ設定を開く", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", "OpenAI Compatible": "OpenAI互換", "OpenAI Organization": "OpenAI組織", "OpenAI Organization ID (optional)": "OpenAI 組織 ID (オプション)", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAI, Anthropic, etc.": "OpenAI、Anthropicなど", "OpenAI, Anthropic, Google, etc.": "OpenAI、Anthropic、Googleなど", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opened authorization page": "認証ページを開きました", "OpenRouter": "OpenRouter", "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "外部クライアントで開きます。サイドバーまたはAPIキーアクションからトリガーして、設定されたアプリケーションを起動します。", @@ -2617,6 +2697,8 @@ "Please try again later.": "後でもう一度お試しください。", "Please upload key file(s)": "キーファイルをアップロードしてください", "Please wait a moment, human check is initializing...": "しばらくお待ちください、人間チェックを初期化中です...", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "Policy JSON": "ポリシーJSON", "Polling": "ポーリング", "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded": "ポーリングモードにはRedisとメモリキャッシュが必要です。そうでない場合、パフォーマンスが大幅に低下します", @@ -2627,6 +2709,7 @@ "PostgreSQL detected": "PostgreSQLが検出されました", "PostgreSQL offers advanced reliability and data integrity for production workloads.": "PostgreSQL は本番ワークロード向けの高度な信頼性とデータ整合性を提供します。", "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.": "PostgreSQLは強力な信頼性保証を提供します。本番稼働する前に、メンテナンスウィンドウと保持ポリシーを再確認してください。", + "Powered by": "Powered by", "Powerful API Management Platform": "強力なAPI管理プラットフォーム", "Pre-Consume for Free Models": "無料モデルの事前消費", "Pre-consumed": "事前消費", @@ -2660,7 +2743,6 @@ "Previous": "前へ", "Previous branch": "前のブランチ", "Previous page": "前のページ", - "Base Price": "基本価格", "Price": "価格", "Price ($/1K calls)": "価格($/1K 回)", "Price (local currency / USD)": "価格 (現地通貨 / USD)", @@ -2848,6 +2930,7 @@ "Registry username": "レジストリ ユーザー名", "Reject Reason": "拒否理由", "Release details": "リリース詳細", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Relying Party Display Name": "依拠当事者表示名", "Relying Party ID": "依拠当事者ID", "Remaining": "残り", @@ -2998,8 +3081,11 @@ "Rules": "ルール", "Rules JSON": "ルール JSON", "Rules JSON must be an array": "ルール JSON は配列である必要があります", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", "Run GC": "GC 実行", "Run tests for the selected models": "選択したモデルのテストを実行", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "Running": "実行中", "s": "s", "Safety Settings": "安全設定", @@ -3111,8 +3197,8 @@ "Select groups (leave empty to keep current)": "グループを選択 (現在の設定を維持するには空のままにしてください)", "Select items...": "項目を選択...", "Select key format": "キーフォーマットを選択", - "Select Language": "言語を選択", "Select language": "言語を選択", + "Select Language": "言語を選択", "Select layout style": "レイアウトスタイルを選択", "Select locations": "ロケーションを選択", "Select Model": "モデルを選択", @@ -3176,20 +3262,25 @@ "Set quota amount and limits": "クォータ量と制限を設定", "Set Request Header": "リクエストヘッダーを設定", "Set runtime request header: override entire value, or manipulate comma-separated tokens": "ランタイムリクエストヘッダーを設定:値全体を上書き、またはカンマ区切りトークンを操作", - "Set the language used across the interface": "インターフェースで使用する言語を設定します", "Set Tag": "タグを設定", "Set tag for selected channels": "選択したチャネルにタグを設定", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the language used across the interface": "インターフェースで使用する言語を設定します", + "Set the messages endpoint to:": "Set the messages endpoint to:", "Set the user's role (cannot be Root)": "ユーザーのロールを設定します(Rootにはできません)", + "Set your API key": "Set your API key", "Setting saved": "設定が保存されました", "Setting up 2FA...": "2FAを設定中...", "Setting updated successfully": "設定が正常に更新されました", "Settings": "設定", "Settings & Preferences": "設定と環境設定", "Settings updated successfully": "設定が正常に更新されました", + "settings.json (optional)": "settings.json (optional)", "Setup Instructions": "セットアップ手順", "Setup Two-Factor Authentication": "2要素認証を設定", "Share your link and earn rewards": "リンクを共有して報酬を獲得", "Shared configuration for all payment gateways": "すべての決済ゲートウェイの共有設定", + "Shell environment": "Shell environment", "Shorten": "短縮", "Show": "表示", "Show All": "すべて表示", @@ -3256,6 +3347,7 @@ "Standard": "標準", "Start": "開始", "Start a conversation to see messages here": "会話を開始すると、ここにメッセージが表示されます", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Start for free with generous limits. No credit card required.": "豊富な無料枠で始められます。クレジットカードは不要です。", "Start Time": "開始時間", "Static page describing the platform.": "プラットフォームを説明する静的ページ。", @@ -3487,7 +3579,9 @@ "Timed cache (1h)": "有効期限付きキャッシュ(1h)", "Timeline": "タイムライン", "times": "回", + "Timezone (IANA, optional)": "タイムゾーン(IANA、任意)", "Timing": "所要時間", + "Tip": "Tip", "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.": "ヒント:生成されたキーは access_token / refresh_token / account_id を含むJSON認証情報です。", "to access this resource.": "このリソースにアクセスするには。", "to confirm": "確認する", @@ -3550,15 +3644,19 @@ "Total invitation revenue": "招待による総収益", "Total Log Size": "ログ合計サイズ", "Total Quota": "合計クォータ", + "Total requests": "Total requests", "Total requests allowed per period. 0 = unlimited.": "期間ごとに許可されるリクエストの総数。0 = 無制限。", "Total requests made": "合計リクエスト数", + "Total tokens": "Total tokens", "Total Tokens": "合計トークン", "Total Usage": "総使用量", "Total:": "合計:", "TPM": "TPM", + "Trace (Trae IDE)": "Trace (Trae IDE)", "Track per-request consumption to power usage analytics. Keeping this on increases database writes.": "リクエストごとの消費を追跡し、使用状況分析に利用します。これをオンにすると、データベースへの書き込みが増加します。", "Track usage, costs and performance with real-time analytics": "リアルタイム分析で使用量、コスト、パフォーマンスを追跡", "Tracks current account base limits and additional metered usage on Codex upstream.": "Codex 上でのアカウント基礎枠と追加従量の利用量を表示します。", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "Transfer": "振替", "Transfer Amount": "振替金額", "Transfer failed": "転送に失敗しました", @@ -3683,7 +3781,11 @@ "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.": "生体認証またはセキュリティキーを備えた互換性のあるブラウザまたはデバイスを使用して、パスキーを登録してください。", "Use authenticator code": "認証コードを使用", "Use backup code": "バックアップコードを使用", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", "Use disk cache when request body exceeds this size": "リクエストボディがこのサイズを超えた場合にディスクキャッシュを使用", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Use our unified OpenAI-compatible endpoint in your applications": "アプリケーションでOpenAI互換の統一エンドポイントを使用", "Use Passkey to sign in without entering your password.": "パスワードを入力せずにサインインするには、パスキーを使用してください。", "Use secure connection when sending emails": "メール送信時に安全な接続を使用する", @@ -3778,6 +3880,7 @@ "View detailed information about this user including balance, usage statistics, and invitation details.": "残高、使用統計、招待の詳細など、このユーザーに関する詳細情報を表示します。", "View details": "詳細を表示", "View document": "ドキュメントを表示", + "View guide": "View guide", "View logs": "ログを表示", "View mode": "表示モード", "View model call count analytics and charts": "モデル呼び出し回数の分析とグラフを表示", @@ -3870,6 +3973,8 @@ "whsec_xxx": "whsec_xxx", "Window:": "ウィンドウ:", "with conflicts": "競合あり", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Without additional conditions, only the type above is used for pruning.": "追加条件がない場合、上記のtypeのみが削除に使用されます。", "Worker Access Key": "Workerアクセスキー", "Worker Proxy": "Workerプロキシ", @@ -3880,6 +3985,7 @@ "xAI": "xAI", "Xinference": "Xinference", "Xunfei": "Xunfei", + "Year": "年", "years": "年", "You are about to delete {{count}} API key(s).": "{{count}}個のAPIキーを削除しようとしています。", "You are running the latest version ({{version}}).": "最新バージョン ({{version}}) を使用中です。", @@ -3889,6 +3995,7 @@ "You don't have necessary permission": "必要な権限がありません", "You have unsaved changes": "未保存の変更があります", "You have unsaved changes. Are you sure you want to leave?": "未保存の変更があります。離れてもよろしいですか?", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", "You Pay": "お支払い額", "You save": "節約額", "You will be redirected to Telegram to complete the binding process.": "バインドプロセスを完了するためにTelegramにリダイレクトされます。", @@ -3899,6 +4006,7 @@ "Your Cloudflare Account ID": "あなたのCloudflareアカウントID", "Your Discord OAuth Client ID": "Discord OAuth クライアント ID", "Your Discord OAuth Client Secret": "Discord OAuth クライアント シークレット", + "Your FaceCloud API key": "Your FaceCloud API key", "Your GitHub OAuth Client ID": "あなたのGitHub OAuthクライアントID", "Your GitHub OAuth Client Secret": "あなたのGitHub OAuthクライアントシークレット", "Your new backup codes are ready": "新しいバックアップコードの準備ができました", diff --git a/web/default/src/i18n/locales/ru.json b/web/default/src/i18n/locales/ru.json index 9aa4991a097e..1c187e01ef04 100644 --- a/web/default/src/i18n/locales/ru.json +++ b/web/default/src/i18n/locales/ru.json @@ -15,6 +15,7 @@ "(Optional: redirect model names)": "(Необязательно: перенаправить имена моделей)", "(Override all channels' groups)": "(Переопределить группы всех каналов)", "(Override all channels' models)": "(Переопределить модели всех каналов)", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\"original-model\": \"replacement-model\"}", @@ -109,6 +110,7 @@ "Actual Model:": "Фактическая модель:", "Add": "Добавить", "Add {{title}}": "Добавить {{title}}", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", "Add a group identifier to the auto assignment list.": "Добавить идентификатор группы в список автоматического назначения.", "Add a new API key by providing necessary info.": "Добавьте новый API-ключ, предоставив необходимую информацию.", "Add a new channel by providing the necessary information.": "Добавьте новый канал, предоставив необходимую информацию.", @@ -127,6 +129,8 @@ "Add custom model(s), comma-separated": "Добавить пользовательскую модель(и), через запятую", "Add discount tier": "Добавить уровень скидки", "Add each model or tag you want to include.": "Добавьте каждую модель или тег, который хотите включить.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", "Add FAQ": "Добавить вопрос-ответ", "Add from available models...": "Добавить из доступных моделей...", "Add Funds": "Добавить средства", @@ -156,6 +160,9 @@ "Add selectable group": "Добавить выбираемую группу", "Add subscription": "Добавить подписку", "Add tags...": "Добавить теги...", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "Add tier": "Добавить уровень", "Add time condition": "Добавить условие по времени", "Add time rule group": "Добавить группу правил по времени", @@ -256,6 +263,7 @@ "Allowed Origins": "Разрешенные Origins", "Allowed Ports": "Разрешенные порты", "Already have an account?": "Уже есть аккаунт?", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", "Always matches (default tier).": "Всегда совпадает (уровень по умолчанию).", "Amount": "Сумма", "Amount cannot be changed when editing.": "Количество нельзя изменить при редактировании.", @@ -268,6 +276,7 @@ "Amount to pay:": "Сумма к оплате:", "An unexpected error occurred": "Произошла непредвиденная ошибка", "and": "и", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Announcement added. Click \"Save Settings\" to apply.": "Объявление добавлено. Нажмите \"Сохранить настройки\", чтобы применить.", "Announcement content": "Содержимое объявления", "Announcement deleted. Click \"Save Settings\" to apply.": "Объявление удалено. Нажмите \"Сохранить настройки\", чтобы применить.", @@ -278,6 +287,7 @@ "Announcements saved successfully": "Объявления успешно сохранены", "Answer": "Ответ", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "Any Match (OR)": "Любое совпадение (OR)", "API Access": "Доступ к API", "API Addresses": "Адреса API", @@ -327,6 +337,7 @@ "Apply IP Filter to Resolved Domains": "Применить IP-фильтр к разрешенным доменам", "Apply Overwrite": "Применить перезапись", "Apply Sync": "Применить синхронизацию", + "Apply user filter": "Apply user filter", "Applying...": "Применение...", "Approx.": "Примерно.", "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.": "также перечислены здесь. Удалите их из Моделей, чтобы ответ `/v1/models` был удобным для пользователя и скрывал имена, специфичные для поставщиков.", @@ -428,6 +439,7 @@ "Base amount. Actual deduction = base amount × system group rate.": "Базовая сумма. Фактический вычет = базовая сумма × коэффициент группы.", "Base Limits": "Базовые лимиты", "Base multipliers applied when users select specific groups.": "Базовые множители, применяемые, когда пользователи выбирают определенные группы.", + "Base Price": "Базовая цена", "Base rate limit windows for this account.": "Окна базовых лимитов для этого аккаунта.", "Base URL": "Адрес API", "Base URL of your Uptime Kuma instance": "Базовый URL вашего экземпляра Uptime Kuma", @@ -447,6 +459,7 @@ "Batch enable failed": "Пакетное включение не удалось", "Batch processing failed": "Пакетная обработка не удалась", "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Пакетное обновление моделей: {{channels}} каналов, {{added}} добавлено, {{removed}} удалено, {{fails}} ошибок", + "Before you start": "Before you start", "Best for single-tenant deployments. Pricing and billing options stay hidden.": "Лучший вариант для однопользовательских развёртываний. Опции ценообразования и биллинга будут скрыты.", "Billing": "Биллинг", "Billing currency": "Валюта оплаты", @@ -485,7 +498,6 @@ "Broadcast a global banner to users. Markdown is supported.": "Транслировать глобальный баннер пользователям. Поддерживается Markdown.", "Broadcast short system notices on the dashboard": "Транслировать короткие системные уведомления на панели управления", "Browse and compare": "Просмотр и сравнение", - "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Откройте для себя подобранные AI-модели, сравнивайте цены и возможности и выбирайте подходящую модель для каждого сценария.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.": "Бюджетные токены = макс. токены × соотношение. Принимает десятичное число от 0.002 до 1. Рекомендуется поддерживать в соответствии с биллингом вышестоящего провайдера.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.": "Бюджетные токены = макс. токены × соотношение. Принимает десятичное число от 0.1 до 1.", "Budget Tokens Ratio": "Соотношение бюджетных токенов", @@ -544,6 +556,7 @@ "Channel Affinity": "Привязка к каналу", "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "Привязка к каналу повторно использует последний успешный канал на основе ключей, извлечённых из контекста запроса или тела JSON.", "Channel Affinity: Upstream Cache Hit": "Привязка к каналу: попадание в кэш upstream", + "Channel Consumption": "Channel Consumption", "Channel copied successfully": "Канал успешно скопирован", "Channel created successfully": "Канал успешно создан", "Channel deleted successfully": "Канал успешно удалён", @@ -608,6 +621,8 @@ "Classic (Legacy Frontend)": "Классический (Старый интерфейс)", "Claude": "Клод", "Claude CLI Header Passthrough": "Проброс заголовков Claude CLI", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Clean history logs": "Очистить журналы истории", "Clean logs": "Очистить логи", "Clean up inactive cache": "Очистить неактивный кэш", @@ -628,6 +643,7 @@ "Clear search": "Очистить поиск", "Clear selection": "Снять выделение", "Clear selection (Escape)": "Снять выделение (Escape)", + "Clear user filter": "Clear user filter", "Cleared": "Очищено", "Cleared all models": "Все модели очищены", "Click \"Create Plan\" to create your first subscription plan": "Нажмите «Создать план», чтобы создать первый план подписки", @@ -655,12 +671,15 @@ "CNY": "Юань", "CNY per USD": "CNY за USD", "Code": "Код", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", "Codes copied!": "Коды скопированы!", "Codex": "Codex", "Codex Account & Usage": "Аккаунт и использование Codex", "Codex Authorization": "Авторизация Codex", "Codex channels use an OAuth JSON credential as the key.": "Каналы Codex используют учётные данные OAuth в формате JSON в качестве ключа.", "Codex CLI Header Passthrough": "Проброс заголовков Codex CLI", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", "Collapse": "Свернуть", "Collapse All": "Свернуть все", @@ -701,6 +720,7 @@ "Configuration for Creem payment integration": "Конфигурация для интеграции платежей Creem", "Configuration for Epay payment integration": "Конфигурация для интеграции платежей Epay", "Configuration for Stripe payment integration": "Конфигурация для интеграции платежей Stripe", + "Configuration reference": "Configuration reference", "Configuration required": "Требуется настройка", "Configure": "Настройка", "Configure a Creem product for user recharge options.": "Настройте продукт Creem для опций пополнения пользователя.", @@ -715,17 +735,22 @@ "Configure available payment methods. Provide a JSON array.": "Настроить доступные способы оплаты. Предоставьте JSON-массив.", "Configure basic system information and branding": "Настроить основную информацию о системе и брендинг", "Configure channel affinity (sticky routing) rules": "Настроить правила привязки к каналу (липкая маршрутизация)", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", "Configure Creem products. Provide a JSON array.": "Настройте продукты Creem. Укажите массив JSON.", "Configure custom OAuth providers for user authentication": "Настройка пользовательских OAuth-провайдеров для аутентификации пользователей", "Configure daily check-in rewards for users": "Настроить ежедневные награды за регистрацию для пользователей", "Configure discount rates based on recharge amounts": "Настроить скидки в зависимости от сумм пополнения", + "Configure environment": "Configure environment", "Configure experimental data export for the dashboard": "Настроить экспериментальный экспорт данных для панели управления", + "Configure FaceCloud": "Configure FaceCloud", "Configure Gemini safety behavior, version overrides, and thinking adapter": "Настроить поведение безопасности Gemini, переопределения версий и адаптер мышления", "Configure in your Creem dashboard": "Настройте в панели управления Creem", "Configure io.net API key for model deployments": "Настройте API-ключ io.net для развертывания моделей", "Configure keyword filtering for prompts and responses.": "Настроить фильтрацию по ключевым словам для запросов и ответов.", "Configure model, caching, and group ratios used for billing": "Настроить модель, кэширование и групповые коэффициенты, используемые для выставления счетов", "Configure monitoring status page groups for the dashboard": "Настроить группы страниц состояния мониторинга для панели управления", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", "Configure outgoing email server for notifications": "Настроить исходящий почтовый сервер для уведомлений", "Configure Passkey (WebAuthn) login settings": "Настроить настройки входа с помощью ключа доступа (WebAuthn)", "Configure password-based login and registration": "Настроить вход и регистрацию по паролю", @@ -739,6 +764,8 @@ "Configure system-wide behavior and defaults": "Настроить общесистемное поведение и значения по умолчанию", "Configure the ratio for this group.": "Настроить коэффициент для этой группы.", "Configure third-party authentication providers": "Настроить сторонних поставщиков аутентификации", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", "Configure upstream providers and routing.": "Настроить провайдеров верхнего уровня и маршрутизацию.", "Configure upstream worker or proxy service for outbound requests": "Настроить вышестоящий рабочий или прокси-сервис для исходящих запросов", "Configure user quota allocation and rewards": "Настроить распределение пользовательских квот и вознаграждений", @@ -774,6 +801,8 @@ "Confirm your identity with Two-factor Authentication before registering a Passkey.": "Подтвердите свою личность с помощью двухфакторной аутентификации перед регистрацией Passkey.", "Conflict": "Противоречие", "Connect": "Подключение", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", "Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Подключайтесь через OpenAI, Claude, Gemini и другие совместимые API-маршруты", "Connected to io.net service normally.": "Соединение с сервисом io.net установлено.", "Connection error": "Ошибка соединения", @@ -871,6 +900,7 @@ "Create multiple channels from multiple keys": "Создать несколько каналов из нескольких ключей", "Create multiple redemption codes at once (1-100)": "Создать несколько кодов активации одновременно (1-100)", "Create new subscription plan": "Создать новый план подписки", + "Create or edit": "Create or edit", "Create or update frequently asked questions for users": "Создать или обновить часто задаваемые вопросы для пользователей", "Create or update system announcements for the dashboard": "Создать или обновить системные объявления для панели управления", "Create Plan": "Создать план", @@ -881,6 +911,7 @@ "Create request parameter override rules without editing raw JSON.": "Создавайте правила переопределения параметров запроса без редактирования raw JSON.", "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.": "Создавайте многократно используемые пакеты моделей, тегов, конечных точек и групп пользователей для ускорения настройки в других частях консоли.", "Create succeeded": "Успешно создано", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Create Vendor": "Создать поставщика", "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Создайте свою первую группу для повторного использования выбранных моделей, тегов или конечных точек в любом месте панели управления.", "Create, revoke, and audit API tokens.": "Создать, отозвать и аудитировать токены API.", @@ -962,6 +993,7 @@ "Default consumption chart": "График потребления по умолчанию", "Default Max Tokens": "Максимальное количество токенов по умолчанию", "Default model call chart": "График вызовов моделей по умолчанию", + "Default model name for requests": "Default model name for requests", "Default range": "Диапазон по умолчанию", "Default Responses API version, if empty, will use the API version above": "Версия API ответов по умолчанию; если пусто, будет использоваться версия API, указанная выше", "Default system prompt for this channel": "Системный промпт по умолчанию для этого канала", @@ -1059,6 +1091,8 @@ "Disabled all channels with tag: {{tag}}": "Все каналы с тегом {{tag}} отключены", "Disabled Reason": "Причина отключения", "Disabled Time": "Время отключения", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Disabling...": "Отключение...", "Discord": "Discord", "Discount": "Скидка", @@ -1069,6 +1103,7 @@ "Discount Rate:": "Ставка скидки:", "Discount ratio for cache hits.": "Коэффициент скидки для попаданий в кэш.", "Discouraged": "Не рекомендуется", + "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Откройте для себя подобранные AI-модели, сравнивайте цены и возможности и выбирайте подходящую модель для каждого сценария.", "Discovering...": "Обнаружение...", "Disk cache cleared": "Дисковый кэш очищен", "Disk Cache Settings": "Настройки дискового кэша", @@ -1106,6 +1141,7 @@ "DoubaoVideo": "DoubaoVideo", "Double check the configuration below. Your system will be locked until initialization is complete.": "Дважды проверьте конфигурацию ниже. Ваша система будет заблокирована до завершения инициализации.", "Download": "Скачать", + "Download started": "Загрузка начата", "Draw": "Рисование", "Drawing": "Рисование", "Drawing logs": "Журналы рисования", @@ -1121,6 +1157,7 @@ "e.g. ¥ or HK$": "напр. ¥ или HK$", "e.g. 401, 403, 429, 500-599": "напр. 401, 403, 429, 500-599", "e.g. 8 means 1 USD = 8 units": "напр. 8 означает 1 USD = 8 единиц", + "e.g. Asia/Shanghai": "напр. Asia/Shanghai", "e.g. Basic Plan": "напр. Базовый план", "e.g. Clean tool parameters to avoid upstream validation errors": "напр. Очистить параметры инструментов во избежание ошибок валидации", "e.g. example.com": "напр. example.com", @@ -1179,6 +1216,7 @@ "Edit model": "Редактировать модель", "Edit Model": "Редактировать модель", "Edit OAuth Provider": "Редактировать поставщика OAuth", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", "Edit payment method": "Редактировать способ оплаты", "Edit Prefill Group": "Редактировать группу предзаполнения", "Edit product": "Редактировать продукт", @@ -1254,6 +1292,7 @@ "Endpoint": "Точка доступа", "Endpoint config": "Конфигурация конечной точки", "Endpoint Configuration": "Конфигурация конечной точки", + "Endpoint reference": "Endpoint reference", "Endpoint Type": "Тип конечной точки", "Endpoint:": "Конечная точка:", "Endpoints": "Конечные точки", @@ -1333,6 +1372,7 @@ "Enterprise-grade security with comprehensive permission management": "Безопасность корпоративного уровня с комплексным управлением разрешениями", "Entrypoint (space separated)": "Точка входа (через пробелы)", "Env (JSON object)": "Env (объект JSON)", + "Environment variable holding your API key": "Environment variable holding your API key", "Environment variables": "Переменные окружения", "Environment variables (JSON)": "Переменные окружения (JSON)", "Epay endpoint": "Конечная точка Epay", @@ -1371,6 +1411,15 @@ "Expired at": "Истекает", "Expired time cannot be earlier than current time": "Время истечения срока действия не может быть раньше текущего времени", "Expires": "Истекает", + "Export completed": "Export completed", + "Export consumption details": "Экспорт детализации расходов", + "Export failed": "Ошибка экспорта", + "Export logs": "Export logs", + "Export monthly bill": "Экспорт месячного счёта", + "Export monthly bill and consumption details": "Экспорт месячного счёта и детализации расходов", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Export usage CSV": "Экспорт использования (CSV)", + "Export usage CSV for user {{name}} (ID {{id}})": "Экспорт CSV использования для пользователя {{name}} (ID {{id}})", "Expose grouped Uptime Kuma status pages directly on the dashboard": "Отображать сгруппированные страницы статуса Uptime Kuma непосредственно на панели управления", "Expose ratio API": "Интерфейс экспонирования коэффициента", "Exposes the pricing/models catalog in the top navigation.": "Отображает каталог цен/моделей в верхней навигации.", @@ -1388,6 +1437,9 @@ "External Speed Test": "Внешний тест скорости", "Extra": "Дополнительно", "Extra Notes (Optional)": "Дополнительные примечания (необязательно)", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "Fail Reason": "Причина сбоя", "Fail Reason Details": "Детали причины сбоя", "Failed": "Неудача", @@ -1450,6 +1502,7 @@ "Failed to load": "Не удалось загрузить", "Failed to load API keys": "Не удалось загрузить API ключи", "Failed to load billing history": "Не удалось загрузить историю платежей", + "Failed to load consumption": "Failed to load consumption", "Failed to load home page content": "Не удалось загрузить содержимое главной страницы", "Failed to load image": "Не удалось загрузить изображение", "Failed to load logs": "Не удалось загрузить логи", @@ -1557,6 +1610,7 @@ "Filter by request ID": "Фильтр по ID запроса", "Filter by task ID": "Фильтр по ID задачи", "Filter by token name": "Фильтр по имени токена", + "Filter by user (optional)": "Filter by user (optional)", "Filter by username": "Фильтр по имени пользователя", "Filter by username, name or email...": "Фильтр по имени пользователя, имени или email...", "Filter Dashboard Models": "Фильтровать модели панели управления", @@ -1595,6 +1649,8 @@ "footer.defaultCopyright": "Все права защищены.", "footer.new\u0061pi.projectAttributionSuffix": "Все права защищены. Разработано участниками проекта.", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "Для каналов, добавленных после 10 мая 2025 г., не нужно удалять \".\" из имён моделей при развёртывании", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", "For private deployments, format: https://fastgpt.run/api/openapi": "Для частных развертываний, формат: https://fastgpt.run/api/openapi", "Force AUTH LOGIN": "Принудительный AUTH LOGIN", "Force Format": "Принудительный формат", @@ -1623,11 +1679,13 @@ "Full API Key": "Полный ключ API", "Full Base URL (supports": "Полный базовый URL (поддерживает", "Full Code": "Полный код", + "Full endpoint URL": "Full endpoint URL", "Functions": "Функции", "GC Count": "Кол-во GC", "GC executed": "GC выполнен", "GC execution failed": "Ошибка выполнения GC", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.": "Gemini продолжит автоматически определять режим мышления, даже если адаптер отключен. Включайте это только тогда, когда вам нужен более тонкий контроль над ценообразованием и бюджетированием.", "General": "Общие", @@ -1779,7 +1837,9 @@ "ID": "ID", "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.": "Если ошибка вышестоящего уровня содержит любое из этих ключевых слов (без учета регистра), канал будет автоматически отключен.", "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.": "При успешной авторизации сгенерированный JSON будет вставлен в поле ключа. Сохраните канал, чтобы применить изменения.", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing": "При подключении к upstream One API или проектам-ретрансляторам New API используйте тип OpenAI, если только вы точно знаете, что делаете", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "Если привязанный канал не работает и повторная попытка удалась через другой канал, привязка обновляется на успешный канал.", "Ignored upstream models": "Игнорируемые upstream-модели", "Image": "Изображение", @@ -1792,7 +1852,10 @@ "Image to Video": "Изображение в видео", "Image Tokens": "Токены изображений", "Import to CC Switch": "Импорт в CC Switch", + "Important": "Important", "In Progress": "Выполняется", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "In:": "Вх:", "Include Group": "Включить группу", "Include Model": "Включить модель", @@ -1811,13 +1874,17 @@ "Input tokens": "Входные токены", "Input Tokens": "Входные токены", "Inspect user prompts": "Просмотр запросов пользователя", + "Install Claude Code": "Install Claude Code", "Instance": "Экземпляр", + "Integration": "Integration", + "Integration guides": "Integration guides", "Integrations": "Интеграции", "Inter-group overrides": "Переопределения между группами", "Inter-group ratio overrides": "Переопределения соотношений между группами", + "Interactive login": "Interactive login", + "Interface Language": "Язык интерфейса", "Internal Notes": "Внутренние заметки", "Internal notes (not shown to users)": "Внутренние заметки (не показываются пользователям)", - "Interface Language": "Язык интерфейса", "Internal Server Error!": "Внутренняя ошибка сервера!", "Invalid chat link. Please contact the administrator.": "Неверная ссылка на чат. Пожалуйста, обратитесь к администратору.", "Invalid chat link. Please contact your administrator.": "Недействительная ссылка чата. Обратитесь к администратору.", @@ -1828,6 +1895,7 @@ "Invalid JSON in parameter override template": "Недопустимый JSON в шаблоне переопределения параметров", "Invalid JSON string.": "Недопустимая строка JSON.", "Invalid model mapping format": "Неверный формат сопоставления моделей", + "Invalid month": "Некорректный месяц", "Invalid Passkey registration response": "Неверный ответ на регистрацию Passkey", "Invalid Passkey response": "Недопустимый ответ Passkey", "Invalid payment redirect URL": "Недопустимый URL перенаправления для оплаты", @@ -1835,6 +1903,7 @@ "Invalid reset link, please request a new password reset.": "Недействительная ссылка для сброса, пожалуйста, запросите новый сброс пароля.", "Invalid rules JSON format": "Неверный формат JSON правил", "Invalid status code mapping entries: {{entries}}": "Недопустимые записи маппинга кодов состояния: {{entries}}", + "Invalid year": "Некорректный год", "Invalidate": "Аннулировать", "Invalidated": "Аннулирована", "Invert match": "Инвертировать совпадение", @@ -1894,8 +1963,8 @@ "Kling": "Kling", "Knowledge Base ID *": "ID базы знаний *", "Landing page with system overview.": "Главная страница с обзором системы.", - "Language Preferences": "Языковые настройки", "Language preference saved": "Языковая настройка сохранена", + "Language Preferences": "Языковые настройки", "Language preferences sync across your signed-in devices and affect API error messages.": "Языковые настройки синхронизируются на всех ваших устройствах после входа и влияют на язык сообщений об ошибках API.", "Last check time": "Время последней проверки", "Last detected addable models": "Последние обнаруженные модели для добавления", @@ -1905,7 +1974,9 @@ "Last updated:": "Последнее обновление:", "Last Used": "Последнее использование", "Last used:": "Последнее использование:", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", "Layout": "Макет", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Learn more": "Узнать больше", "Learn more:": "Узнать больше:", "Leave": "Выйти", @@ -1928,6 +1999,7 @@ "Less": "Меньше", "Less Than": "Меньше", "Less Than or Equal": "Меньше или равно", + "Lifetime channel usage": "Lifetime channel usage", "Light": "Светлая", "Lightning Fast": "Молниеносно быстро", "Limit period": "Период ограничения", @@ -1999,6 +2071,7 @@ "Manage your API keys for accessing the service": "Управление ключами API для доступа к сервису", "Manage your balance and payment methods": "Управление балансом и способами оплаты", "Manage your security settings and account access": "Управление настройками безопасности и доступом к аккаунту", + "Manual configuration": "Manual configuration", "Manual Disabled": "Ручное отключение", "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).": "Сопоставление полей из ответа информации о пользователе с локальными атрибутами пользователя. Поддерживает вложенные пути (например, ocs.data.id).", "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.": "Сопоставьте идентификаторы моделей с версиями Gemini API. Запись `default` применяется, если не найдено конкретного совпадения.", @@ -2125,6 +2198,7 @@ "Monitor": "Мониторинг", "Monitoring & Alerts": "Мониторинг и оповещения", "Month": "Месяц", + "Month range uses server local time unless a timezone is set.": "Если часовой пояс не указан, границы календарного месяца берутся по локальному времени сервера; при указании IANA — по этому поясу.", "Monthly": "Ежемесячно", "months": "месяцев", "Moonshot": "Moonshot", @@ -2337,6 +2411,7 @@ "Not Submitted": "Не отправлено", "Not tested": "Не протестировано", "Not used yet": "Ещё не использовано", + "Note": "Note", "Notice": "Уведомления", "Notification Email": "Электронная почта для уведомлений", "Notification Method": "Метод уведомления", @@ -2400,13 +2475,18 @@ "Open Source": "Открытый исходный код", "Open the io.net console API Keys page": "Открыть страницу ключей API консоли io.net", "Open theme settings": "Открыть настройки темы", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", "OpenAI Compatible": "Совместимо с OpenAI", "OpenAI Organization": "Организация OpenAI", "OpenAI Organization ID (optional)": "Идентификатор организации OpenAI (необязательно)", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAI, Anthropic, etc.": "OpenAI, Anthropic и т.д.", "OpenAI, Anthropic, Google, etc.": "OpenAI, Anthropic, Google и т.д.", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opened authorization page": "Страница авторизации открыта", "OpenRouter": "OpenRouter", "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "открывается во внешнем клиенте. Запустите его из боковой панели или действий с ключом API, чтобы запустить настроенное приложение.", @@ -2617,6 +2697,8 @@ "Please try again later.": "Пожалуйста, попробуйте еще раз позже.", "Please upload key file(s)": "Загрузите ключевой файл(ы)", "Please wait a moment, human check is initializing...": "Пожалуйста, подождите немного, инициализация проверки человеком...", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "Policy JSON": "JSON политики", "Polling": "Опрос", "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded": "Режим опроса требует Redis и кэш памяти, в противном случае производительность будет значительно снижена", @@ -2627,6 +2709,7 @@ "PostgreSQL detected": "PostgreSQL обнаружен", "PostgreSQL offers advanced reliability and data integrity for production workloads.": "PostgreSQL обеспечивает высокую надёжность и целостность данных для продакшен-нагрузок.", "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.": "PostgreSQL предлагает надежные гарантии. Дважды проверьте окно обслуживания и политики хранения данных перед запуском.", + "Powered by": "Powered by", "Powerful API Management Platform": "Мощная платформа управления API", "Pre-Consume for Free Models": "Предварительное потребление для бесплатных моделей", "Pre-consumed": "Предоплата", @@ -2660,7 +2743,6 @@ "Previous": "Предыдущий шаг", "Previous branch": "Предыдущая ветка", "Previous page": "Предыдущая страница", - "Base Price": "Базовая цена", "Price": "Цена", "Price ($/1K calls)": "Цена ($/1K вызовов)", "Price (local currency / USD)": "Цена (местная валюта / USD)", @@ -2848,6 +2930,7 @@ "Registry username": "Имя пользователя реестра", "Reject Reason": "Причина отклонения", "Release details": "Детали релиза", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Relying Party Display Name": "Отображаемое имя проверяющей стороны", "Relying Party ID": "Идентификатор проверяющей стороны", "Remaining": "Остаток", @@ -2998,8 +3081,11 @@ "Rules": "Правила", "Rules JSON": "Правила JSON", "Rules JSON must be an array": "JSON правил должен быть массивом", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", "Run GC": "Запустить GC", "Run tests for the selected models": "Запустить тесты для выбранных моделей", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "Running": "Выполняется", "s": "s", "Safety Settings": "Настройки безопасности", @@ -3111,8 +3197,8 @@ "Select groups (leave empty to keep current)": "Выбрать группы (оставьте пустым, чтобы сохранить текущие)", "Select items...": "Выберите элементы...", "Select key format": "Выберите формат ключа", - "Select Language": "Выбрать язык", "Select language": "Выберите язык", + "Select Language": "Выбрать язык", "Select layout style": "Выбрать стиль макета", "Select locations": "Выбрать локации", "Select Model": "Выбрать модель", @@ -3176,20 +3262,25 @@ "Set quota amount and limits": "Настройте квоту и лимиты", "Set Request Header": "Установить заголовок запроса", "Set runtime request header: override entire value, or manipulate comma-separated tokens": "Установить заголовок запроса: переопределить значение или управлять токенами через запятую", - "Set the language used across the interface": "Настроить язык интерфейса", "Set Tag": "Установить тег", "Set tag for selected channels": "Установить тег для выбранных каналов", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the language used across the interface": "Настроить язык интерфейса", + "Set the messages endpoint to:": "Set the messages endpoint to:", "Set the user's role (cannot be Root)": "Установить роль пользователя (не может быть Root)", + "Set your API key": "Set your API key", "Setting saved": "Настройка сохранена", "Setting up 2FA...": "Настройка 2FA...", "Setting updated successfully": "Настройка успешно обновлена", "Settings": "Настройки", "Settings & Preferences": "Настройки и предпочтения", "Settings updated successfully": "Настройки успешно обновлены", + "settings.json (optional)": "settings.json (optional)", "Setup Instructions": "Инструкции по настройке", "Setup Two-Factor Authentication": "Настроить двухфакторную аутентификацию", "Share your link and earn rewards": "Поделитесь своей ссылкой и получайте вознаграждения", "Shared configuration for all payment gateways": "Общая конфигурация для всех платежных шлюзов", + "Shell environment": "Shell environment", "Shorten": "Сократить", "Show": "Показать", "Show All": "Показать все", @@ -3256,6 +3347,7 @@ "Standard": "Стандартный", "Start": "Начало", "Start a conversation to see messages here": "Начните разговор, чтобы увидеть сообщения здесь", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Start for free with generous limits. No credit card required.": "Начните бесплатно с щедрыми лимитами. Кредитная карта не требуется.", "Start Time": "Время начала", "Static page describing the platform.": "Статическая страница, описывающая платформу.", @@ -3487,7 +3579,9 @@ "Timed cache (1h)": "Кэш с TTL (1 ч)", "Timeline": "Хронология", "times": "раз", + "Timezone (IANA, optional)": "Часовой пояс (IANA, необязательно)", "Timing": "Время", + "Tip": "Tip", "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.": "Подсказка: сгенерированный ключ — это учётные данные JSON с access_token / refresh_token / account_id.", "to access this resource.": "для доступа к этому ресурсу.", "to confirm": "для подтверждения", @@ -3550,15 +3644,19 @@ "Total invitation revenue": "Общий доход от приглашений", "Total Log Size": "Общий размер журналов", "Total Quota": "Общая квота", + "Total requests": "Total requests", "Total requests allowed per period. 0 = unlimited.": "Общее количество запросов, разрешенных за период. 0 = без ограничений.", "Total requests made": "Всего сделанных запросов", + "Total tokens": "Total tokens", "Total Tokens": "Всего токенов", "Total Usage": "Общее использование", "Total:": "Всего:", "TPM": "TPM", + "Trace (Trae IDE)": "Trace (Trae IDE)", "Track per-request consumption to power usage analytics. Keeping this on increases database writes.": "Отслеживать потребление для каждого запроса для аналитики использования. Сохранение этой опции увеличивает количество записей в базу данных.", "Track usage, costs and performance with real-time analytics": "Отслеживайте использование, затраты и производительность с помощью аналитики в реальном времени", "Tracks current account base limits and additional metered usage on Codex upstream.": "Отслеживает базовые лимиты и дополнительное потребление (metered) аккаунта на стороне Codex.", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "Transfer": "Перевод", "Transfer Amount": "Сумма перевода", "Transfer failed": "Перевод не удался", @@ -3683,7 +3781,11 @@ "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.": "Используйте совместимый браузер или устройство с биометрической аутентификацией или ключ безопасности для регистрации ключа доступа.", "Use authenticator code": "Использовать код аутентификатора", "Use backup code": "Использовать резервный код", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", "Use disk cache when request body exceeds this size": "Использовать дисковый кэш, когда тело запроса превышает этот размер", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Use our unified OpenAI-compatible endpoint in your applications": "Используйте наш единый OpenAI-совместимый эндпоинт в ваших приложениях", "Use Passkey to sign in without entering your password.": "Используйте ключ доступа для входа без ввода пароля.", "Use secure connection when sending emails": "Использовать безопасное соединение при отправке электронных писем", @@ -3778,6 +3880,7 @@ "View detailed information about this user including balance, usage statistics, and invitation details.": "Просмотр подробной информации об этом пользователе, включая баланс, статистику использования и данные приглашения.", "View details": "Просмотреть детали", "View document": "Просмотреть документ", + "View guide": "View guide", "View logs": "Просмотреть логи", "View mode": "Режим отображения", "View model call count analytics and charts": "Просмотр аналитики и графиков количества вызовов моделей", @@ -3870,6 +3973,8 @@ "whsec_xxx": "whsec_xxx", "Window:": "Окно:", "with conflicts": "с конфликтами", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Without additional conditions, only the type above is used for pruning.": "Без дополнительных условий для очистки используется только тип выше.", "Worker Access Key": "Ключ доступа воркера", "Worker Proxy": "Прокси воркера", @@ -3880,6 +3985,7 @@ "xAI": "xAI", "Xinference": "Xinference", "Xunfei": "Xunfei", + "Year": "Год", "years": "лет", "You are about to delete {{count}} API key(s).": "Вы собираетесь удалить {{count}} API-ключ(а/ей).", "You are running the latest version ({{version}}).": "Вы используете последнюю версию ({{version}}).", @@ -3889,6 +3995,7 @@ "You don't have necessary permission": "У вас нет необходимых разрешений", "You have unsaved changes": "У вас есть несохранённые изменения", "You have unsaved changes. Are you sure you want to leave?": "У вас есть несохранённые изменения. Вы уверены, что хотите уйти?", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", "You Pay": "Вы платите", "You save": "Вы экономите", "You will be redirected to Telegram to complete the binding process.": "Вы будете перенаправлены в Telegram для завершения процесса привязки.", @@ -3899,6 +4006,7 @@ "Your Cloudflare Account ID": "Ваш ID аккаунта Cloudflare", "Your Discord OAuth Client ID": "Ваш Discord OAuth Client ID", "Your Discord OAuth Client Secret": "Ваш Discord OAuth Client Secret", + "Your FaceCloud API key": "Your FaceCloud API key", "Your GitHub OAuth Client ID": "Ваш ID клиента GitHub OAuth", "Your GitHub OAuth Client Secret": "Ваш секрет клиента GitHub OAuth", "Your new backup codes are ready": "Ваши новые резервные коды готовы", diff --git a/web/default/src/i18n/locales/vi.json b/web/default/src/i18n/locales/vi.json index 194864dcab3c..bf4c2aa2aa22 100644 --- a/web/default/src/i18n/locales/vi.json +++ b/web/default/src/i18n/locales/vi.json @@ -15,6 +15,7 @@ "(Optional: redirect model names)": "(Tùy chọn: chuyển hướng tên mô hình)", "(Override all channels' groups)": "(Ghi đè các nhóm của tất cả các kênh)", "(Override all channels' models)": "(Ghi đè các mô hình của tất cả các kênh)", + ") and choose a model name available on your account.": ") and choose a model name available on your account.", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"Alipay\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\"original-model\": \"replacement-model\"}", @@ -109,6 +110,7 @@ "Actual Model:": "Mô hình thực tế:", "Add": "Add", "Add {{title}}": "Thêm {{title}}", + "Add a custom Anthropic provider or Claude model in Trae settings.": "Add a custom Anthropic provider or Claude model in Trae settings.", "Add a group identifier to the auto assignment list.": "Thêm một mã định danh nhóm vào danh sách phân công tự động.", "Add a new API key by providing necessary info.": "Thêm khóa API mới bằng cách cung cấp thông tin cần thiết.", "Add a new channel by providing the necessary information.": "Thêm kênh mới bằng cách cung cấp thông tin cần thiết.", @@ -127,6 +129,8 @@ "Add custom model(s), comma-separated": "Thêm mô hình tùy chỉnh, phân tách bằng dấu phẩy", "Add discount tier": "Thêm bậc giảm giá", "Add each model or tag you want to include.": "Thêm mỗi mô hình hoặc thẻ bạn muốn đưa vào.", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.", + "Add FaceCloud as a custom provider in OpenCode configuration.": "Add FaceCloud as a custom provider in OpenCode configuration.", "Add FAQ": "Thêm FAQ", "Add from available models...": "Thêm từ các mô hình có sẵn...", "Add Funds": "Thêm Tiền", @@ -156,6 +160,9 @@ "Add selectable group": "Thêm nhóm có thể chọn", "Add subscription": "Thêm đăng ký", "Add tags...": "Thêm thẻ...", + "Add the FaceCloud provider configuration:": "Add the FaceCloud provider configuration:", + "Add the following environment variables:": "Add the following environment variables:", + "Add the following variables:": "Add the following variables:", "Add tier": "Thêm bậc", "Add time condition": "Thêm điều kiện thời gian", "Add time rule group": "Thêm nhóm quy tắc theo thời gian", @@ -256,6 +263,7 @@ "Allowed Origins": "Nguồn gốc được phép", "Allowed Ports": "Cổng được phép", "Already have an account?": "Đã có tài khoản?", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.", "Always matches (default tier).": "Luôn khớp (bậc mặc định).", "Amount": "Số lượng", "Amount cannot be changed when editing.": "Số tiền không thể thay đổi khi chỉnh sửa.", @@ -268,6 +276,7 @@ "Amount to pay:": "Amount due:", "An unexpected error occurred": "Đã xảy ra lỗi không mong muốn", "and": "and", + "and your-model-name with your API key and desired model.": "and your-model-name with your API key and desired model.", "Announcement added. Click \"Save Settings\" to apply.": "Đã thêm thông báo. Nhấp \"Save Settings\" để áp dụng.", "Announcement content": "Nội dung thông báo", "Announcement deleted. Click \"Save Settings\" to apply.": "Đã xóa thông báo. Nhấp \"Save Settings\" để áp dụng.", @@ -278,6 +287,7 @@ "Announcements saved successfully": "Đã lưu thông báo thành công", "Answer": "Trả lời", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic-compatible models", "Any Match (OR)": "Bất kỳ khớp (OR)", "API Access": "Truy cập API", "API Addresses": "Địa chỉ API", @@ -327,6 +337,7 @@ "Apply IP Filter to Resolved Domains": "Áp dụng Bộ lọc IP cho Tên miền đã phân giải", "Apply Overwrite": "Áp dụng Ghi đè", "Apply Sync": "Áp dụng đồng bộ", + "Apply user filter": "Apply user filter", "Applying...": "Đang áp dụng...", "Approx.": "Xấp xỉ.", "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.": "cũng được liệt kê ở đây. Xóa chúng khỏi Models để giữ cho phản hồi `/v1/models` thân thiện với người dùng và ẩn các tên dành riêng cho nhà cung cấp.", @@ -428,6 +439,7 @@ "Base amount. Actual deduction = base amount × system group rate.": "Số tiền cơ sở. Số tiền trừ thực tế = số tiền cơ sở × tỷ lệ nhóm hệ thống.", "Base Limits": "Giới hạn cơ bản", "Base multipliers applied when users select specific groups.": "Hệ số nhân cơ bản được áp dụng khi người dùng chọn các nhóm cụ thể.", + "Base Price": "Giá cơ bản", "Base rate limit windows for this account.": "Cửa sổ giới hạn tốc độ cơ bản cho tài khoản này.", "Base URL": "URL cơ sở", "Base URL of your Uptime Kuma instance": "URL cơ sở của phiên bản Uptime Kuma của bạn", @@ -447,6 +459,7 @@ "Batch enable failed": "Kích hoạt hàng loạt thất bại", "Batch processing failed": "Xử lý hàng loạt thất bại", "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "Đã áp dụng cập nhật hàng loạt mô hình upstream: {{channels}} kênh, {{added}} đã thêm, {{removed}} đã xóa, {{fails}} thất bại", + "Before you start": "Before you start", "Best for single-tenant deployments. Pricing and billing options stay hidden.": "Phù hợp nhất cho triển khai đơn người dùng. Các tùy chọn giá và thanh toán sẽ được ẩn.", "Billing": "Thanh toán", "Billing currency": "Loại tiền thanh toán", @@ -485,7 +498,6 @@ "Broadcast a global banner to users. Markdown is supported.": "Phát một biểu ngữ toàn cầu đến người dùng. Hỗ trợ Markdown.", "Broadcast short system notices on the dashboard": "Phát các thông báo hệ thống ngắn trên bảng điều khiển", "Browse and compare": "Duyệt và so sánh", - "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Khám phá các mô hình AI được tuyển chọn, so sánh giá và khả năng, rồi chọn mô hình phù hợp cho từng kịch bản.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.": "Số token ngân sách = số token tối đa × tỷ lệ. Chấp nhận một số thập phân từ 0.002 đến 1. Khuyến nghị nên giữ cho phù hợp với cách tính phí của nhà cung cấp.", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.": "Số token ngân sách = số token tối đa × tỷ lệ. Chấp nhận một số thập phân từ 0.1 đến 1.", "Budget Tokens Ratio": "Tỷ lệ Mã thông báo Ngân sách", @@ -544,6 +556,7 @@ "Channel Affinity": "Ưu tiên kênh", "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "Ưu tiên kênh sẽ sử dụng lại kênh thành công gần nhất dựa trên các khóa được trích xuất từ ngữ cảnh yêu cầu hoặc JSON body.", "Channel Affinity: Upstream Cache Hit": "Ưu tiên kênh: Cache hit từ upstream", + "Channel Consumption": "Channel Consumption", "Channel copied successfully": "Sao chép kênh thành công", "Channel created successfully": "Tạo kênh thành công", "Channel deleted successfully": "Xóa kênh thành công", @@ -608,6 +621,8 @@ "Classic (Legacy Frontend)": "Cổ điển (Frontend cũ)", "Claude": "Claude", "Claude CLI Header Passthrough": "Chuyển tiếp header Claude CLI", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.", "Clean history logs": "Xóa nhật ký lịch sử", "Clean logs": "Dọn dẹp nhật ký", "Clean up inactive cache": "Dọn dẹp bộ nhớ đệm không hoạt động", @@ -628,6 +643,7 @@ "Clear search": "Xóa tìm kiếm", "Clear selection": "Bỏ chọn", "Clear selection (Escape)": "Bỏ chọn (Escape)", + "Clear user filter": "Clear user filter", "Cleared": "Đã xóa", "Cleared all models": "Đã xóa tất cả các mô hình", "Click \"Create Plan\" to create your first subscription plan": "Nhấp \"Tạo gói\" để tạo gói đăng ký đầu tiên", @@ -655,12 +671,15 @@ "CNY": "CNY", "CNY per USD": "CNY trên USD", "Code": "Mã", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.", "Codes copied!": "Đã sao chép mã!", "Codex": "Codex", "Codex Account & Usage": "Tài khoản và sử dụng Codex", "Codex Authorization": "Ủy quyền Codex", "Codex channels use an OAuth JSON credential as the key.": "Kênh Codex dùng thông tin xác thực OAuth JSON làm khóa.", "Codex CLI Header Passthrough": "Chuyển tiếp header Codex CLI", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.", "Cohere": "Cohere", "Collapse": "Thu gọn", "Collapse All": "Thu gọn tất cả", @@ -701,6 +720,7 @@ "Configuration for Creem payment integration": "Cấu hình tích hợp thanh toán Creem", "Configuration for Epay payment integration": "Cấu hình cho tích hợp thanh toán Epay", "Configuration for Stripe payment integration": "Cấu hình cho tích hợp thanh toán Stripe", + "Configuration reference": "Configuration reference", "Configuration required": "Cần cấu hình", "Configure": "Cấu hình", "Configure a Creem product for user recharge options.": "Cấu hình một sản phẩm Creem cho các tùy chọn nạp tiền người dùng.", @@ -715,17 +735,22 @@ "Configure available payment methods. Provide a JSON array.": "Cấu hình các phương thức thanh toán khả dụng. Cung cấp một mảng JSON.", "Configure basic system information and branding": "Cấu hình thông tin hệ thống cơ bản và nhận diện thương hiệu", "Configure channel affinity (sticky routing) rules": "Cấu hình quy tắc ưu tiên kênh (định tuyến dính)", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.", + "Configure Codex": "Configure Codex", "Configure Creem products. Provide a JSON array.": "Cấu hình sản phẩm Creem. Cung cấp một mảng JSON.", "Configure custom OAuth providers for user authentication": "Cấu hình nhà cung cấp OAuth tùy chỉnh cho xác thực người dùng", "Configure daily check-in rewards for users": "Cấu hình phần thưởng điểm danh hàng ngày cho người dùng", "Configure discount rates based on recharge amounts": "Cấu hình tỷ lệ chiết khấu dựa trên số tiền nạp", + "Configure environment": "Configure environment", "Configure experimental data export for the dashboard": "Cấu hình xuất dữ liệu thử nghiệm cho bảng điều khiển", + "Configure FaceCloud": "Configure FaceCloud", "Configure Gemini safety behavior, version overrides, and thinking adapter": "Cấu hình hành vi an toàn Gemini, ghi đè phiên bản và bộ điều hợp tư duy", "Configure in your Creem dashboard": "Cấu hình trong bảng điều khiển Creem của bạn", "Configure io.net API key for model deployments": "Cấu hình khóa API io.net cho triển khai mô hình", "Configure keyword filtering for prompts and responses.": "Định cấu hình lọc từ khóa để xem lời nhắc và câu trả lời.", "Configure model, caching, and group ratios used for billing": "Cấu hình mô hình, bộ nhớ đệm và tỷ lệ nhóm được sử dụng để tính phí.", "Configure monitoring status page groups for the dashboard": "Cấu hình các nhóm trang trạng thái giám sát cho bảng điều khiển", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.", "Configure outgoing email server for notifications": "Cấu hình máy chủ email gửi đi cho thông báo", "Configure Passkey (WebAuthn) login settings": "Cấu hình cài đặt đăng nhập Passkey (WebAuthn)", "Configure password-based login and registration": "Cấu hình đăng nhập và đăng ký dựa trên mật khẩu", @@ -739,6 +764,8 @@ "Configure system-wide behavior and defaults": "Cấu hình hành vi và mặc định toàn hệ thống", "Configure the ratio for this group.": "Cấu hình tỷ lệ cho nhóm này.", "Configure third-party authentication providers": "Cấu hình nhà cung cấp xác thực bên thứ ba", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.", "Configure upstream providers and routing.": "Cấu hình nhà cung cấp upstream và định tuyến.", "Configure upstream worker or proxy service for outbound requests": "Cấu hình worker thượng nguồn hoặc dịch vụ proxy cho các yêu cầu đi", "Configure user quota allocation and rewards": "Cấu hình phân bổ hạn ngạch người dùng và phần thưởng", @@ -774,6 +801,8 @@ "Confirm your identity with Two-factor Authentication before registering a Passkey.": "Hãy xác minh danh tính bằng Xác thực hai yếu tố trước khi đăng ký Passkey.", "Conflict": "Xung đột", "Connect": "Kết nối", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.", "Connect through OpenAI, Claude, Gemini, and other compatible API routes": "Kết nối qua OpenAI, Claude, Gemini và các tuyến API tương thích khác", "Connected to io.net service normally.": "Đã kết nối bình thường tới dịch vụ io.net.", "Connection error": "Lỗi kết nối", @@ -871,6 +900,7 @@ "Create multiple channels from multiple keys": "Tạo nhiều kênh từ nhiều khóa", "Create multiple redemption codes at once (1-100)": "Tạo nhiều mã đổi thưởng cùng lúc (1-100)", "Create new subscription plan": "Tạo gói đăng ký mới", + "Create or edit": "Create or edit", "Create or update frequently asked questions for users": "Tạo hoặc cập nhật các câu hỏi thường gặp cho người dùng", "Create or update system announcements for the dashboard": "Tạo hoặc cập nhật thông báo hệ thống cho bảng điều khiển", "Create Plan": "Tạo gói", @@ -881,6 +911,7 @@ "Create request parameter override rules without editing raw JSON.": "Tạo quy tắc ghi đè tham số yêu cầu mà không cần sửa JSON thô.", "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.": "Tạo các gói có thể tái sử dụng gồm các mô hình, thẻ, điểm cuối và nhóm người dùng để tăng tốc cấu hình ở những nơi khác trong bảng điều khiển.", "Create succeeded": "Tạo thành công", + "Create the config directory if it does not exist:": "Create the config directory if it does not exist:", "Create Vendor": "Tạo Nhà cung cấp", "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "Tạo nhóm đầu tiên của bạn để dùng lại các lựa chọn mô hình, thẻ hoặc điểm cuối ở bất cứ đâu trên bảng điều khiển.", "Create, revoke, and audit API tokens.": "Tạo, thu hồi và kiểm toán token API.", @@ -962,6 +993,7 @@ "Default consumption chart": "Biểu đồ tiêu thụ mặc định", "Default Max Tokens": "Tokens Tối đa Mặc định", "Default model call chart": "Biểu đồ lượt gọi mô hình mặc định", + "Default model name for requests": "Default model name for requests", "Default range": "Khoảng mặc định", "Default Responses API version, if empty, will use the API version above": "Phiên bản API phản hồi mặc định, nếu để trống, sẽ sử dụng phiên bản API ở trên", "Default system prompt for this channel": "Lời nhắc hệ thống mặc định cho kênh này", @@ -1059,6 +1091,8 @@ "Disabled all channels with tag: {{tag}}": "Đã tắt tất cả kênh với nhãn: {{tag}}", "Disabled Reason": "Lý do vô hiệu hóa", "Disabled Time": "Thời gian vô hiệu hóa", + "Disables attribution header when using a proxy": "Disables attribution header when using a proxy", + "Disables experimental beta headers for third-party gateways": "Disables experimental beta headers for third-party gateways", "Disabling...": "Đang vô hiệu hóa...", "Discord": "Discord", "Discount": "Giảm giá", @@ -1069,6 +1103,7 @@ "Discount Rate:": "Tỷ lệ chiết khấu:", "Discount ratio for cache hits.": "Tỷ lệ chiết khấu cho lượt truy cập bộ nhớ đệm thành công.", "Discouraged": "Tuyệt vọng", + "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "Khám phá các mô hình AI được tuyển chọn, so sánh giá và khả năng, rồi chọn mô hình phù hợp cho từng kịch bản.", "Discovering...": "Đang khám phá...", "Disk cache cleared": "Đã xóa bộ nhớ đệm đĩa", "Disk Cache Settings": "Cài đặt bộ nhớ đệm đĩa", @@ -1106,6 +1141,7 @@ "DoubaoVideo": "DoubaoVideo", "Double check the configuration below. Your system will be locked until initialization is complete.": "Kiểm tra kỹ lại cấu hình bên dưới. Hệ thống của bạn sẽ bị khóa cho đến khi quá trình khởi tạo hoàn tất.", "Download": "Tải xuống", + "Download started": "Đã bắt đầu tải xuống", "Draw": "Vẽ", "Drawing": "Vẽ", "Drawing logs": "Nhật ký vẽ", @@ -1121,6 +1157,7 @@ "e.g. ¥ or HK$": "ví dụ ¥ hoặc HK$", "e.g. 401, 403, 429, 500-599": "vd. 401, 403, 429, 500-599", "e.g. 8 means 1 USD = 8 units": "Ví dụ: 8 có nghĩa là 1 USD = 8 đơn vị", + "e.g. Asia/Shanghai": "ví dụ Asia/Shanghai", "e.g. Basic Plan": "ví dụ: Gói cơ bản", "e.g. Clean tool parameters to avoid upstream validation errors": "ví dụ: Dọn dẹp tham số công cụ để tránh lỗi xác thực upstream", "e.g. example.com": "ví dụ example.com", @@ -1179,6 +1216,7 @@ "Edit model": "Chỉnh sửa mô hình", "Edit Model": "Chỉnh sửa Mô hình", "Edit OAuth Provider": "Chỉnh Sửa Nhà Cung Cấp OAuth", + "Edit opencode.json with the FaceCloud provider:": "Edit opencode.json with the FaceCloud provider:", "Edit payment method": "Sửa phương thức thanh toán", "Edit Prefill Group": "Chỉnh sửa Nhóm Điền sẵn", "Edit product": "Chỉnh sửa sản phẩm", @@ -1254,6 +1292,7 @@ "Endpoint": "Endpoint", "Endpoint config": "Cấu hình điểm cuối", "Endpoint Configuration": "Cấu hình điểm cuối", + "Endpoint reference": "Endpoint reference", "Endpoint Type": "Loại điểm cuối", "Endpoint:": "Điểm cuối:", "Endpoints": "Điểm cuối", @@ -1333,6 +1372,7 @@ "Enterprise-grade security with comprehensive permission management": "Bảo mật cấp doanh nghiệp với quản lý quyền toàn diện", "Entrypoint (space separated)": "Entrypoint (cách nhau bằng dấu cách)", "Env (JSON object)": "Env (đối tượng JSON)", + "Environment variable holding your API key": "Environment variable holding your API key", "Environment variables": "Biến môi trường", "Environment variables (JSON)": "Biến môi trường (JSON)", "Epay endpoint": "Epay điểm cuối", @@ -1371,6 +1411,15 @@ "Expired at": "Hết hạn lúc", "Expired time cannot be earlier than current time": "Thời gian hết hạn không thể sớm hơn thời gian hiện tại", "Expires": "Hết hạn", + "Export completed": "Export completed", + "Export consumption details": "Xuất chi tiết tiêu thụ", + "Export failed": "Xuất thất bại", + "Export logs": "Export logs", + "Export monthly bill": "Xuất hóa đơn tháng", + "Export monthly bill and consumption details": "Xuất hóa đơn tháng và chi tiết tiêu thụ", + "Export the following variables in your terminal or shell profile:": "Export the following variables in your terminal or shell profile:", + "Export usage CSV": "Xuất CSV sử dụng", + "Export usage CSV for user {{name}} (ID {{id}})": "Xuất CSV sử dụng cho người dùng {{name}} (ID {{id}})", "Expose grouped Uptime Kuma status pages directly on the dashboard": "Hiển thị các trang trạng thái Uptime Kuma đã nhóm trực tiếp trên bảng điều khiển", "Expose ratio API": "Cung cấp API tỷ lệ", "Exposes the pricing/models catalog in the top navigation.": "Hiển thị danh mục giá/mô hình trên thanh điều hướng đầu trang.", @@ -1388,6 +1437,9 @@ "External Speed Test": "Kiểm tra tốc độ bên ngoài", "Extra": "Thêm", "Extra Notes (Optional)": "Ghi chú bổ sung (Tùy chọn)", + "FaceCloud gateway URL": "FaceCloud gateway URL", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini-compatible base URL", + "FaceCloud Integration Guides": "FaceCloud Integration Guides", "Fail Reason": "Lý do thất bại", "Fail Reason Details": "Chi tiết lý do thất bại", "Failed": "Thất bại", @@ -1450,6 +1502,7 @@ "Failed to load": "Tải thất bại", "Failed to load API keys": "Không thể tải khóa API", "Failed to load billing history": "Không thể tải lịch sử thanh toán", + "Failed to load consumption": "Failed to load consumption", "Failed to load home page content": "Không thể tải nội dung trang chủ", "Failed to load image": "Không thể tải ảnh", "Failed to load logs": "Không tải được nhật ký", @@ -1557,6 +1610,7 @@ "Filter by request ID": "Lọc theo ID yêu cầu", "Filter by task ID": "Lọc theo ID nhiệm vụ", "Filter by token name": "Lọc theo tên token", + "Filter by user (optional)": "Filter by user (optional)", "Filter by username": "Lọc theo tên người dùng", "Filter by username, name or email...": "Lọc theo tên người dùng, tên hoặc email...", "Filter Dashboard Models": "Lọc Mô hình Bảng điều khiển", @@ -1595,6 +1649,8 @@ "footer.defaultCopyright": "Bản quyền được bảo lưu.", "footer.new\u0061pi.projectAttributionSuffix": "Bản quyền được bảo lưu. Được thiết kế và phát triển bởi các cộng tác viên dự án.", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "Đối với các kênh được thêm sau ngày 10 tháng 5 năm 2025, không cần loại bỏ \".\" khỏi tên mô hình trong quá trình triển khai", + "For model availability and pricing, visit the pricing page or dashboard.": "For model availability and pricing, visit the pricing page or dashboard.", + "For OpenAI-compatible models, set the request URL to:": "For OpenAI-compatible models, set the request URL to:", "For private deployments, format: https://fastgpt.run/api/openapi": "Đối với các triển khai riêng tư, định dạng: https://fastgpt.run/api/openapi", "Force AUTH LOGIN": "Bắt buộc AUTH LOGIN", "Force Format": "Buộc định dạng", @@ -1623,11 +1679,13 @@ "Full API Key": "Khóa API đầy đủ", "Full Base URL (supports": "URL cơ sở đầy đủ (hỗ trợ", "Full Code": "Mã đầy đủ", + "Full endpoint URL": "Full endpoint URL", "Functions": "Hàm", "GC Count": "Số lần GC", "GC executed": "GC đã thực thi", "GC execution failed": "Thực thi GC thất bại", "Gemini": "Song Tử", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.", "Gemini Image 4K": "Gemini Image 4K", "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.": "Gemini sẽ tiếp tục tự động phát hiện chế độ suy nghĩ ngay cả khi bộ điều hợp bị tắt. Chỉ bật tính năng này khi bạn cần kiểm soát chi tiết hơn về giá cả và lập ngân sách.", "General": "Chung", @@ -1779,7 +1837,9 @@ "ID": "ID", "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.": "Nếu một lỗi thượng nguồn chứa bất kỳ từ khóa nào trong số này (không phân biệt chữ hoa chữ thường), kênh sẽ tự động bị vô hiệu hóa.", "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.": "Nếu ủy quyền thành công, JSON tạo ra sẽ được chèn vào trường khóa. Bạn vẫn cần lưu kênh để áp dụng.", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:", "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing": "Nếu kết nối với dự án relay One API hoặc New API upstream, hãy sử dụng loại OpenAI thay thế trừ khi bạn biết mình đang làm gì", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.", "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "Nếu kênh ưu tiên thất bại và thử lại thành công trên kênh khác, cập nhật ưu tiên sang kênh thành công.", "Ignored upstream models": "Mô hình upstream bị bỏ qua", "Image": "Hình ảnh", @@ -1792,7 +1852,10 @@ "Image to Video": "Ảnh sang video", "Image Tokens": "Token hình ảnh", "Import to CC Switch": "Nhập vào CC Switch", + "Important": "Important", "In Progress": "Đang xử lý", + "in the examples below with your real key. API base URL:": "in the examples below with your real key. API base URL:", + "in your home directory.": "in your home directory.", "In:": "Vào:", "Include Group": "Bao gồm nhóm", "Include Model": "Bao gồm mô hình", @@ -1811,13 +1874,17 @@ "Input tokens": "Token đầu vào", "Input Tokens": "Token đầu vào", "Inspect user prompts": "Kiểm tra lời nhắc của người dùng", + "Install Claude Code": "Install Claude Code", "Instance": "Phiên bản", + "Integration": "Integration", + "Integration guides": "Integration guides", "Integrations": "Tích hợp", "Inter-group overrides": "Ghi đè liên nhóm", "Inter-group ratio overrides": "Tỷ lệ liên nhóm ghi đè", + "Interactive login": "Interactive login", + "Interface Language": "Ngôn ngữ giao diện", "Internal Notes": "Ghi chú nội bộ", "Internal notes (not shown to users)": "Ghi chú nội bộ (không hiển thị cho người dùng)", - "Interface Language": "Ngôn ngữ giao diện", "Internal Server Error!": "Lỗi máy chủ nội bộ!", "Invalid chat link. Please contact the administrator.": "Liên kết trò chuyện không hợp lệ. Vui lòng liên hệ quản trị viên.", "Invalid chat link. Please contact your administrator.": "Liên kết trò chuyện không hợp lệ. Vui lòng liên hệ với quản trị viên của bạn.", @@ -1828,6 +1895,7 @@ "Invalid JSON in parameter override template": "JSON không hợp lệ trong mẫu ghi đè tham số", "Invalid JSON string.": "Chuỗi JSON không hợp lệ.", "Invalid model mapping format": "Định dạng ánh xạ mô hình không hợp lệ", + "Invalid month": "Tháng không hợp lệ", "Invalid Passkey registration response": "Phản hồi đăng ký Passkey không hợp lệ", "Invalid Passkey response": "Phản hồi Passkey không hợp lệ", "Invalid payment redirect URL": "URL chuyển hướng thanh toán không hợp lệ", @@ -1835,6 +1903,7 @@ "Invalid reset link, please request a new password reset.": "Liên kết đặt lại không hợp lệ, vui lòng yêu cầu đặt lại mật khẩu mới.", "Invalid rules JSON format": "Định dạng JSON quy tắc không hợp lệ", "Invalid status code mapping entries: {{entries}}": "Mục ánh xạ mã trạng thái không hợp lệ: {{entries}}", + "Invalid year": "Năm không hợp lệ", "Invalidate": "Vô hiệu hóa", "Invalidated": "Đã vô hiệu", "Invert match": "Đảo điều kiện khớp", @@ -1894,8 +1963,8 @@ "Kling": "Kling", "Knowledge Base ID *": "Mã số Cơ sở kiến thức *", "Landing page with system overview.": "Trang chủ với tổng quan hệ thống.", - "Language Preferences": "Tùy chọn ngôn ngữ", "Language preference saved": "Đã lưu tùy chọn ngôn ngữ", + "Language Preferences": "Tùy chọn ngôn ngữ", "Language preferences sync across your signed-in devices and affect API error messages.": "Tùy chọn ngôn ngữ sẽ đồng bộ trên các thiết bị đã đăng nhập và ảnh hưởng đến ngôn ngữ thông báo lỗi API.", "Last check time": "Thời gian kiểm tra gần nhất", "Last detected addable models": "Mô hình có thể thêm được phát hiện gần nhất", @@ -1905,7 +1974,9 @@ "Last updated:": "Cập nhật lần cuối:", "Last Used": "Dùng lần cuối", "Last used:": "Lần cuối sử dụng:", + "Launch OpenCode and verify that requests route through FaceCloud.": "Launch OpenCode and verify that requests route through FaceCloud.", "Layout": "Bố cục", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.", "Learn more": "Tìm hiểu thêm", "Learn more:": "Tìm hiểu thêm:", "Leave": "Rời khỏi", @@ -1928,6 +1999,7 @@ "Less": "Ít hơn", "Less Than": "Nhỏ hơn", "Less Than or Equal": "Nhỏ hơn hoặc bằng", + "Lifetime channel usage": "Lifetime channel usage", "Light": "Ánh sáng", "Lightning Fast": "Nhanh như chớp", "Limit period": "Thời hiệu", @@ -1999,6 +2071,7 @@ "Manage your API keys for accessing the service": "Quản lý các khóa API của bạn để truy cập dịch vụ", "Manage your balance and payment methods": "Quản lý số dư và phương thức thanh toán của bạn", "Manage your security settings and account access": "Quản lý cài đặt bảo mật và quyền truy cập tài khoản của bạn", + "Manual configuration": "Manual configuration", "Manual Disabled": "Vô hiệu hóa thủ công", "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).": "Ánh xạ các trường từ phản hồi thông tin người dùng sang thuộc tính người dùng cục bộ. Hỗ trợ đường dẫn lồng nhau (ví dụ: ocs.data.id).", "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.": "Ánh xạ các mã định danh mô hình với các phiên bản API Gemini. Một mục `default` áp dụng khi không tìm thấy kết quả khớp cụ thể nào.", @@ -2125,6 +2198,7 @@ "Monitor": "Giám sát", "Monitoring & Alerts": "Giám sát & Cảnh báo", "Month": "Tháng", + "Month range uses server local time unless a timezone is set.": "Nếu không nhập múi giờ, phạ vi tháng dương lịch theo giờ cục bộ của máy chủ; nếu nhập IANA thì theo múi giờ đó.", "Monthly": "Hàng tháng", "months": "tháng", "Moonshot": "Dự án táo bạo", @@ -2337,6 +2411,7 @@ "Not Submitted": "Chưa gửi", "Not tested": "Chưa kiểm tra", "Not used yet": "Chưa sử dụng", + "Note": "Note", "Notice": "Thông báo", "Notification Email": "Email thông báo", "Notification Method": "Phương thức thông báo", @@ -2400,13 +2475,18 @@ "Open Source": "Mã nguồn mở", "Open the io.net console API Keys page": "Mở trang Khóa API của console io.net", "Open theme settings": "Mở cài đặt giao diện", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.", "OpenAI": "OpenAI", "OpenAI Compatible": "Tương thích OpenAI", "OpenAI Organization": "Tổ chức OpenAI", "OpenAI Organization ID (optional)": "ID Tổ chức OpenAI (tùy chọn)", + "OpenAI-compatible base URL at {{url}}": "OpenAI-compatible base URL at {{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI-compatible endpoint at {{url}}", + "OpenAI-compatible models": "OpenAI-compatible models", "OpenAI, Anthropic, etc.": "OpenAI, Anthropic, v.v.", "OpenAI, Anthropic, Google, etc.": "OpenAI, Anthropic, Google, v.v.", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.", "Opened authorization page": "Đã mở trang ủy quyền", "OpenRouter": "OpenRouter", "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "mở trong một ứng dụng bên ngoài. Kích hoạt nó từ thanh bên hoặc các hành động khóa API để khởi chạy ứng dụng đã cấu hình.", @@ -2617,6 +2697,8 @@ "Please try again later.": "Vui lòng thử lại sau.", "Please upload key file(s)": "Vui lòng tải lên (các) tệp khóa", "Please wait a moment, human check is initializing...": "Vui lòng đợi một chút, kiểm tra con người đang khởi tạo...", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.", "Policy JSON": "JSON chính sách", "Polling": "Thăm dò", "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded": "Chế độ thăm dò yêu cầu Redis và bộ nhớ đệm, nếu không hiệu suất sẽ bị suy giảm đáng kể.", @@ -2627,6 +2709,7 @@ "PostgreSQL detected": "Phát hiện PostgreSQL", "PostgreSQL offers advanced reliability and data integrity for production workloads.": "PostgreSQL cung cấp độ tin cậy cao và tính toàn vẹn dữ liệu cho khối lượng công việc production.", "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.": "PostgreSQL cung cấp các đảm bảo độ tin cậy cao. Hãy kiểm tra kỹ lưỡng cửa sổ bảo trì và các chính sách lưu giữ của bạn trước khi vận hành chính thức.", + "Powered by": "Powered by", "Powerful API Management Platform": "Nền tảng Quản lý API mạnh mẽ", "Pre-Consume for Free Models": "Dùng trước các mô hình miễn phí", "Pre-consumed": "Khấu trừ trước", @@ -2660,7 +2743,6 @@ "Previous": "Trước", "Previous branch": "Nhánh trước", "Previous page": "Trang trước", - "Base Price": "Giá cơ bản", "Price": "Giá", "Price ($/1K calls)": "Giá ($/1K lượt gọi)", "Price (local currency / USD)": "Giá (tiền tệ địa phương / USD)", @@ -2848,6 +2930,7 @@ "Registry username": "Tên người dùng Registry", "Reject Reason": "Lý do từ chối", "Release details": "Chi tiết phiên bản", + "Reload your shell or run source on the file after exporting the variable.": "Reload your shell or run source on the file after exporting the variable.", "Relying Party Display Name": "Tên Hiển Thị của Bên Tin Cậy", "Relying Party ID": "Định danh Bên phụ thuộc", "Remaining": "Còn lại", @@ -2998,8 +3081,11 @@ "Rules": "Quy tắc", "Rules JSON": "JSON quy tắc", "Rules JSON must be an array": "JSON quy tắc phải là một mảng", + "Run claude in a new terminal session to verify the connection.": "Run claude in a new terminal session to verify the connection.", + "Run codebuddy from the same shell session to use FaceCloud.": "Run codebuddy from the same shell session to use FaceCloud.", "Run GC": "Chạy GC", "Run tests for the selected models": "Chạy kiểm thử cho các mô hình đã chọn", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "Run the Gemini CLI and send a test prompt to confirm connectivity.", "Running": "Đang chạy", "s": "s", "Safety Settings": "Cài đặt an toàn", @@ -3111,8 +3197,8 @@ "Select groups (leave empty to keep current)": "Chọn nhóm (để trống để giữ nguyên hiện tại)", "Select items...": "Chọn các mục...", "Select key format": "Chọn định dạng khóa", - "Select Language": "Chọn Ngôn ngữ", "Select language": "Chọn ngôn ngữ", + "Select Language": "Chọn Ngôn ngữ", "Select layout style": "Chọn kiểu bố cục", "Select locations": "Chọn vị trí", "Select Model": "Chọn mẫu", @@ -3176,20 +3262,25 @@ "Set quota amount and limits": "Thiết lập hạn mức và giới hạn", "Set Request Header": "Đặt header yêu cầu", "Set runtime request header: override entire value, or manipulate comma-separated tokens": "Đặt header yêu cầu runtime: ghi đè toàn bộ giá trị hoặc thao tác token phân cách bằng dấu phẩy", - "Set the language used across the interface": "Đặt ngôn ngữ sử dụng trong giao diện", "Set Tag": "Gán Thẻ", "Set tag for selected channels": "Đặt thẻ cho các kênh đã chọn", + "Set the API key to your FaceCloud key (": "Set the API key to your FaceCloud key (", + "Set the language used across the interface": "Đặt ngôn ngữ sử dụng trong giao diện", + "Set the messages endpoint to:": "Set the messages endpoint to:", "Set the user's role (cannot be Root)": "Đặt vai trò của người dùng (không được là Root)", + "Set your API key": "Set your API key", "Setting saved": "Cài đặt đã được lưu", "Setting up 2FA...": "Đang thiết lập 2FA...", "Setting updated successfully": "Cài đặt đã được cập nhật thành công", "Settings": "Cài đặt", "Settings & Preferences": "Cài đặt & Tùy chọn", "Settings updated successfully": "Cài đặt đã được cập nhật thành công", + "settings.json (optional)": "settings.json (optional)", "Setup Instructions": "Hướng dẫn Thiết lập", "Setup Two-Factor Authentication": "Thiết lập Xác thực hai yếu tố", "Share your link and earn rewards": "Chia sẻ liên kết của bạn và kiếm phần thưởng", "Shared configuration for all payment gateways": "Cấu hình chung cho tất cả các cổng thanh toán", + "Shell environment": "Shell environment", "Shorten": "Rút gọn", "Show": "Hiển thị", "Show All": "Hiển thị tất cả", @@ -3256,6 +3347,7 @@ "Standard": "Tiêu chuẩn", "Start": "Bắt đầu", "Start a conversation to see messages here": "Bắt đầu một cuộc trò chuyện để xem tin nhắn tại đây", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.", "Start for free with generous limits. No credit card required.": "Bắt đầu miễn phí với giới hạn hào phóng. Không cần thẻ tín dụng.", "Start Time": "Thời gian bắt đầu", "Static page describing the platform.": "Trang tĩnh mô tả nền tảng.", @@ -3487,7 +3579,9 @@ "Timed cache (1h)": "Bộ đệm theo thời gian (1 giờ)", "Timeline": "Dòng thời gian", "times": "lần", + "Timezone (IANA, optional)": "Múi giờ (IANA, tùy chọn)", "Timing": "Thời gian", + "Tip": "Tip", "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.": "Mẹo: Khóa tạo ra là thông tin xác thực JSON gồm access_token / refresh_token / account_id.", "to access this resource.": "để truy cập tài nguyên này.", "to confirm": "Chờ xác nhận", @@ -3550,15 +3644,19 @@ "Total invitation revenue": "Tổng doanh thu mời", "Total Log Size": "Tổng dung lượng nhật ký", "Total Quota": "Tổng hạn mức", + "Total requests": "Total requests", "Total requests allowed per period. 0 = unlimited.": "Tổng số yêu cầu được phép mỗi kỳ. 0 = không giới hạn.", "Total requests made": "Tổng lượt yêu cầu", + "Total tokens": "Total tokens", "Total Tokens": "Tổng số token", "Total Usage": "Tổng Mức Sử dụng", "Total:": "Tổng cộng:", "TPM": "TPM", + "Trace (Trae IDE)": "Trace (Trae IDE)", "Track per-request consumption to power usage analytics. Keeping this on increases database writes.": "Theo dõi mức tiêu thụ theo từng yêu cầu để phục vụ phân tích mức độ sử dụng. Việc bật tính năng này làm tăng số lượt ghi vào cơ sở dữ liệu.", "Track usage, costs and performance with real-time analytics": "Theo dõi sử dụng, chi phí và hiệu suất với phân tích thời gian thực", "Tracks current account base limits and additional metered usage on Codex upstream.": "Theo dõi hạn cơ bản và mức dùng tính phí bổ sung của tài khoản ở phía upstream Codex.", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.", "Transfer": "Chuyển", "Transfer Amount": "Số tiền chuyển khoản", "Transfer failed": "Chuyển thất bại", @@ -3683,7 +3781,11 @@ "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.": "Sử dụng trình duyệt hoặc thiết bị tương thích có xác thực sinh trắc học hoặc khóa bảo mật để đăng ký Khóa truy cập.", "Use authenticator code": "Sử dụng mã xác thực", "Use backup code": "Sử dụng mã dự phòng", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "Use Bearer authentication with your FaceCloud API key in the Authorization header.", + "Use chat completions wire format": "Use chat completions wire format", "Use disk cache when request body exceeds this size": "Sử dụng bộ nhớ đệm đĩa khi nội dung yêu cầu vượt quá kích thước này", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.", "Use our unified OpenAI-compatible endpoint in your applications": "Sử dụng endpoint thống nhất tương thích OpenAI trong ứng dụng của bạn", "Use Passkey to sign in without entering your password.": "Sử dụng Khóa truy cập để đăng nhập mà không cần nhập mật khẩu của bạn.", "Use secure connection when sending emails": "Sử dụng kết nối an toàn khi gửi email", @@ -3778,6 +3880,7 @@ "View detailed information about this user including balance, usage statistics, and invitation details.": "Xem thông tin chi tiết về người dùng này bao gồm số dư, thống kê sử dụng và chi tiết lời mời.", "View details": "Xem chi tiết", "View document": "Xem tài liệu", + "View guide": "View guide", "View logs": "Xem nhật ký", "View mode": "Chế độ xem", "View model call count analytics and charts": "Xem phân tích và biểu đồ số lượt gọi mô hình", @@ -3870,6 +3973,8 @@ "whsec_xxx": "whsec_xxx", "Window:": "Cửa sổ:", "with conflicts": "với các xung đột", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.", + "with your FaceCloud API key.": "with your FaceCloud API key.", "Without additional conditions, only the type above is used for pruning.": "Không có điều kiện bổ sung, chỉ type ở trên được sử dụng để dọn dẹp.", "Worker Access Key": "Khóa truy cập nhân viên", "Worker Proxy": "Proxy Nhân viên", @@ -3880,6 +3985,7 @@ "xAI": "xAI", "Xinference": "Xinference", "Xunfei": "Xunfei", + "Year": "Năm", "years": "năm", "You are about to delete {{count}} API key(s).": "Bạn sắp xóa {{count}} khóa API.", "You are running the latest version ({{version}}).": "Bạn đang sử dụng phiên bản mới nhất ({{version}}).", @@ -3889,6 +3995,7 @@ "You don't have necessary permission": "Bạn không có quyền cần thiết", "You have unsaved changes": "Bạn có thay đổi chưa được lưu", "You have unsaved changes. Are you sure you want to leave?": "Bạn có thay đổi chưa được lưu. Bạn có chắc chắn muốn rời đi không?", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "You need a FaceCloud API key. Create one in the dashboard, then replace", "You Pay": "Bạn thanh toán", "You save": "Bạn tiết kiệm", "You will be redirected to Telegram to complete the binding process.": "Bạn sẽ được chuyển hướng đến Telegram để hoàn tất quá trình liên kết.", @@ -3899,6 +4006,7 @@ "Your Cloudflare Account ID": "ID tài khoản Cloudflare của bạn", "Your Discord OAuth Client ID": "Discord OAuth Client ID của bạn", "Your Discord OAuth Client Secret": "Discord OAuth Client Secret của bạn", + "Your FaceCloud API key": "Your FaceCloud API key", "Your GitHub OAuth Client ID": "Client ID OAuth GitHub của bạn", "Your GitHub OAuth Client Secret": "Bí mật ứng dụng OAuth của GitHub của bạn", "Your new backup codes are ready": "Mã dự phòng mới của bạn đã sẵn sàng", diff --git a/web/default/src/i18n/locales/zh.json b/web/default/src/i18n/locales/zh.json index 5755a489681c..e0691798e515 100644 --- a/web/default/src/i18n/locales/zh.json +++ b/web/default/src/i18n/locales/zh.json @@ -15,6 +15,7 @@ "(Optional: redirect model names)": "(可选:重定向模型名称)", "(Override all channels' groups)": "覆盖所有渠道的分组", "(Override all channels' models)": "覆盖所有渠道的模型", + ") and choose a model name available on your account.": "),并选择你账户可用的模型名称。", "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]": "[{\"ChatGPT\":\"https://chat.openai.com\"},{\"Lobe Chat\":\"https://chat-preview.lobehub.com/?settings={...}\"}]", "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]": "[{\"name\":\"支付宝\",\"type\":\"alipay\",\"color\":\"#1677FF\"}]", "{\"original-model\": \"replacement-model\"}": "{\"original-model\": \"replacement-model\"}", @@ -109,6 +110,7 @@ "Actual Model:": "实际模型:", "Add": "添加", "Add {{title}}": "添加{{title}}", + "Add a custom Anthropic provider or Claude model in Trae settings.": "在 Trae 设置中添加 Anthropic 自定义 Provider 或 Claude 模型。", "Add a group identifier to the auto assignment list.": "将分组标识符添加到自动分配列表。", "Add a new API key by providing necessary info.": "通过提供必要信息添加新的 API 密钥。", "Add a new channel by providing the necessary information.": "通过提供必要信息添加新的通道。", @@ -127,6 +129,8 @@ "Add custom model(s), comma-separated": "添加自定义模型(多个以逗号分隔)", "Add discount tier": "添加折扣等级", "Add each model or tag you want to include.": "添加您想要包含的每个模型或标签。", + "Add FaceCloud as a custom OpenAI-compatible provider in OpenCode.": "在 OpenCode 中添加 FaceCloud 作为 OpenAI 兼容 Provider。", + "Add FaceCloud as a custom provider in OpenCode configuration.": "在 OpenCode 中添加 FaceCloud 自定义 Provider。", "Add FAQ": "添加问答", "Add from available models...": "从可用模型中添加...", "Add Funds": "添加资金", @@ -156,6 +160,9 @@ "Add selectable group": "添加可选分组", "Add subscription": "新增订阅", "Add tags...": "添加标签...", + "Add the FaceCloud provider configuration:": "添加 FaceCloud Provider 配置:", + "Add the following environment variables:": "添加以下环境变量:", + "Add the following variables:": "添加以下变量:", "Add tier": "新增档位", "Add time condition": "新增时间条件", "Add time rule group": "新增时间规则组", @@ -256,6 +263,7 @@ "Allowed Origins": "允许的 Origins", "Allowed Ports": "允许的端口", "Already have an account?": "已有账户?", + "Alternatively, run opencode auth login and choose to add a custom provider. Set the provider id to facecloud, base URL to the FaceCloud /v1 endpoint, and paste your API key when prompted.": "也可运行 opencode auth login 添加自定义 Provider:id 设为 facecloud,Base URL 设为 FaceCloud 的 /v1 端点,并按提示粘贴 API Key。", "Always matches (default tier).": "始终匹配(默认档位)。", "Amount": "金额", "Amount cannot be changed when editing.": "编辑时无法更改数量。", @@ -268,6 +276,7 @@ "Amount to pay:": "待支付金额:", "An unexpected error occurred": "发生意外错误", "and": "和", + "and your-model-name with your API key and desired model.": "和 your-model-name 替换为你的 API Key 与目标模型。", "Announcement added. Click \"Save Settings\" to apply.": "公告已添加。点击 \"保存设置\" 以应用。", "Announcement content": "公告内容", "Announcement deleted. Click \"Save Settings\" to apply.": "公告已删除。点击 \"保存设置\" 以应用。", @@ -278,6 +287,7 @@ "Announcements saved successfully": "公告保存成功", "Answer": "答案", "Anthropic": "Anthropic", + "Anthropic-compatible models": "Anthropic 兼容模型", "Any Match (OR)": "任一满足(OR)", "API Access": "API 访问", "API Addresses": "API 地址", @@ -327,6 +337,7 @@ "Apply IP Filter to Resolved Domains": "对已解析的域应用 IP 筛选器", "Apply Overwrite": "应用覆盖", "Apply Sync": "应用同步", + "Apply user filter": "应用用户筛选", "Applying...": "正在应用...", "Approx.": "约", "are also listed here. Remove them from Models to keep the `/v1/models` response user-friendly and hide vendor-specific names.": "也在此处列出。将它们从模型中移除,以保持 `/v1/models` 响应对用户友好并隐藏供应商特定的名称。", @@ -428,6 +439,7 @@ "Base amount. Actual deduction = base amount × system group rate.": "基础金额,实际扣费 = 基础金额 × 系统分组倍率。", "Base Limits": "基础额度", "Base multipliers applied when users select specific groups.": "当用户选择特定分组时应用的基础乘数。", + "Base Price": "基础价格", "Base rate limit windows for this account.": "当前账号的基础额度窗口。", "Base URL": "API 地址", "Base URL of your Uptime Kuma instance": "您的 Uptime Kuma 实例的基础 URL", @@ -447,6 +459,7 @@ "Batch enable failed": "批量启用失败", "Batch processing failed": "批量处理失败", "Batch upstream model updates applied: {{channels}} channels, {{added}} added, {{removed}} removed, {{fails}} failed": "已批量处理上游模型更新:渠道 {{channels}} 个,加入 {{added}} 个,删除 {{removed}} 个,失败 {{fails}} 个", + "Before you start": "开始之前", "Best for single-tenant deployments. Pricing and billing options stay hidden.": "适合单用户部署。定价和计费选项将被隐藏。", "Billing": "计费", "Billing currency": "计费货币", @@ -485,7 +498,6 @@ "Broadcast a global banner to users. Markdown is supported.": "向用户广播全局横幅。支持 Markdown。", "Broadcast short system notices on the dashboard": "在仪表板上广播简短的系统通知", "Browse and compare": "浏览和比较", - "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "探索精选 AI 模型,清晰比较价格与能力,为不同场景选择合适的模型。", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.002 and 1. Recommended to keep aligned with upstream billing.": "预算令牌 = 最大令牌数 × 比例。接受 0.002 到 1 之间的十进制数。建议与上游计费保持一致。", "Budget tokens = max tokens × ratio. Accepts a decimal between 0.1 and 1.": "预算令牌 = 最大令牌数 × 比例。接受 0.1 到 1 之间的十进制数。", "Budget Tokens Ratio": "预算令牌比例", @@ -544,6 +556,7 @@ "Channel Affinity": "渠道亲和性", "Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "渠道亲和性会基于从请求上下文或 JSON Body 提取的 Key,优先复用上一次成功的渠道。", "Channel Affinity: Upstream Cache Hit": "渠道亲和性:上游缓存命中", + "Channel Consumption": "渠道消费统计", "Channel copied successfully": "渠道复制成功", "Channel created successfully": "渠道创建成功", "Channel deleted successfully": "渠道删除成功", @@ -608,6 +621,8 @@ "Classic (Legacy Frontend)": "经典前端", "Claude": "Claude", "Claude CLI Header Passthrough": "Claude CLI 请求头透传", + "Claude Code": "Claude Code", + "Claude Code reads configuration from ~/.claude/settings.json. Restart the CLI after saving changes.": "Claude Code 从 ~/.claude/settings.json 读取配置。保存后请重启 CLI。", "Clean history logs": "清理历史日志", "Clean logs": "清理日志", "Clean up inactive cache": "清理不活跃缓存", @@ -628,6 +643,7 @@ "Clear search": "清除搜索", "Clear selection": "清除选择", "Clear selection (Escape)": "清除选择 (Escape)", + "Clear user filter": "清除用户筛选", "Cleared": "已清空", "Cleared all models": "已清除所有模型", "Click \"Create Plan\" to create your first subscription plan": "点击「新建套餐」创建您的第一个订阅套餐", @@ -655,12 +671,15 @@ "CNY": "元", "CNY per USD": "人民币兑美元汇率", "Code": "代码", + "Code Buddy": "Code Buddy", + "CodeBuddy reads CODEBUDDY_API_KEY and CODEBUDDY_BASE_URL to locate the API. Replace your-model-name with a model enabled on your FaceCloud account.": "CodeBuddy 通过 CODEBUDDY_API_KEY 与 CODEBUDDY_BASE_URL 定位 API。请将 your-model-name 替换为你账户已启用的模型。", "Codes copied!": "代码已复制!", "Codex": "Codex", "Codex Account & Usage": "Codex 账户和用量", "Codex Authorization": "Codex 授权", "Codex channels use an OAuth JSON credential as the key.": "Codex 频道使用 OAuth JSON 凭据作为密钥。", "Codex CLI Header Passthrough": "Codex CLI 请求头透传", + "Codex uses TOML configuration at ~/.codex/config.toml and reads the API key from the FACEAPI_API_KEY environment variable.": "Codex 使用 ~/.codex/config.toml 配置,并从 FACEAPI_API_KEY 环境变量读取 API Key。", "Cohere": "Cohere", "Collapse": "收起", "Collapse All": "全部收起", @@ -701,6 +720,7 @@ "Configuration for Creem payment integration": "Creem 支付集成的配置", "Configuration for Epay payment integration": "Epay 支付集成的配置", "Configuration for Stripe payment integration": "Stripe 支付集成的配置", + "Configuration reference": "配置说明", "Configuration required": "需要配置", "Configure": "配置", "Configure a Creem product for user recharge options.": "为用户充值选项配置 Creem 产品。", @@ -715,17 +735,22 @@ "Configure available payment methods. Provide a JSON array.": "配置可用的支付方式。提供一个 JSON 数组。", "Configure basic system information and branding": "配置基本系统信息和品牌", "Configure channel affinity (sticky routing) rules": "配置渠道亲和性(粘滞选路)规则", + "Configure Claude Code CLI to use FaceCloud as the Anthropic API gateway.": "配置 Claude Code CLI,通过 FaceCloud 访问 Anthropic API。", + "Configure Codex": "配置 Codex", "Configure Creem products. Provide a JSON array.": "配置 Creem 产品。提供 JSON 数组。", "Configure custom OAuth providers for user authentication": "配置自定义OAuth提供商用于用户认证", "Configure daily check-in rewards for users": "配置用户每日签到奖励", "Configure discount rates based on recharge amounts": "配置基于充值金额的折扣率", + "Configure environment": "配置环境变量", "Configure experimental data export for the dashboard": "配置仪表板的实验性数据导出", + "Configure FaceCloud": "配置 FaceCloud", "Configure Gemini safety behavior, version overrides, and thinking adapter": "配置 Gemini 安全行为、版本覆盖和思维适配器", "Configure in your Creem dashboard": "在您的 Creem 仪表板中配置", "Configure io.net API key for model deployments": "配置 io.net API Key 用于模型部署", "Configure keyword filtering for prompts and responses.": "配置用于提示和响应的关键词过滤。", "Configure model, caching, and group ratios used for billing": "配置用于计费的模型、缓存和分组比例", "Configure monitoring status page groups for the dashboard": "配置用于仪表板的监控状态页面分组", + "Configure OpenAI Codex CLI to use FaceCloud via OpenAI-compatible chat completions.": "配置 OpenAI Codex CLI,通过 OpenAI 兼容 Chat Completions 使用 FaceCloud。", "Configure outgoing email server for notifications": "配置用于通知的发送邮件服务器", "Configure Passkey (WebAuthn) login settings": "配置 Passkey (WebAuthn) 登录设置", "Configure password-based login and registration": "配置基于密码的登录和注册", @@ -739,6 +764,8 @@ "Configure system-wide behavior and defaults": "配置系统范围的行为和默认设置", "Configure the ratio for this group.": "配置此分组的比例。", "Configure third-party authentication providers": "配置第三方身份验证提供商", + "Configure Trae IDE / Trae Agent (Trace) with full FaceCloud endpoint paths for custom models.": "为 Trae IDE / Trae Agent(Trace)配置完整 FaceCloud 端点路径以使用自定义模型。", + "Configure Trae IDE / Trae Agent with full FaceCloud endpoint paths.": "为 Trae IDE / Trae Agent 配置完整的 FaceCloud 端点路径。", "Configure upstream providers and routing.": "配置上游提供者和路由。", "Configure upstream worker or proxy service for outbound requests": "配置出站请求的上游工作程序或代理服务", "Configure user quota allocation and rewards": "配置用户额度分配和奖励", @@ -774,6 +801,8 @@ "Confirm your identity with Two-factor Authentication before registering a Passkey.": "在注册 Passkey 前请使用两步验证确认你的身份。", "Conflict": "矛盾", "Connect": "连接", + "Connect Tencent CodeBuddy CLI to FaceCloud using environment variables or settings.json.": "通过环境变量或 settings.json 将腾讯 CodeBuddy CLI 接入 FaceCloud。", + "Connect Tencent CodeBuddy CLI to FaceCloud with environment variables.": "通过环境变量将腾讯 CodeBuddy CLI 接入 FaceCloud。", "Connect through OpenAI, Claude, Gemini, and other compatible API routes": "通过 OpenAI、Claude、Gemini 以及其他兼容 API 路由接入", "Connected to io.net service normally.": "已正常连接 io.net 服务。", "Connection error": "连接错误", @@ -871,6 +900,7 @@ "Create multiple channels from multiple keys": "从多个密钥创建多个渠道", "Create multiple redemption codes at once (1-100)": "一次创建多个兑换码 (1-100)", "Create new subscription plan": "创建新的订阅套餐", + "Create or edit": "创建或编辑", "Create or update frequently asked questions for users": "创建或更新用户的常见问题", "Create or update system announcements for the dashboard": "创建或更新仪表板的系统公告", "Create Plan": "新建套餐", @@ -881,6 +911,7 @@ "Create request parameter override rules without editing raw JSON.": "无需编辑原始 JSON 即可创建请求参数覆盖规则。", "Create reusable bundles of models, tags, endpoints, and user groups to speed up configuration elsewhere in the console.": "创建模型、标签、端点和用户分组的可重用捆绑包,以加快控制台中其他地方的配置速度。", "Create succeeded": "创建成功", + "Create the config directory if it does not exist:": "若目录不存在,请先创建:", "Create Vendor": "创建供应商", "Create your first group to reuse model, tag, or endpoint selections anywhere in the dashboard.": "创建您的第一个分组,以便在仪表板的任何位置重用模型、标签或端点选择。", "Create, revoke, and audit API tokens.": "创建、撤销和审计 API 令牌。", @@ -962,6 +993,7 @@ "Default consumption chart": "默认消耗分布图", "Default Max Tokens": "默认最大 Token 数", "Default model call chart": "默认模型调用图", + "Default model name for requests": "默认请求模型名称", "Default range": "默认范围", "Default Responses API version, if empty, will use the API version above": "默认响应 API 版本,如果为空,将使用上面的 API 版本", "Default system prompt for this channel": "此渠道的默认系统提示", @@ -1059,6 +1091,8 @@ "Disabled all channels with tag: {{tag}}": "已禁用标签「{{tag}}」下的所有渠道", "Disabled Reason": "禁用原因", "Disabled Time": "禁用时间", + "Disables attribution header when using a proxy": "使用代理时禁用归属请求头", + "Disables experimental beta headers for third-party gateways": "禁用实验性 Beta 请求头,便于第三方网关接入", "Disabling...": "禁用中...", "Discord": "Discord", "Discount": "优惠", @@ -1069,6 +1103,7 @@ "Discount Rate:": "折扣率:", "Discount ratio for cache hits.": "缓存命中时的折扣比例。", "Discouraged": "不推荐", + "Discover curated AI models, compare pricing and capabilities, and choose the right model for every scenario.": "探索精选 AI 模型,清晰比较价格与能力,为不同场景选择合适的模型。", "Discovering...": "发现中...", "Disk cache cleared": "磁盘缓存已清理", "Disk Cache Settings": "磁盘缓存设置", @@ -1106,6 +1141,7 @@ "DoubaoVideo": "DoubaoVideo", "Double check the configuration below. Your system will be locked until initialization is complete.": "仔细检查以下配置。您的系统将在初始化完成前保持锁定状态。", "Download": "下载", + "Download started": "已开始下载", "Draw": "绘图", "Drawing": "绘图", "Drawing logs": "绘制日志", @@ -1121,6 +1157,7 @@ "e.g. ¥ or HK$": "例如,¥ 或 HK$", "e.g. 401, 403, 429, 500-599": "例如 401、403、429、500-599", "e.g. 8 means 1 USD = 8 units": "例如,8 表示 1 美元 = 8 单位", + "e.g. Asia/Shanghai": "例如 Asia/Shanghai", "e.g. Basic Plan": "例如:基础套餐", "e.g. Clean tool parameters to avoid upstream validation errors": "例如:清理工具参数,避免上游校验错误", "e.g. example.com": "例如,example.com", @@ -1179,6 +1216,7 @@ "Edit model": "编辑模型", "Edit Model": "编辑模型", "Edit OAuth Provider": "编辑 OAuth 提供商", + "Edit opencode.json with the FaceCloud provider:": "在 opencode.json 中添加 FaceCloud Provider:", "Edit payment method": "编辑支付方式", "Edit Prefill Group": "编辑预填充组", "Edit product": "编辑产品", @@ -1254,6 +1292,7 @@ "Endpoint": "端点", "Endpoint config": "端点配置", "Endpoint Configuration": "端点配置", + "Endpoint reference": "端点参考", "Endpoint Type": "端点类型", "Endpoint:": "端点:", "Endpoints": "端点", @@ -1333,6 +1372,7 @@ "Enterprise-grade security with comprehensive permission management": "企业级安全性,提供全面的权限管理", "Entrypoint (space separated)": "入口点 (空格分隔)", "Env (JSON object)": "环境变量 (JSON 对象)", + "Environment variable holding your API key": "存放 API Key 的环境变量名", "Environment variables": "环境变量", "Environment variables (JSON)": "环境变量 (JSON)", "Epay endpoint": "Epay 端点", @@ -1371,6 +1411,15 @@ "Expired at": "过期于", "Expired time cannot be earlier than current time": "过期时间不能早于当前时间", "Expires": "过期", + "Export completed": "导出成功", + "Export consumption details": "导出消费明细", + "Export failed": "导出失败", + "Export logs": "导出日志", + "Export monthly bill": "导出月账单", + "Export monthly bill and consumption details": "导出月账单和消费明细", + "Export the following variables in your terminal or shell profile:": "在终端或 Shell 配置中导出以下变量:", + "Export usage CSV": "导出用量 CSV", + "Export usage CSV for user {{name}} (ID {{id}})": "为用户 {{name}}(ID {{id}})导出用量 CSV", "Expose grouped Uptime Kuma status pages directly on the dashboard": "直接在仪表板上显示分组的 Uptime Kuma 状态页面", "Expose ratio API": "暴露倍率接口", "Exposes the pricing/models catalog in the top navigation.": "在顶部导航中显示定价/模型目录。", @@ -1388,6 +1437,9 @@ "External Speed Test": "外部速度测试", "Extra": "额外", "Extra Notes (Optional)": "额外备注(可选)", + "FaceCloud gateway URL": "FaceCloud 网关地址", + "FaceCloud Gemini-compatible base URL": "FaceCloud Gemini 兼容基础 URL", + "FaceCloud Integration Guides": "FaceCloud 集成教程", "Fail Reason": "失败原因", "Fail Reason Details": "失败原因详情", "Failed": "失败", @@ -1450,6 +1502,7 @@ "Failed to load": "加载失败", "Failed to load API keys": "加载 API 密钥失败", "Failed to load billing history": "加载计费历史失败", + "Failed to load consumption": "加载消费统计失败", "Failed to load home page content": "加载首页内容失败", "Failed to load image": "无法加载图像", "Failed to load logs": "加载日志失败", @@ -1557,6 +1610,7 @@ "Filter by request ID": "按请求 ID 筛选", "Filter by task ID": "按任务 ID 筛选", "Filter by token name": "按 Token 名称筛选", + "Filter by user (optional)": "按用户筛选(可选)", "Filter by username": "按用户名筛选", "Filter by username, name or email...": "按用户名、姓名或邮箱筛选...", "Filter Dashboard Models": "筛选仪表板模型", @@ -1595,6 +1649,8 @@ "footer.defaultCopyright": "版权所有。", "footer.new\u0061pi.projectAttributionSuffix": "版权所有,由项目贡献者设计与开发。", "For channels added after May 10, 2025, no need to remove \".\" from model names during deployment": "对于 2025 年 5 月 10 日之后添加的渠道,在部署时无需从模型名称中移除 \".\"", + "For model availability and pricing, visit the pricing page or dashboard.": "模型可用性与价格请查看定价页或控制台。", + "For OpenAI-compatible models, set the request URL to:": "OpenAI 兼容模型请将请求 URL 设为:", "For private deployments, format: https://fastgpt.run/api/openapi": "对于私有部署,格式为:https://fastgpt.run/api/openapi", "Force AUTH LOGIN": "强制 AUTH LOGIN", "Force Format": "强制格式化", @@ -1623,11 +1679,13 @@ "Full API Key": "完整 API 密钥", "Full Base URL (supports": "完整基础 URL (支持", "Full Code": "完整代码", + "Full endpoint URL": "完整端点 URL", "Functions": "函数", "GC Count": "GC 次数", "GC executed": "GC 已执行", "GC execution failed": "GC 执行失败", "Gemini": "Gemini", + "Gemini CLI loads environment variables from ~/.env by default. You can also export them in your shell profile.": "Gemini CLI 默认从 ~/.env 加载环境变量,也可在 Shell 配置文件中导出。", "Gemini Image 4K": "Gemini 图片 4K", "Gemini will continue to auto-detect thinking mode even with the adapter disabled. Enable this only when you need finer control over pricing and budgeting.": "即使禁用适配器,Gemini 也会继续自动检测思维模式。仅当您需要对定价和预算进行更精细的控制时才启用此选项。", "General": "常规", @@ -1779,7 +1837,9 @@ "ID": "ID", "If an upstream error contains any of these keywords (case insensitive), the channel will be disabled automatically.": "如果上游错误包含以下任何关键字(不区分大小写),渠道将自动禁用。", "If authorization succeeds, the generated JSON will be inserted into the key field. You still need to save the channel to persist it.": "授权成功后,生成的 JSON 将插入密钥字段。您仍需保存频道以持久化。", + "If CodeBuddy supports a settings.json env block (similar to Claude Code), you can persist configuration:": "若 CodeBuddy 支持 settings.json 的 env 字段(类似 Claude Code),可持久化配置:", "If connecting to upstream One API or New API relay projects, use OpenAI type instead unless you know what you are doing": "如果连接上游 One API 或 New API 中继项目,除非您知道自己在做什么,否则请使用 OpenAI 类型", + "If requests fail with 404, double-check that the full path is entered in Trae and that your FaceCloud deployment exposes the corresponding relay routes.": "若返回 404,请检查 Trae 中是否填写了完整路径,并确认 FaceCloud 已开放对应转发路由。", "If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "如果亲和到的渠道失败,重试到其他渠道成功后,将亲和更新到成功的渠道。", "Ignored upstream models": "已忽略上游模型", "Image": "图片", @@ -1792,7 +1852,10 @@ "Image to Video": "图生视频", "Image Tokens": "图像 Token", "Import to CC Switch": "填入 CC Switch", + "Important": "重要", "In Progress": "进行中", + "in the examples below with your real key. API base URL:": "替换为你的真实 Key。API 基础地址:", + "in your home directory.": "(位于用户主目录)。", "In:": "入:", "Include Group": "包含分组", "Include Model": "包含模型", @@ -1811,13 +1874,17 @@ "Input tokens": "输入 token", "Input Tokens": "输入 Token", "Inspect user prompts": "检查用户提示", + "Install Claude Code": "安装 Claude Code", "Instance": "实例", + "Integration": "集成", + "Integration guides": "集成教程", "Integrations": "集成", "Inter-group overrides": "分组间覆盖", "Inter-group ratio overrides": "分组间比例覆盖", + "Interactive login": "交互式登录", + "Interface Language": "界面语言", "Internal Notes": "内部备注", "Internal notes (not shown to users)": "内部备注(不显示给用户)", - "Interface Language": "界面语言", "Internal Server Error!": "内部服务器错误!", "Invalid chat link. Please contact the administrator.": "无效的聊天链接。请联系管理员。", "Invalid chat link. Please contact your administrator.": "无效的聊天链接。请联系您的管理员。", @@ -1828,6 +1895,7 @@ "Invalid JSON in parameter override template": "参数覆盖模板中的 JSON 格式无效", "Invalid JSON string.": "无效的 JSON 字符串。", "Invalid model mapping format": "无效的模型映射格式", + "Invalid month": "月份无效", "Invalid Passkey registration response": "无效的 Passkey 注册响应", "Invalid Passkey response": "无效的 Passkey 响应", "Invalid payment redirect URL": "无效的支付跳转链接", @@ -1835,6 +1903,7 @@ "Invalid reset link, please request a new password reset.": "无效的重置链接,请请求新的密码重置。", "Invalid rules JSON format": "规则 JSON 格式不正确", "Invalid status code mapping entries: {{entries}}": "无效的状态码映射条目:{{entries}}", + "Invalid year": "年份无效", "Invalidate": "作废", "Invalidated": "已作废", "Invert match": "反向匹配", @@ -1894,8 +1963,8 @@ "Kling": "Kling", "Knowledge Base ID *": "知识库 ID *", "Landing page with system overview.": "带有系统概览的登陆页面。", - "Language Preferences": "语言偏好", "Language preference saved": "语言偏好已保存", + "Language Preferences": "语言偏好", "Language preferences sync across your signed-in devices and affect API error messages.": "语言偏好会同步到您登录的所有设备,并影响 API 错误消息语言。", "Last check time": "上次检测时间", "Last detected addable models": "上次检测到可加入模型", @@ -1905,7 +1974,9 @@ "Last updated:": "上次更新时间:", "Last Used": "最后使用时间", "Last used:": "上次使用时间:", + "Launch OpenCode and verify that requests route through FaceCloud.": "启动 OpenCode 并确认请求经由 FaceCloud 转发。", "Layout": "布局", + "Learn how to connect FaceCloud to popular AI coding tools and IDEs. FaceCloud acts as a unified API gateway so you can use one API key across multiple providers.": "了解如何将 FaceCloud 接入常用 AI 编程工具与 IDE。FaceCloud 作为统一 API 网关,只需一个 API Key 即可使用多种模型服务。", "Learn more": "了解更多", "Learn more:": "了解更多:", "Leave": "离开", @@ -1928,6 +1999,7 @@ "Less": "更少", "Less Than": "小于", "Less Than or Equal": "小于等于", + "Lifetime channel usage": "渠道历史总消耗", "Light": "浅色", "Lightning Fast": "极速", "Limit period": "限制周期", @@ -1999,6 +2071,7 @@ "Manage your API keys for accessing the service": "管理您用于访问服务的 API 密钥", "Manage your balance and payment methods": "管理您的余额和付款方式", "Manage your security settings and account access": "管理您的安全设置和账户访问", + "Manual configuration": "手动配置", "Manual Disabled": "手动禁用", "Map fields from the user info response to local user attributes. Supports nested paths (e.g. ocs.data.id).": "将用户信息响应中的字段映射到本地用户属性。支持嵌套路径(例如 ocs.data.id)。", "Map model identifiers to Gemini API versions. A `default` entry applies when no specific match is found.": "将模型标识符映射到 Gemini API 版本。当未找到特定匹配项时,将应用 `default` 条目。", @@ -2125,6 +2198,7 @@ "Monitor": "监控", "Monitoring & Alerts": "监控与警报", "Month": "月份", + "Month range uses server local time unless a timezone is set.": "未填写时按服务器本地时区划分自然月;填写 IANA 时区后按该时区的自然月。", "Monthly": "每月", "months": "个月", "Moonshot": "Moonshot", @@ -2337,6 +2411,7 @@ "Not Submitted": "未提交", "Not tested": "未测试", "Not used yet": "暂未使用", + "Note": "说明", "Notice": "通知", "Notification Email": "通知邮箱", "Notification Method": "通知方式", @@ -2400,13 +2475,18 @@ "Open Source": "开源项目", "Open the io.net console API Keys page": "打开 io.net 控制台 API 密钥页面", "Open theme settings": "打开主题设置", + "Open Trae IDE settings and navigate to Custom Model or AI Provider configuration.": "打开 Trae IDE 设置,进入自定义模型或 AI Provider 配置。", "OpenAI": "OpenAI", "OpenAI Compatible": "兼容 OpenAI", "OpenAI Organization": "OpenAI 组织", "OpenAI Organization ID (optional)": "OpenAI 组织 ID(可选)", + "OpenAI-compatible base URL at {{url}}": "OpenAI 兼容基础 URL:{{url}}", + "OpenAI-compatible endpoint at {{url}}": "OpenAI 兼容端点:{{url}}", + "OpenAI-compatible models": "OpenAI 兼容模型", "OpenAI, Anthropic, etc.": "OpenAI、Anthropic 等", "OpenAI, Anthropic, Google, etc.": "OpenAI、Anthropic、Google 等", "OpenAIMax": "OpenAIMax", + "OpenCode configuration lives at ~/.config/opencode/opencode.json. You can also authenticate interactively with opencode auth login.": "OpenCode 配置文件位于 ~/.config/opencode/opencode.json,也可通过 opencode auth login 交互式登录。", "Opened authorization page": "已打开授权页", "OpenRouter": "OpenRouter", "opens in an external client. Trigger it from the sidebar or API key actions to launch the configured application.": "在外部客户端中打开。从侧边栏或 API 密钥操作中触发,以启动配置的应用。", @@ -2617,6 +2697,8 @@ "Please try again later.": "请稍后再试。", "Please upload key file(s)": "请上传密钥文件", "Please wait a moment, human check is initializing...": "请稍等,人机验证正在初始化...", + "Point Google Gemini CLI at FaceCloud for Gemini-compatible requests.": "将 Gemini CLI 指向 FaceCloud 的 Gemini 兼容端点。", + "Point the Google Gemini CLI at FaceCloud for Gemini-compatible API requests.": "将 Google Gemini CLI 指向 FaceCloud 的 Gemini 兼容 API。", "Policy JSON": "策略 JSON", "Polling": "轮询", "Polling mode requires Redis and memory cache, otherwise performance will be significantly degraded": "轮询模式需要 Redis 和内存缓存,否则性能将显著下降", @@ -2627,6 +2709,7 @@ "PostgreSQL detected": "检测到 PostgreSQL", "PostgreSQL offers advanced reliability and data integrity for production workloads.": "PostgreSQL 为生产工作负载提供高级可靠性和数据完整性。", "PostgreSQL offers strong reliability guarantees. Double check your maintenance window and retention policies before going live.": "PostgreSQL 提供强大的可靠性保证。在上线之前,请仔细检查您的维护窗口和保留策略。", + "Powered by": "技术支持", "Powerful API Management Platform": "强大的 API 管理平台", "Pre-Consume for Free Models": "免费模型预消耗", "Pre-consumed": "预扣费", @@ -2660,7 +2743,6 @@ "Previous": "上一步", "Previous branch": "上一分支", "Previous page": "上一页", - "Base Price": "基础价格", "Price": "价格", "Price ($/1K calls)": "价格($/1K 次)", "Price (local currency / USD)": "价格(本地货币/美元)", @@ -2848,6 +2930,7 @@ "Registry username": "注册表用户名", "Reject Reason": "拒绝原因", "Release details": "版本详情", + "Reload your shell or run source on the file after exporting the variable.": "导出变量后请重新加载 Shell,或执行 source 使配置生效。", "Relying Party Display Name": "依赖方显示名称", "Relying Party ID": "依赖方 ID", "Remaining": "剩余", @@ -2882,7 +2965,7 @@ "Rename failed": "重命名失败", "Renamed successfully": "重命名成功", "Repeat the administrator password": "重复输入管理员密码", - "Replace": "替换", + "Replace": "将", "Replace all existing keys": "替换所有现有密钥", "Replace channel models": "覆盖渠道模型", "Replace mode: Will completely replace all existing keys": "替换模式:将完全替换所有现有键", @@ -2998,8 +3081,11 @@ "Rules": "规则", "Rules JSON": "规则 JSON", "Rules JSON must be an array": "规则 JSON 必须是数组", + "Run claude in a new terminal session to verify the connection.": "在新终端中运行 claude 验证连接。", + "Run codebuddy from the same shell session to use FaceCloud.": "在同一 Shell 会话中运行 codebuddy 即可使用 FaceCloud。", "Run GC": "执行 GC", "Run tests for the selected models": "运行所选模型的测试", + "Run the Gemini CLI and send a test prompt to confirm connectivity.": "运行 Gemini CLI 并发送测试请求以确认连接。", "Running": "运行中", "s": "秒", "Safety Settings": "安全设置", @@ -3111,8 +3197,8 @@ "Select groups (leave empty to keep current)": "选择分组(留空以保持当前设置)", "Select items...": "选择项目...", "Select key format": "请选择密钥格式", - "Select Language": "选择语言", "Select language": "选择语言", + "Select Language": "选择语言", "Select layout style": "选择布局样式", "Select locations": "选择位置", "Select Model": "选择模型", @@ -3176,20 +3262,25 @@ "Set quota amount and limits": "设置令牌可用额度和数量", "Set Request Header": "设置请求头", "Set runtime request header: override entire value, or manipulate comma-separated tokens": "设置运行期请求头:可直接覆盖整条值,也可对逗号分隔的 token 做处理", - "Set the language used across the interface": "设置界面显示语言", "Set Tag": "设置标签", "Set tag for selected channels": "为选定的渠道设置标签", + "Set the API key to your FaceCloud key (": "API Key 填写 FaceCloud Key(", + "Set the language used across the interface": "设置界面显示语言", + "Set the messages endpoint to:": "将 messages 端点设为:", "Set the user's role (cannot be Root)": "设置用户角色(不能是 Root)", + "Set your API key": "设置 API Key", "Setting saved": "设置已保存", "Setting up 2FA...": "正在设置 2FA...", "Setting updated successfully": "设置更新成功", "Settings": "设置", "Settings & Preferences": "设置与偏好", "Settings updated successfully": "设置更新成功", + "settings.json (optional)": "settings.json(可选)", "Setup Instructions": "设置说明", "Setup Two-Factor Authentication": "设置双重身份验证", "Share your link and earn rewards": "分享您的链接并赚取奖励", "Shared configuration for all payment gateways": "所有支付网关的共享配置", + "Shell environment": "Shell 环境变量", "Shorten": "缩词", "Show": "显示", "Show All": "显示全部", @@ -3256,6 +3347,7 @@ "Standard": "标准", "Start": "开始", "Start a conversation to see messages here": "开始对话以在此处查看消息", + "Start Codex and select the FaceCloud provider. Adjust model to one available on your account.": "启动 Codex 并选择 FaceCloud Provider,将 model 改为你账户可用的模型。", "Start for free with generous limits. No credit card required.": "免费开始使用,额度充足,无需绑定信用卡。", "Start Time": "起始时间", "Static page describing the platform.": "描述平台的静态页面。", @@ -3487,7 +3579,9 @@ "Timed cache (1h)": "定时缓存(1 小时)", "Timeline": "时间线", "times": "次", + "Timezone (IANA, optional)": "时区(IANA,可选)", "Timing": "耗时", + "Tip": "提示", "Tip: The generated key is a JSON credential including access_token / refresh_token / account_id.": "提示:生成的密钥为包含 access_token / refresh_token / account_id 的 JSON 凭据。", "to access this resource.": "访问此资源。", "to confirm": "以确认", @@ -3550,15 +3644,19 @@ "Total invitation revenue": "总邀请收入", "Total Log Size": "日志总大小", "Total Quota": "总额度", + "Total requests": "请求总数", "Total requests allowed per period. 0 = unlimited.": "每周期允许的总请求数。0 = 无限制。", "Total requests made": "总请求数", + "Total tokens": "Token 总数", "Total Tokens": "总 Token 数", "Total Usage": "总用量", "Total:": "总计:", "TPM": "TPM", + "Trace (Trae IDE)": "Trace(Trae IDE)", "Track per-request consumption to power usage analytics. Keeping this on increases database writes.": "跟踪每个请求的消耗,以支持使用情况分析。保持开启会增加数据库写入。", "Track usage, costs and performance with real-time analytics": "通过实时分析跟踪用量、成本和性能", "Tracks current account base limits and additional metered usage on Codex upstream.": "跟踪当前账号在 Codex 上游的基础限额与附加计费用量。", + "Trae requires complete endpoint URLs including the path segment. Do not use only the base domain — include /v1/chat/completions or /v1/messages as shown below.": "Trae 需要填写完整 URL(含路径),不要只填域名,请使用下方所示的 /v1/chat/completions 或 /v1/messages。", "Transfer": "转移", "Transfer Amount": "转移金额", "Transfer failed": "转账失败", @@ -3683,7 +3781,11 @@ "Use a compatible browser or device with biometric authentication or a security key to register a Passkey.": "请使用支持生物识别认证或安全密钥的兼容浏览器或设备来注册通行密钥。", "Use authenticator code": "使用验证器代码", "Use backup code": "使用备用代码", + "Use Bearer authentication with your FaceCloud API key in the Authorization header.": "在 Authorization 头中使用 Bearer 方式携带 FaceCloud API Key。", + "Use chat completions wire format": "使用 Chat Completions 协议", "Use disk cache when request body exceeds this size": "请求体超过此大小时使用磁盘缓存", + "Use FaceCloud as the Anthropic API endpoint for Claude Code CLI in your terminal.": "在终端中将 FaceCloud 配置为 Claude Code CLI 的 Anthropic API 端点。", + "Use OpenAI Codex CLI with FaceCloud via OpenAI-compatible chat completions.": "通过 OpenAI 兼容接口,在 Codex CLI 中使用 FaceCloud。", "Use our unified OpenAI-compatible endpoint in your applications": "在应用中使用我们兼容 OpenAI 的统一接口", "Use Passkey to sign in without entering your password.": "使用通行密钥登录,无需输入密码。", "Use secure connection when sending emails": "发送电子邮件时使用安全连接", @@ -3778,6 +3880,7 @@ "View detailed information about this user including balance, usage statistics, and invitation details.": "查看此用户的详细信息,包括余额、使用统计和邀请详情。", "View details": "查看详情", "View document": "查看文档", + "View guide": "查看教程", "View logs": "查看日志", "View mode": "视图模式", "View model call count analytics and charts": "查看模型调用次数统计和图表", @@ -3870,6 +3973,8 @@ "whsec_xxx": "whsec_xxx", "Window:": "窗口:", "with conflicts": "有冲突", + "with your FaceCloud API key and set GEMINI_MODEL to a model your account supports.": "替换为你的 FaceCloud API Key,并将 GEMINI_MODEL 设为你账户支持的模型。", + "with your FaceCloud API key.": "替换为你的 FaceCloud API Key。", "Without additional conditions, only the type above is used for pruning.": "未添加附加条件时,仅使用上方 type 进行清理。", "Worker Access Key": "Worker 访问密钥", "Worker Proxy": "Worker 代理", @@ -3880,6 +3985,7 @@ "xAI": "xAI", "Xinference": "Xinference", "Xunfei": "讯飞", + "Year": "年份", "years": "年", "You are about to delete {{count}} API key(s).": "您即将删除 {{count}} 个 API 密钥。", "You are running the latest version ({{version}}).": "您正在运行最新版本 ({{version}})。", @@ -3889,6 +3995,7 @@ "You don't have necessary permission": "您没有必要的权限", "You have unsaved changes": "您有未保存的更改", "You have unsaved changes. Are you sure you want to leave?": "您有未保存的更改。确定要离开吗?", + "You need a FaceCloud API key. Create one in the dashboard, then replace": "你需要一个 FaceCloud API Key。在控制台创建后,将示例中的", "You Pay": "您支付", "You save": "您节省", "You will be redirected to Telegram to complete the binding process.": "您将被重定向到 Telegram 以完成绑定过程。", @@ -3899,6 +4006,7 @@ "Your Cloudflare Account ID": "您的 Cloudflare 账户 ID", "Your Discord OAuth Client ID": "您的 Discord OAuth 客户端 ID", "Your Discord OAuth Client Secret": "您的 Discord OAuth 客户端密钥", + "Your FaceCloud API key": "你的 FaceCloud API Key", "Your GitHub OAuth Client ID": "您的 GitHub OAuth 客户端 ID", "Your GitHub OAuth Client Secret": "您的 GitHub OAuth 客户端密钥", "Your new backup codes are ready": "您的新备份代码已准备就绪", diff --git a/web/default/src/lib/docs-nav-link.ts b/web/default/src/lib/docs-nav-link.ts new file mode 100644 index 000000000000..0d0ff9c2cefa --- /dev/null +++ b/web/default/src/lib/docs-nav-link.ts @@ -0,0 +1,62 @@ +/** + * 将后台配置的文档链接解析为顶部导航使用的 href,并判断是否在站内打开。 + * 与当前浏览器 origin 或 {@link serverAddress} 同源时用 SPA 路由,否则新开标签页。 + */ +export function resolveDocsNavLink( + docsLink: string, + serverAddress?: string +): { href: string; external: boolean } { + const trimmed = docsLink.trim() + if (!trimmed) { + return { href: '/docs', external: false } + } + + if (trimmed.startsWith('/') && !trimmed.startsWith('//')) { + return { href: trimmed, external: false } + } + + let absolute: URL + try { + if (trimmed.startsWith('//')) { + absolute = new URL(`https:${trimmed}`) + } else if (!/^https?:\/\//i.test(trimmed)) { + const base = + (typeof window !== 'undefined' && window.location.origin) || + originFromServerAddress(serverAddress) || + 'http://localhost' + const normalizedBase = base.endsWith('/') ? base : `${base}/` + absolute = new URL(trimmed, normalizedBase) + } else { + absolute = new URL(trimmed) + } + } catch { + return { href: trimmed, external: true } + } + + const browserOrigin = + typeof window !== 'undefined' ? window.location.origin : undefined + const sameAsBrowser = Boolean( + browserOrigin && browserOrigin === absolute.origin + ) + + const srvOrigin = originFromServerAddress(serverAddress) + const sameAsServer = Boolean(srvOrigin && srvOrigin === absolute.origin) + + if (sameAsBrowser || sameAsServer) { + return { + href: `${absolute.pathname}${absolute.search}${absolute.hash}`, + external: false, + } + } + + return { href: absolute.href, external: true } +} + +function originFromServerAddress(serverAddress?: string): string | undefined { + if (!serverAddress?.trim()) return undefined + try { + return new URL(serverAddress.trim()).origin + } catch { + return undefined + } +} diff --git a/web/default/src/lib/time.ts b/web/default/src/lib/time.ts index dad6c1480e8f..d862fe1254ce 100644 --- a/web/default/src/lib/time.ts +++ b/web/default/src/lib/time.ts @@ -79,6 +79,21 @@ export function getRollingDateRange( return { start, end } } +/** + * Inclusive calendar-day range: start at 00:00:00, end at 23:59:59.999 local time. + * `numDays === 1` → today only; `numDays === 7` → today and the previous 6 calendar days. + */ +export function getCalendarDayRangeInclusive( + numDays: number, + fromDate: Date = new Date() +): { start: Date; end: Date } { + const end = getEndOfDay(fromDate) + const startBase = new Date(fromDate) + startBase.setDate(startBase.getDate() - (numDays - 1)) + const start = getStartOfDay(startBase) + return { start, end } +} + /** * Compute time range as Unix timestamps (seconds) * @param days Default number of days if no dates provided diff --git a/web/default/src/routeTree.gen.ts b/web/default/src/routeTree.gen.ts index fd78de1527c6..f7edfacb6d10 100644 --- a/web/default/src/routeTree.gen.ts +++ b/web/default/src/routeTree.gen.ts @@ -16,6 +16,7 @@ import { Route as authRouteRouteImport } from './routes/(auth)/route' import { Route as IndexRouteImport } from './routes/index' import { Route as SetupIndexRouteImport } from './routes/setup/index' import { Route as PricingIndexRouteImport } from './routes/pricing/index' +import { Route as DocsIndexRouteImport } from './routes/docs/index' import { Route as AboutIndexRouteImport } from './routes/about/index' import { Route as OauthProviderRouteImport } from './routes/oauth/$provider' import { Route as AuthenticatedChat2linkRouteImport } from './routes/_authenticated/chat2link' @@ -30,8 +31,10 @@ import { Route as authResetRouteImport } from './routes/(auth)/reset' import { Route as authOtpRouteImport } from './routes/(auth)/otp' import { Route as authOauthRouteImport } from './routes/(auth)/oauth' import { Route as authForgotPasswordRouteImport } from './routes/(auth)/forgot-password' +import { Route as DocsIntegrationRouteRouteImport } from './routes/docs/integration/route' import { Route as AuthenticatedSystemSettingsRouteRouteImport } from './routes/_authenticated/system-settings/route' import { Route as PricingModelIdIndexRouteImport } from './routes/pricing/$modelId/index' +import { Route as DocsIntegrationIndexRouteImport } from './routes/docs/integration/index' import { Route as AuthenticatedWalletIndexRouteImport } from './routes/_authenticated/wallet/index' import { Route as AuthenticatedUsersIndexRouteImport } from './routes/_authenticated/users/index' import { Route as AuthenticatedUsageLogsIndexRouteImport } from './routes/_authenticated/usage-logs/index' @@ -44,6 +47,12 @@ import { Route as AuthenticatedModelsIndexRouteImport } from './routes/_authenti import { Route as AuthenticatedKeysIndexRouteImport } from './routes/_authenticated/keys/index' import { Route as AuthenticatedDashboardIndexRouteImport } from './routes/_authenticated/dashboard/index' import { Route as AuthenticatedChannelsIndexRouteImport } from './routes/_authenticated/channels/index' +import { Route as DocsIntegrationTraceRouteImport } from './routes/docs/integration/trace' +import { Route as DocsIntegrationOpenCodeRouteImport } from './routes/docs/integration/open-code' +import { Route as DocsIntegrationGeminiCliRouteImport } from './routes/docs/integration/gemini-cli' +import { Route as DocsIntegrationCodexRouteImport } from './routes/docs/integration/codex' +import { Route as DocsIntegrationCodeBuddyRouteImport } from './routes/docs/integration/code-buddy' +import { Route as DocsIntegrationClaudeCodeRouteImport } from './routes/docs/integration/claude-code' import { Route as AuthenticatedUsageLogsSectionRouteImport } from './routes/_authenticated/usage-logs/$section' import { Route as AuthenticatedModelsSectionRouteImport } from './routes/_authenticated/models/$section' import { Route as AuthenticatedErrorsErrorRouteImport } from './routes/_authenticated/errors/$error' @@ -98,6 +107,11 @@ const PricingIndexRoute = PricingIndexRouteImport.update({ path: '/pricing/', getParentRoute: () => rootRouteImport, } as any) +const DocsIndexRoute = DocsIndexRouteImport.update({ + id: '/docs/', + path: '/docs/', + getParentRoute: () => rootRouteImport, +} as any) const AboutIndexRoute = AboutIndexRouteImport.update({ id: '/about/', path: '/about/', @@ -168,6 +182,11 @@ const authForgotPasswordRoute = authForgotPasswordRouteImport.update({ path: '/forgot-password', getParentRoute: () => authRouteRoute, } as any) +const DocsIntegrationRouteRoute = DocsIntegrationRouteRouteImport.update({ + id: '/docs/integration', + path: '/docs/integration', + getParentRoute: () => rootRouteImport, +} as any) const AuthenticatedSystemSettingsRouteRoute = AuthenticatedSystemSettingsRouteRouteImport.update({ id: '/system-settings', @@ -179,6 +198,11 @@ const PricingModelIdIndexRoute = PricingModelIdIndexRouteImport.update({ path: '/pricing/$modelId/', getParentRoute: () => rootRouteImport, } as any) +const DocsIntegrationIndexRoute = DocsIntegrationIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => DocsIntegrationRouteRoute, +} as any) const AuthenticatedWalletIndexRoute = AuthenticatedWalletIndexRouteImport.update({ id: '/wallet/', @@ -249,6 +273,39 @@ const AuthenticatedChannelsIndexRoute = path: '/channels/', getParentRoute: () => AuthenticatedRouteRoute, } as any) +const DocsIntegrationTraceRoute = DocsIntegrationTraceRouteImport.update({ + id: '/trace', + path: '/trace', + getParentRoute: () => DocsIntegrationRouteRoute, +} as any) +const DocsIntegrationOpenCodeRoute = DocsIntegrationOpenCodeRouteImport.update({ + id: '/open-code', + path: '/open-code', + getParentRoute: () => DocsIntegrationRouteRoute, +} as any) +const DocsIntegrationGeminiCliRoute = + DocsIntegrationGeminiCliRouteImport.update({ + id: '/gemini-cli', + path: '/gemini-cli', + getParentRoute: () => DocsIntegrationRouteRoute, + } as any) +const DocsIntegrationCodexRoute = DocsIntegrationCodexRouteImport.update({ + id: '/codex', + path: '/codex', + getParentRoute: () => DocsIntegrationRouteRoute, +} as any) +const DocsIntegrationCodeBuddyRoute = + DocsIntegrationCodeBuddyRouteImport.update({ + id: '/code-buddy', + path: '/code-buddy', + getParentRoute: () => DocsIntegrationRouteRoute, + } as any) +const DocsIntegrationClaudeCodeRoute = + DocsIntegrationClaudeCodeRouteImport.update({ + id: '/claude-code', + path: '/claude-code', + getParentRoute: () => DocsIntegrationRouteRoute, + } as any) const AuthenticatedUsageLogsSectionRoute = AuthenticatedUsageLogsSectionRouteImport.update({ id: '/usage-logs/$section', @@ -373,6 +430,7 @@ export interface FileRoutesByFullPath { '/privacy-policy': typeof PrivacyPolicyRoute '/user-agreement': typeof UserAgreementRoute '/system-settings': typeof AuthenticatedSystemSettingsRouteRouteWithChildren + '/docs/integration': typeof DocsIntegrationRouteRouteWithChildren '/forgot-password': typeof authForgotPasswordRoute '/oauth': typeof authOauthRoute '/otp': typeof authOtpRoute @@ -387,6 +445,7 @@ export interface FileRoutesByFullPath { '/chat2link': typeof AuthenticatedChat2linkRoute '/oauth/$provider': typeof OauthProviderRoute '/about/': typeof AboutIndexRoute + '/docs/': typeof DocsIndexRoute '/pricing/': typeof PricingIndexRoute '/setup/': typeof SetupIndexRoute '/user/reset': typeof authUserResetRoute @@ -395,6 +454,12 @@ export interface FileRoutesByFullPath { '/errors/$error': typeof AuthenticatedErrorsErrorRoute '/models/$section': typeof AuthenticatedModelsSectionRoute '/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute + '/docs/integration/claude-code': typeof DocsIntegrationClaudeCodeRoute + '/docs/integration/code-buddy': typeof DocsIntegrationCodeBuddyRoute + '/docs/integration/codex': typeof DocsIntegrationCodexRoute + '/docs/integration/gemini-cli': typeof DocsIntegrationGeminiCliRoute + '/docs/integration/open-code': typeof DocsIntegrationOpenCodeRoute + '/docs/integration/trace': typeof DocsIntegrationTraceRoute '/channels/': typeof AuthenticatedChannelsIndexRoute '/dashboard/': typeof AuthenticatedDashboardIndexRoute '/keys/': typeof AuthenticatedKeysIndexRoute @@ -407,6 +472,7 @@ export interface FileRoutesByFullPath { '/usage-logs/': typeof AuthenticatedUsageLogsIndexRoute '/users/': typeof AuthenticatedUsersIndexRoute '/wallet/': typeof AuthenticatedWalletIndexRoute + '/docs/integration/': typeof DocsIntegrationIndexRoute '/pricing/$modelId/': typeof PricingModelIdIndexRoute '/system-settings/auth/$section': typeof AuthenticatedSystemSettingsAuthSectionRoute '/system-settings/content/$section': typeof AuthenticatedSystemSettingsContentSectionRoute @@ -441,6 +507,7 @@ export interface FileRoutesByTo { '/chat2link': typeof AuthenticatedChat2linkRoute '/oauth/$provider': typeof OauthProviderRoute '/about': typeof AboutIndexRoute + '/docs': typeof DocsIndexRoute '/pricing': typeof PricingIndexRoute '/setup': typeof SetupIndexRoute '/user/reset': typeof authUserResetRoute @@ -449,6 +516,12 @@ export interface FileRoutesByTo { '/errors/$error': typeof AuthenticatedErrorsErrorRoute '/models/$section': typeof AuthenticatedModelsSectionRoute '/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute + '/docs/integration/claude-code': typeof DocsIntegrationClaudeCodeRoute + '/docs/integration/code-buddy': typeof DocsIntegrationCodeBuddyRoute + '/docs/integration/codex': typeof DocsIntegrationCodexRoute + '/docs/integration/gemini-cli': typeof DocsIntegrationGeminiCliRoute + '/docs/integration/open-code': typeof DocsIntegrationOpenCodeRoute + '/docs/integration/trace': typeof DocsIntegrationTraceRoute '/channels': typeof AuthenticatedChannelsIndexRoute '/dashboard': typeof AuthenticatedDashboardIndexRoute '/keys': typeof AuthenticatedKeysIndexRoute @@ -461,6 +534,7 @@ export interface FileRoutesByTo { '/usage-logs': typeof AuthenticatedUsageLogsIndexRoute '/users': typeof AuthenticatedUsersIndexRoute '/wallet': typeof AuthenticatedWalletIndexRoute + '/docs/integration': typeof DocsIntegrationIndexRoute '/pricing/$modelId': typeof PricingModelIdIndexRoute '/system-settings/auth/$section': typeof AuthenticatedSystemSettingsAuthSectionRoute '/system-settings/content/$section': typeof AuthenticatedSystemSettingsContentSectionRoute @@ -485,6 +559,7 @@ export interface FileRoutesById { '/privacy-policy': typeof PrivacyPolicyRoute '/user-agreement': typeof UserAgreementRoute '/_authenticated/system-settings': typeof AuthenticatedSystemSettingsRouteRouteWithChildren + '/docs/integration': typeof DocsIntegrationRouteRouteWithChildren '/(auth)/forgot-password': typeof authForgotPasswordRoute '/(auth)/oauth': typeof authOauthRoute '/(auth)/otp': typeof authOtpRoute @@ -499,6 +574,7 @@ export interface FileRoutesById { '/_authenticated/chat2link': typeof AuthenticatedChat2linkRoute '/oauth/$provider': typeof OauthProviderRoute '/about/': typeof AboutIndexRoute + '/docs/': typeof DocsIndexRoute '/pricing/': typeof PricingIndexRoute '/setup/': typeof SetupIndexRoute '/(auth)/user/reset': typeof authUserResetRoute @@ -507,6 +583,12 @@ export interface FileRoutesById { '/_authenticated/errors/$error': typeof AuthenticatedErrorsErrorRoute '/_authenticated/models/$section': typeof AuthenticatedModelsSectionRoute '/_authenticated/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute + '/docs/integration/claude-code': typeof DocsIntegrationClaudeCodeRoute + '/docs/integration/code-buddy': typeof DocsIntegrationCodeBuddyRoute + '/docs/integration/codex': typeof DocsIntegrationCodexRoute + '/docs/integration/gemini-cli': typeof DocsIntegrationGeminiCliRoute + '/docs/integration/open-code': typeof DocsIntegrationOpenCodeRoute + '/docs/integration/trace': typeof DocsIntegrationTraceRoute '/_authenticated/channels/': typeof AuthenticatedChannelsIndexRoute '/_authenticated/dashboard/': typeof AuthenticatedDashboardIndexRoute '/_authenticated/keys/': typeof AuthenticatedKeysIndexRoute @@ -519,6 +601,7 @@ export interface FileRoutesById { '/_authenticated/usage-logs/': typeof AuthenticatedUsageLogsIndexRoute '/_authenticated/users/': typeof AuthenticatedUsersIndexRoute '/_authenticated/wallet/': typeof AuthenticatedWalletIndexRoute + '/docs/integration/': typeof DocsIntegrationIndexRoute '/pricing/$modelId/': typeof PricingModelIdIndexRoute '/_authenticated/system-settings/auth/$section': typeof AuthenticatedSystemSettingsAuthSectionRoute '/_authenticated/system-settings/content/$section': typeof AuthenticatedSystemSettingsContentSectionRoute @@ -542,6 +625,7 @@ export interface FileRouteTypes { | '/privacy-policy' | '/user-agreement' | '/system-settings' + | '/docs/integration' | '/forgot-password' | '/oauth' | '/otp' @@ -556,6 +640,7 @@ export interface FileRouteTypes { | '/chat2link' | '/oauth/$provider' | '/about/' + | '/docs/' | '/pricing/' | '/setup/' | '/user/reset' @@ -564,6 +649,12 @@ export interface FileRouteTypes { | '/errors/$error' | '/models/$section' | '/usage-logs/$section' + | '/docs/integration/claude-code' + | '/docs/integration/code-buddy' + | '/docs/integration/codex' + | '/docs/integration/gemini-cli' + | '/docs/integration/open-code' + | '/docs/integration/trace' | '/channels/' | '/dashboard/' | '/keys/' @@ -576,6 +667,7 @@ export interface FileRouteTypes { | '/usage-logs/' | '/users/' | '/wallet/' + | '/docs/integration/' | '/pricing/$modelId/' | '/system-settings/auth/$section' | '/system-settings/content/$section' @@ -610,6 +702,7 @@ export interface FileRouteTypes { | '/chat2link' | '/oauth/$provider' | '/about' + | '/docs' | '/pricing' | '/setup' | '/user/reset' @@ -618,6 +711,12 @@ export interface FileRouteTypes { | '/errors/$error' | '/models/$section' | '/usage-logs/$section' + | '/docs/integration/claude-code' + | '/docs/integration/code-buddy' + | '/docs/integration/codex' + | '/docs/integration/gemini-cli' + | '/docs/integration/open-code' + | '/docs/integration/trace' | '/channels' | '/dashboard' | '/keys' @@ -630,6 +729,7 @@ export interface FileRouteTypes { | '/usage-logs' | '/users' | '/wallet' + | '/docs/integration' | '/pricing/$modelId' | '/system-settings/auth/$section' | '/system-settings/content/$section' @@ -653,6 +753,7 @@ export interface FileRouteTypes { | '/privacy-policy' | '/user-agreement' | '/_authenticated/system-settings' + | '/docs/integration' | '/(auth)/forgot-password' | '/(auth)/oauth' | '/(auth)/otp' @@ -667,6 +768,7 @@ export interface FileRouteTypes { | '/_authenticated/chat2link' | '/oauth/$provider' | '/about/' + | '/docs/' | '/pricing/' | '/setup/' | '/(auth)/user/reset' @@ -675,6 +777,12 @@ export interface FileRouteTypes { | '/_authenticated/errors/$error' | '/_authenticated/models/$section' | '/_authenticated/usage-logs/$section' + | '/docs/integration/claude-code' + | '/docs/integration/code-buddy' + | '/docs/integration/codex' + | '/docs/integration/gemini-cli' + | '/docs/integration/open-code' + | '/docs/integration/trace' | '/_authenticated/channels/' | '/_authenticated/dashboard/' | '/_authenticated/keys/' @@ -687,6 +795,7 @@ export interface FileRouteTypes { | '/_authenticated/usage-logs/' | '/_authenticated/users/' | '/_authenticated/wallet/' + | '/docs/integration/' | '/pricing/$modelId/' | '/_authenticated/system-settings/auth/$section' | '/_authenticated/system-settings/content/$section' @@ -710,6 +819,7 @@ export interface RootRouteChildren { AuthenticatedRouteRoute: typeof AuthenticatedRouteRouteWithChildren PrivacyPolicyRoute: typeof PrivacyPolicyRoute UserAgreementRoute: typeof UserAgreementRoute + DocsIntegrationRouteRoute: typeof DocsIntegrationRouteRouteWithChildren errors401Route: typeof errors401Route errors403Route: typeof errors403Route errors404Route: typeof errors404Route @@ -717,6 +827,7 @@ export interface RootRouteChildren { errors503Route: typeof errors503Route OauthProviderRoute: typeof OauthProviderRoute AboutIndexRoute: typeof AboutIndexRoute + DocsIndexRoute: typeof DocsIndexRoute PricingIndexRoute: typeof PricingIndexRoute SetupIndexRoute: typeof SetupIndexRoute PricingModelIdIndexRoute: typeof PricingModelIdIndexRoute @@ -773,6 +884,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof PricingIndexRouteImport parentRoute: typeof rootRouteImport } + '/docs/': { + id: '/docs/' + path: '/docs' + fullPath: '/docs/' + preLoaderRoute: typeof DocsIndexRouteImport + parentRoute: typeof rootRouteImport + } '/about/': { id: '/about/' path: '/about' @@ -871,6 +989,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof authForgotPasswordRouteImport parentRoute: typeof authRouteRoute } + '/docs/integration': { + id: '/docs/integration' + path: '/docs/integration' + fullPath: '/docs/integration' + preLoaderRoute: typeof DocsIntegrationRouteRouteImport + parentRoute: typeof rootRouteImport + } '/_authenticated/system-settings': { id: '/_authenticated/system-settings' path: '/system-settings' @@ -885,6 +1010,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof PricingModelIdIndexRouteImport parentRoute: typeof rootRouteImport } + '/docs/integration/': { + id: '/docs/integration/' + path: '/' + fullPath: '/docs/integration/' + preLoaderRoute: typeof DocsIntegrationIndexRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } '/_authenticated/wallet/': { id: '/_authenticated/wallet/' path: '/wallet' @@ -969,6 +1101,48 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedChannelsIndexRouteImport parentRoute: typeof AuthenticatedRouteRoute } + '/docs/integration/trace': { + id: '/docs/integration/trace' + path: '/trace' + fullPath: '/docs/integration/trace' + preLoaderRoute: typeof DocsIntegrationTraceRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } + '/docs/integration/open-code': { + id: '/docs/integration/open-code' + path: '/open-code' + fullPath: '/docs/integration/open-code' + preLoaderRoute: typeof DocsIntegrationOpenCodeRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } + '/docs/integration/gemini-cli': { + id: '/docs/integration/gemini-cli' + path: '/gemini-cli' + fullPath: '/docs/integration/gemini-cli' + preLoaderRoute: typeof DocsIntegrationGeminiCliRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } + '/docs/integration/codex': { + id: '/docs/integration/codex' + path: '/codex' + fullPath: '/docs/integration/codex' + preLoaderRoute: typeof DocsIntegrationCodexRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } + '/docs/integration/code-buddy': { + id: '/docs/integration/code-buddy' + path: '/code-buddy' + fullPath: '/docs/integration/code-buddy' + preLoaderRoute: typeof DocsIntegrationCodeBuddyRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } + '/docs/integration/claude-code': { + id: '/docs/integration/claude-code' + path: '/claude-code' + fullPath: '/docs/integration/claude-code' + preLoaderRoute: typeof DocsIntegrationClaudeCodeRouteImport + parentRoute: typeof DocsIntegrationRouteRoute + } '/_authenticated/usage-logs/$section': { id: '/_authenticated/usage-logs/$section' path: '/usage-logs/$section' @@ -1240,12 +1414,36 @@ const AuthenticatedRouteRouteChildren: AuthenticatedRouteRouteChildren = { const AuthenticatedRouteRouteWithChildren = AuthenticatedRouteRoute._addFileChildren(AuthenticatedRouteRouteChildren) +interface DocsIntegrationRouteRouteChildren { + DocsIntegrationClaudeCodeRoute: typeof DocsIntegrationClaudeCodeRoute + DocsIntegrationCodeBuddyRoute: typeof DocsIntegrationCodeBuddyRoute + DocsIntegrationCodexRoute: typeof DocsIntegrationCodexRoute + DocsIntegrationGeminiCliRoute: typeof DocsIntegrationGeminiCliRoute + DocsIntegrationOpenCodeRoute: typeof DocsIntegrationOpenCodeRoute + DocsIntegrationTraceRoute: typeof DocsIntegrationTraceRoute + DocsIntegrationIndexRoute: typeof DocsIntegrationIndexRoute +} + +const DocsIntegrationRouteRouteChildren: DocsIntegrationRouteRouteChildren = { + DocsIntegrationClaudeCodeRoute: DocsIntegrationClaudeCodeRoute, + DocsIntegrationCodeBuddyRoute: DocsIntegrationCodeBuddyRoute, + DocsIntegrationCodexRoute: DocsIntegrationCodexRoute, + DocsIntegrationGeminiCliRoute: DocsIntegrationGeminiCliRoute, + DocsIntegrationOpenCodeRoute: DocsIntegrationOpenCodeRoute, + DocsIntegrationTraceRoute: DocsIntegrationTraceRoute, + DocsIntegrationIndexRoute: DocsIntegrationIndexRoute, +} + +const DocsIntegrationRouteRouteWithChildren = + DocsIntegrationRouteRoute._addFileChildren(DocsIntegrationRouteRouteChildren) + const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, authRouteRoute: authRouteRouteWithChildren, AuthenticatedRouteRoute: AuthenticatedRouteRouteWithChildren, PrivacyPolicyRoute: PrivacyPolicyRoute, UserAgreementRoute: UserAgreementRoute, + DocsIntegrationRouteRoute: DocsIntegrationRouteRouteWithChildren, errors401Route: errors401Route, errors403Route: errors403Route, errors404Route: errors404Route, @@ -1253,6 +1451,7 @@ const rootRouteChildren: RootRouteChildren = { errors503Route: errors503Route, OauthProviderRoute: OauthProviderRoute, AboutIndexRoute: AboutIndexRoute, + DocsIndexRoute: DocsIndexRoute, PricingIndexRoute: PricingIndexRoute, SetupIndexRoute: SetupIndexRoute, PricingModelIdIndexRoute: PricingModelIdIndexRoute, diff --git a/web/default/src/routes/docs/index.tsx b/web/default/src/routes/docs/index.tsx new file mode 100644 index 000000000000..16b1b737f758 --- /dev/null +++ b/web/default/src/routes/docs/index.tsx @@ -0,0 +1,7 @@ +import { createFileRoute, redirect } from '@tanstack/react-router' + +export const Route = createFileRoute('/docs/')({ + beforeLoad: () => { + throw redirect({ to: '/docs/integration' }) + }, +}) diff --git a/web/default/src/routes/docs/integration/claude-code.tsx b/web/default/src/routes/docs/integration/claude-code.tsx new file mode 100644 index 000000000000..a95e9006d9f7 --- /dev/null +++ b/web/default/src/routes/docs/integration/claude-code.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { ClaudeCodePage } from '@/features/docs/integration/pages/claude-code' + +export const Route = createFileRoute('/docs/integration/claude-code')({ + component: ClaudeCodePage, +}) diff --git a/web/default/src/routes/docs/integration/code-buddy.tsx b/web/default/src/routes/docs/integration/code-buddy.tsx new file mode 100644 index 000000000000..191b27611a3f --- /dev/null +++ b/web/default/src/routes/docs/integration/code-buddy.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { CodeBuddyPage } from '@/features/docs/integration/pages/code-buddy' + +export const Route = createFileRoute('/docs/integration/code-buddy')({ + component: CodeBuddyPage, +}) diff --git a/web/default/src/routes/docs/integration/codex.tsx b/web/default/src/routes/docs/integration/codex.tsx new file mode 100644 index 000000000000..2012b20a7b48 --- /dev/null +++ b/web/default/src/routes/docs/integration/codex.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { CodexPage } from '@/features/docs/integration/pages/codex' + +export const Route = createFileRoute('/docs/integration/codex')({ + component: CodexPage, +}) diff --git a/web/default/src/routes/docs/integration/gemini-cli.tsx b/web/default/src/routes/docs/integration/gemini-cli.tsx new file mode 100644 index 000000000000..1b71422b1375 --- /dev/null +++ b/web/default/src/routes/docs/integration/gemini-cli.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { GeminiCliPage } from '@/features/docs/integration/pages/gemini-cli' + +export const Route = createFileRoute('/docs/integration/gemini-cli')({ + component: GeminiCliPage, +}) diff --git a/web/default/src/routes/docs/integration/index.tsx b/web/default/src/routes/docs/integration/index.tsx new file mode 100644 index 000000000000..2d91d6544051 --- /dev/null +++ b/web/default/src/routes/docs/integration/index.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { IntegrationHome } from '@/features/docs/integration' + +export const Route = createFileRoute('/docs/integration/')({ + component: IntegrationHome, +}) diff --git a/web/default/src/routes/docs/integration/open-code.tsx b/web/default/src/routes/docs/integration/open-code.tsx new file mode 100644 index 000000000000..49faa7c022d1 --- /dev/null +++ b/web/default/src/routes/docs/integration/open-code.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { OpenCodePage } from '@/features/docs/integration/pages/open-code' + +export const Route = createFileRoute('/docs/integration/open-code')({ + component: OpenCodePage, +}) diff --git a/web/default/src/routes/docs/integration/route.tsx b/web/default/src/routes/docs/integration/route.tsx new file mode 100644 index 000000000000..2b6127ecdb55 --- /dev/null +++ b/web/default/src/routes/docs/integration/route.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { IntegrationDocsShell } from '@/features/docs/integration/integration-layout' + +export const Route = createFileRoute('/docs/integration')({ + component: IntegrationDocsShell, +}) diff --git a/web/default/src/routes/docs/integration/trace.tsx b/web/default/src/routes/docs/integration/trace.tsx new file mode 100644 index 000000000000..81391f811761 --- /dev/null +++ b/web/default/src/routes/docs/integration/trace.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { TracePage } from '@/features/docs/integration/pages/trace' + +export const Route = createFileRoute('/docs/integration/trace')({ + component: TracePage, +})