Merge remote-tracking branch 'upstream/main' into fix/mobile-usage-log-cost-alignment
# Conflicts: # web/default/src/features/usage-logs/components/usage-logs-mobile-card.tsx
This commit is contained in:
Vendored
-2837
File diff suppressed because it is too large
Load Diff
Vendored
+10
-10
@@ -24,7 +24,7 @@
|
||||
"@hookform/resolvers": "^5.4.0",
|
||||
"@hugeicons/core-free-icons": "^4.1.4",
|
||||
"@hugeicons/react": "^1.1.6",
|
||||
"@lobehub/icons": "^5.8.0",
|
||||
"@lobehub/icons": "catalog:",
|
||||
"@tailwindcss/postcss": "^4.3.0",
|
||||
"@tanstack/react-query": "^5.100.14",
|
||||
"@tanstack/react-router": "^1.170.8",
|
||||
@@ -34,12 +34,12 @@
|
||||
"@visactor/vchart": "^2.0.22",
|
||||
"ai": "^6.0.191",
|
||||
"auto-skeleton-react": "^1.0.5",
|
||||
"axios": "^1.16.1",
|
||||
"axios": "catalog:",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"clsx": "catalog:",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.3.0",
|
||||
"dayjs": "^1.11.20",
|
||||
"dayjs": "catalog:",
|
||||
"i18next": "^26.2.0",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"input-otp": "^1.4.2",
|
||||
@@ -47,22 +47,22 @@
|
||||
"motion": "^12.40.0",
|
||||
"nanoid": "^5.1.11",
|
||||
"next-themes": "^0.4.6",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"qrcode.react": "catalog:",
|
||||
"react": "^19.2.6",
|
||||
"react-day-picker": "^10.0.1",
|
||||
"react-dom": "^19.2.6",
|
||||
"react-hook-form": "^7.76.1",
|
||||
"react-i18next": "^17.0.8",
|
||||
"react-icons": "^5.6.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-icons": "catalog:",
|
||||
"react-markdown": "catalog:",
|
||||
"react-resizable-panels": "^4.11.2",
|
||||
"react-top-loading-bar": "^3.0.2",
|
||||
"recharts": "3.8.1",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-gfm": "catalog:",
|
||||
"shiki": "^4.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
"sse.js": "^2.8.0",
|
||||
"sse.js": "catalog:",
|
||||
"streamdown": "^2.5.0",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"tailwindcss": "^4.3.0",
|
||||
@@ -92,7 +92,7 @@
|
||||
"eslint-plugin-react-refresh": "^0.5.2",
|
||||
"globals": "^17.6.0",
|
||||
"knip": "^6.14.2",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier": "catalog:",
|
||||
"prettier-plugin-tailwindcss": "^0.8.0",
|
||||
"shadcn": "^4.8.0",
|
||||
"typescript": "~6.0.3",
|
||||
|
||||
Vendored
+1
@@ -65,6 +65,7 @@ export default defineConfig(({ envMode }) => {
|
||||
},
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
strictPort: true,
|
||||
proxy: devProxy,
|
||||
},
|
||||
output: {
|
||||
|
||||
+99
-1
@@ -31,7 +31,99 @@ import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Label } from '@/components/ui/label'
|
||||
|
||||
const Form = FormProvider
|
||||
type FormRootContextValue = {
|
||||
id: string
|
||||
}
|
||||
|
||||
const FormRootContext = React.createContext<FormRootContextValue | null>(null)
|
||||
|
||||
function getFormScopedSelector(formId: string, selector: string): string {
|
||||
return `[data-form-root="${formId}"]${selector}`
|
||||
}
|
||||
|
||||
function hasFormErrors(errors: unknown): boolean {
|
||||
return (
|
||||
typeof errors === 'object' &&
|
||||
errors !== null &&
|
||||
Object.keys(errors).length > 0
|
||||
)
|
||||
}
|
||||
|
||||
function getFirstFormErrorTarget(
|
||||
invalidControl: HTMLElement | null,
|
||||
errorMessage: HTMLElement | null
|
||||
): HTMLElement | null {
|
||||
if (!invalidControl) return errorMessage
|
||||
if (!errorMessage) return invalidControl
|
||||
|
||||
const position = invalidControl.compareDocumentPosition(errorMessage)
|
||||
return position & Node.DOCUMENT_POSITION_PRECEDING
|
||||
? errorMessage
|
||||
: invalidControl
|
||||
}
|
||||
|
||||
function FormValidationFocus() {
|
||||
const formContext = React.useContext(FormRootContext)
|
||||
const { control } = useFormContext()
|
||||
const { errors, submitCount } = useFormState({ control })
|
||||
const handledSubmitCountRef = React.useRef(0)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!formContext || submitCount === 0 || !hasFormErrors(errors)) return
|
||||
if (handledSubmitCountRef.current === submitCount) return
|
||||
|
||||
handledSubmitCountRef.current = submitCount
|
||||
|
||||
const animationFrameId = window.requestAnimationFrame(() => {
|
||||
const invalidControl = document.querySelector<HTMLElement>(
|
||||
getFormScopedSelector(formContext.id, '[aria-invalid="true"]')
|
||||
)
|
||||
const errorMessage = document.querySelector<HTMLElement>(
|
||||
getFormScopedSelector(formContext.id, '[data-slot="form-message"]')
|
||||
)
|
||||
const target = getFirstFormErrorTarget(invalidControl, errorMessage)
|
||||
if (!target) return
|
||||
|
||||
const formItem = target.closest<HTMLElement>(
|
||||
getFormScopedSelector(formContext.id, '[data-slot="form-item"]')
|
||||
)
|
||||
const scrollTarget = formItem ?? target
|
||||
const focusTarget =
|
||||
target === invalidControl
|
||||
? invalidControl
|
||||
: (formItem?.querySelector<HTMLElement>(
|
||||
'[aria-invalid="true"], input, textarea, select, button, [tabindex]:not([tabindex="-1"])'
|
||||
) ?? null)
|
||||
|
||||
scrollTarget.scrollIntoView({ block: 'center', behavior: 'smooth' })
|
||||
focusTarget?.focus({ preventScroll: true })
|
||||
})
|
||||
|
||||
return () => window.cancelAnimationFrame(animationFrameId)
|
||||
}, [errors, formContext, submitCount])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function Form<TFieldValues extends FieldValues = FieldValues>({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof FormProvider<TFieldValues>>) {
|
||||
const reactId = React.useId()
|
||||
const id = React.useMemo(
|
||||
() => `form-${reactId.replaceAll(/[^a-zA-Z0-9_-]/g, '_')}`,
|
||||
[reactId]
|
||||
)
|
||||
|
||||
return (
|
||||
<FormRootContext.Provider value={{ id }}>
|
||||
<FormProvider {...props}>
|
||||
<FormValidationFocus />
|
||||
{children}
|
||||
</FormProvider>
|
||||
</FormRootContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
@@ -90,11 +182,13 @@ const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
|
||||
function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
const id = React.useId()
|
||||
const formContext = React.useContext(FormRootContext)
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div
|
||||
data-slot='form-item'
|
||||
data-form-root={formContext?.id}
|
||||
className={cn('grid gap-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -124,11 +218,13 @@ function FormControl({
|
||||
...props
|
||||
}: { children: React.ReactElement } & Record<string, unknown>) {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||
const formContext = React.useContext(FormRootContext)
|
||||
|
||||
return useRender({
|
||||
render: children,
|
||||
props: {
|
||||
'data-slot': 'form-control',
|
||||
'data-form-root': formContext?.id,
|
||||
id: formItemId,
|
||||
'aria-describedby': !error
|
||||
? `${formDescriptionId}`
|
||||
@@ -154,6 +250,7 @@ function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
|
||||
function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
const { error, formMessageId } = useFormField()
|
||||
const formContext = React.useContext(FormRootContext)
|
||||
const { t } = useTranslation()
|
||||
const body = error ? String(error?.message ?? '') : props.children
|
||||
|
||||
@@ -166,6 +263,7 @@ function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
return (
|
||||
<p
|
||||
data-slot='form-message'
|
||||
data-form-root={formContext?.id}
|
||||
id={formMessageId}
|
||||
className={cn('text-destructive text-sm', className)}
|
||||
{...props}
|
||||
|
||||
+23
-13
@@ -24,7 +24,7 @@ import {
|
||||
useCallback,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { type SubmitErrorHandler, useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import {
|
||||
@@ -140,6 +140,7 @@ import {
|
||||
hasModelConfigChanged,
|
||||
findMissingModelsInMapping,
|
||||
validateModelMappingJson,
|
||||
hasAdvancedSettingsErrors,
|
||||
} from '../../lib'
|
||||
import {
|
||||
collectInvalidStatusCodeEntries,
|
||||
@@ -204,7 +205,6 @@ function readAdvancedSettingsPreference(): boolean {
|
||||
|
||||
function hasAdvancedSettingsValues(values: ChannelFormValues): boolean {
|
||||
return Boolean(
|
||||
values.model_mapping?.trim() ||
|
||||
values.param_override?.trim() ||
|
||||
values.header_override?.trim() ||
|
||||
values.status_code_mapping?.trim() ||
|
||||
@@ -1008,6 +1008,26 @@ export function ChannelMutateDrawer({
|
||||
]
|
||||
)
|
||||
|
||||
const handleAdvancedSettingsOpenChange = useCallback((nextOpen: boolean) => {
|
||||
setAdvancedSettingsOpen(nextOpen)
|
||||
if (typeof window !== 'undefined') {
|
||||
window.localStorage.setItem(
|
||||
ADVANCED_SETTINGS_EXPANDED_KEY,
|
||||
String(nextOpen)
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onInvalid: SubmitErrorHandler<ChannelFormValues> = useCallback(
|
||||
(errors) => {
|
||||
if (hasAdvancedSettingsErrors(errors)) {
|
||||
handleAdvancedSettingsOpenChange(true)
|
||||
}
|
||||
toast.error(t('Please fix the highlighted fields before saving'))
|
||||
},
|
||||
[handleAdvancedSettingsOpenChange, t]
|
||||
)
|
||||
|
||||
// Handle drawer close
|
||||
const handleOpenChange = useCallback(
|
||||
(v: boolean) => {
|
||||
@@ -1020,16 +1040,6 @@ export function ChannelMutateDrawer({
|
||||
[onOpenChange, form]
|
||||
)
|
||||
|
||||
const handleAdvancedSettingsOpenChange = useCallback((nextOpen: boolean) => {
|
||||
setAdvancedSettingsOpen(nextOpen)
|
||||
if (typeof window !== 'undefined') {
|
||||
window.localStorage.setItem(
|
||||
ADVANCED_SETTINGS_EXPANDED_KEY,
|
||||
String(nextOpen)
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sheet open={open} onOpenChange={handleOpenChange}>
|
||||
@@ -1060,7 +1070,7 @@ export function ChannelMutateDrawer({
|
||||
<Form {...form}>
|
||||
<form
|
||||
id='channel-form'
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
onSubmit={form.handleSubmit(onSubmit, onInvalid)}
|
||||
className={sideDrawerFormClassName('gap-5')}
|
||||
>
|
||||
{isChannelDetailLoading ? (
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (C) 2023-2026 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import type { FieldPath } from 'react-hook-form'
|
||||
import type { ChannelFormValues } from './channel-form'
|
||||
|
||||
type ChannelFormErrorMap = Partial<
|
||||
Record<FieldPath<ChannelFormValues>, unknown>
|
||||
>
|
||||
|
||||
const ADVANCED_SETTINGS_FIELDS = new Set<FieldPath<ChannelFormValues>>([
|
||||
'priority',
|
||||
'weight',
|
||||
'test_model',
|
||||
'auto_ban',
|
||||
'tag',
|
||||
'remark',
|
||||
'param_override',
|
||||
'header_override',
|
||||
'status_code_mapping',
|
||||
'force_format',
|
||||
'thinking_to_content',
|
||||
'pass_through_body_enabled',
|
||||
'proxy',
|
||||
'system_prompt',
|
||||
'system_prompt_override',
|
||||
'allow_service_tier',
|
||||
'disable_store',
|
||||
'allow_safety_identifier',
|
||||
'allow_include_obfuscation',
|
||||
'allow_inference_geo',
|
||||
'allow_speed',
|
||||
'claude_beta_query',
|
||||
'upstream_model_update_check_enabled',
|
||||
'upstream_model_update_auto_sync_enabled',
|
||||
'upstream_model_update_ignored_models',
|
||||
])
|
||||
|
||||
export function isAdvancedSettingsField(
|
||||
fieldName: string
|
||||
): fieldName is FieldPath<ChannelFormValues> {
|
||||
return ADVANCED_SETTINGS_FIELDS.has(fieldName as FieldPath<ChannelFormValues>)
|
||||
}
|
||||
|
||||
export function hasAdvancedSettingsErrors(
|
||||
errors: ChannelFormErrorMap
|
||||
): boolean {
|
||||
return Object.keys(errors).some((fieldName) =>
|
||||
isAdvancedSettingsField(fieldName)
|
||||
)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
// Re-export all library functions
|
||||
export * from './channel-actions'
|
||||
export * from './channel-form-errors'
|
||||
export * from './channel-form'
|
||||
export * from './channel-type-config'
|
||||
export * from './channel-utils'
|
||||
|
||||
@@ -189,6 +189,7 @@ export function CCSwitchDialog(props: Props) {
|
||||
onValueChange={setName}
|
||||
placeholder={currentConfig.defaultName}
|
||||
emptyText=''
|
||||
allowCustomValue={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -196,6 +196,7 @@ export function ModelMutateDrawer({
|
||||
'grok.violation_deduction_amount': 0,
|
||||
'channel_affinity_setting.enabled': false,
|
||||
'channel_affinity_setting.switch_on_success': true,
|
||||
'channel_affinity_setting.keep_on_channel_disabled': false,
|
||||
'channel_affinity_setting.max_entries': 100000,
|
||||
'channel_affinity_setting.default_ttl_seconds': 3600,
|
||||
'channel_affinity_setting.rules': '[]',
|
||||
|
||||
@@ -56,8 +56,9 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
|
||||
const tags = parseTags(props.model.tags)
|
||||
const groups = props.model.enable_groups || []
|
||||
const endpoints = props.model.supported_endpoint_types || []
|
||||
const vendorIcon = props.model.vendor_icon
|
||||
? getLobeIcon(props.model.vendor_icon, 28)
|
||||
const modelIconKey = props.model.icon || props.model.vendor_icon
|
||||
const modelIcon = modelIconKey
|
||||
? getLobeIcon(modelIconKey, 28)
|
||||
: null
|
||||
const initial = props.model.model_name?.charAt(0).toUpperCase() || '?'
|
||||
const isDynamicPricing =
|
||||
@@ -97,7 +98,7 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
|
||||
<div className='flex items-start justify-between gap-2.5 sm:gap-3'>
|
||||
<div className='flex min-w-0 items-start gap-2.5 sm:gap-3'>
|
||||
<div className='bg-muted/40 flex size-9 shrink-0 items-center justify-center rounded-lg sm:size-10 sm:rounded-xl'>
|
||||
{vendorIcon || (
|
||||
{modelIcon || (
|
||||
<span className='text-muted-foreground text-sm font-bold'>
|
||||
{initial}
|
||||
</span>
|
||||
|
||||
@@ -268,8 +268,9 @@ function OverviewSummaryGrid(props: { model: PricingModel }) {
|
||||
function ModelHeader(props: { model: PricingModel }) {
|
||||
const { t } = useTranslation()
|
||||
const model = props.model
|
||||
const vendorIcon = model.vendor_icon
|
||||
? getLobeIcon(model.vendor_icon, 20)
|
||||
const modelIconKey = model.icon || model.vendor_icon
|
||||
const modelIcon = modelIconKey
|
||||
? getLobeIcon(modelIconKey, 20)
|
||||
: null
|
||||
const description = model.description || model.vendor_description || null
|
||||
const tags = parseTags(model.tags)
|
||||
@@ -281,7 +282,7 @@ function ModelHeader(props: { model: PricingModel }) {
|
||||
return (
|
||||
<header className='pb-4'>
|
||||
<div className='flex items-center gap-2.5'>
|
||||
{vendorIcon}
|
||||
{modelIcon}
|
||||
<h1 className='font-mono text-xl font-bold tracking-tight sm:text-2xl'>
|
||||
{model.model_name}
|
||||
</h1>
|
||||
|
||||
@@ -106,13 +106,14 @@ export function usePricingColumns(
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const model = row.original
|
||||
const vendorIcon = model.vendor_icon
|
||||
? getLobeIcon(model.vendor_icon, 14)
|
||||
const modelIconKey = model.icon || model.vendor_icon
|
||||
const modelIcon = modelIconKey
|
||||
? getLobeIcon(modelIconKey, 14)
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className='flex min-w-[200px] items-center gap-2'>
|
||||
{vendorIcon}
|
||||
{modelIcon}
|
||||
<span className='truncate font-mono text-sm font-medium'>
|
||||
{model.model_name}
|
||||
</span>
|
||||
|
||||
+1
@@ -31,6 +31,7 @@ export type PricingModel = {
|
||||
id: number
|
||||
model_name: string
|
||||
description?: string
|
||||
icon?: string
|
||||
vendor_id?: number
|
||||
vendor_name?: string
|
||||
vendor_icon?: string
|
||||
|
||||
+20
-3
@@ -111,6 +111,7 @@ export function SubscriptionPurchaseDialog(props: Props) {
|
||||
Math.ceil(Number(plan.price_amount || 0) * quotaPerUnit)
|
||||
)
|
||||
const userQuota = Math.max(0, Number(props.userQuota || 0))
|
||||
const allowBalancePay = plan.allow_balance_pay !== false
|
||||
const insufficientBalance = userQuota < balanceCost
|
||||
const limitReached =
|
||||
(props.purchaseLimit || 0) > 0 &&
|
||||
@@ -232,6 +233,10 @@ export function SubscriptionPurchaseDialog(props: Props) {
|
||||
}
|
||||
|
||||
const handlePayBalance = async () => {
|
||||
if (!allowBalancePay) {
|
||||
toast.error(t('This plan does not allow balance redemption'))
|
||||
return
|
||||
}
|
||||
setPaying(true)
|
||||
try {
|
||||
const res = await paySubscriptionBalance({ plan_id: plan.id })
|
||||
@@ -332,15 +337,27 @@ export function SubscriptionPurchaseDialog(props: Props) {
|
||||
<span className='text-muted-foreground'>{t('Available')}</span>
|
||||
<span>{formatQuota(userQuota)}</span>
|
||||
</div>
|
||||
{insufficientBalance && (
|
||||
{!allowBalancePay ? (
|
||||
<Alert variant='destructive'>
|
||||
<AlertDescription>{t('Insufficient balance')}</AlertDescription>
|
||||
<AlertDescription>
|
||||
{t('This plan does not allow balance redemption')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : (
|
||||
insufficientBalance && (
|
||||
<Alert variant='destructive'>
|
||||
<AlertDescription>
|
||||
{t('Insufficient balance')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)
|
||||
)}
|
||||
<Button
|
||||
variant='outline'
|
||||
onClick={handlePayBalance}
|
||||
disabled={paying || limitReached || insufficientBalance}
|
||||
disabled={
|
||||
paying || limitReached || !allowBalancePay || insufficientBalance
|
||||
}
|
||||
>
|
||||
{t('Pay with Balance')}
|
||||
</Button>
|
||||
|
||||
+18
@@ -461,6 +461,24 @@ export function SubscriptionsMutateDrawer({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='allow_balance_pay'
|
||||
render={({ field }) => (
|
||||
<FormItem className={sideDrawerSwitchItemClassName()}>
|
||||
<FormLabel className='!mt-0'>
|
||||
{t('Allow balance redemption')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</SideDrawerSection>
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ export function getPlanFormSchema(t: TFunction) {
|
||||
quota_reset_custom_seconds: z.coerce.number().min(0).optional(),
|
||||
enabled: z.boolean(),
|
||||
sort_order: z.coerce.number(),
|
||||
allow_balance_pay: z.boolean(),
|
||||
max_purchase_per_user: z.coerce.number().min(0),
|
||||
total_amount: z.coerce.number().min(0),
|
||||
upgrade_group: z.string().optional(),
|
||||
@@ -61,6 +62,7 @@ export const PLAN_FORM_DEFAULTS: PlanFormValues = {
|
||||
quota_reset_custom_seconds: 0,
|
||||
enabled: true,
|
||||
sort_order: 0,
|
||||
allow_balance_pay: true,
|
||||
max_purchase_per_user: 0,
|
||||
total_amount: 0,
|
||||
upgrade_group: '',
|
||||
@@ -81,6 +83,7 @@ export function planToFormValues(plan: SubscriptionPlan): PlanFormValues {
|
||||
quota_reset_custom_seconds: Number(plan.quota_reset_custom_seconds || 0),
|
||||
enabled: plan.enabled !== false,
|
||||
sort_order: Number(plan.sort_order || 0),
|
||||
allow_balance_pay: plan.allow_balance_pay !== false,
|
||||
max_purchase_per_user: Number(plan.max_purchase_per_user || 0),
|
||||
total_amount: quotaUnitsToDollars(Number(plan.total_amount || 0)),
|
||||
upgrade_group: plan.upgrade_group || '',
|
||||
|
||||
@@ -35,6 +35,7 @@ export const subscriptionPlanSchema = z.object({
|
||||
quota_reset_custom_seconds: z.number().optional(),
|
||||
enabled: z.boolean(),
|
||||
sort_order: z.number(),
|
||||
allow_balance_pay: z.boolean().optional().default(true),
|
||||
max_purchase_per_user: z.number(),
|
||||
total_amount: z.number(),
|
||||
upgrade_group: z.string().optional(),
|
||||
|
||||
@@ -100,6 +100,9 @@ export function ChannelAffinitySection(props: Props) {
|
||||
const [switchOnSuccess, setSwitchOnSuccess] = useState(
|
||||
props.defaultValues['channel_affinity_setting.switch_on_success']
|
||||
)
|
||||
const [keepOnChannelDisabled, setKeepOnChannelDisabled] = useState(
|
||||
props.defaultValues['channel_affinity_setting.keep_on_channel_disabled']
|
||||
)
|
||||
const [maxEntries, setMaxEntries] = useState(
|
||||
props.defaultValues['channel_affinity_setting.max_entries']
|
||||
)
|
||||
@@ -136,6 +139,9 @@ export function ChannelAffinitySection(props: Props) {
|
||||
setSwitchOnSuccess(
|
||||
props.defaultValues['channel_affinity_setting.switch_on_success']
|
||||
)
|
||||
setKeepOnChannelDisabled(
|
||||
props.defaultValues['channel_affinity_setting.keep_on_channel_disabled']
|
||||
)
|
||||
setMaxEntries(props.defaultValues['channel_affinity_setting.max_entries'])
|
||||
setDefaultTtl(
|
||||
props.defaultValues['channel_affinity_setting.default_ttl_seconds']
|
||||
@@ -231,6 +237,14 @@ export function ChannelAffinitySection(props: Props) {
|
||||
key: 'channel_affinity_setting.switch_on_success',
|
||||
value: String(switchOnSuccess),
|
||||
})
|
||||
if (
|
||||
keepOnChannelDisabled !==
|
||||
props.defaultValues['channel_affinity_setting.keep_on_channel_disabled']
|
||||
)
|
||||
updates.push({
|
||||
key: 'channel_affinity_setting.keep_on_channel_disabled',
|
||||
value: String(keepOnChannelDisabled),
|
||||
})
|
||||
if (
|
||||
maxEntries !==
|
||||
props.defaultValues['channel_affinity_setting.max_entries']
|
||||
@@ -397,6 +411,14 @@ export function ChannelAffinitySection(props: Props) {
|
||||
'If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.'
|
||||
)}
|
||||
/>
|
||||
<SettingsSwitchField
|
||||
checked={keepOnChannelDisabled}
|
||||
onCheckedChange={setKeepOnChannelDisabled}
|
||||
label={t('Keep affinity when channel is disabled')}
|
||||
description={t(
|
||||
'When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.'
|
||||
)}
|
||||
/>
|
||||
|
||||
<Separator />
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface CacheStats {
|
||||
export interface ChannelAffinitySettings {
|
||||
'channel_affinity_setting.enabled': boolean
|
||||
'channel_affinity_setting.switch_on_success': boolean
|
||||
'channel_affinity_setting.keep_on_channel_disabled': boolean
|
||||
'channel_affinity_setting.max_entries': number
|
||||
'channel_affinity_setting.default_ttl_seconds': number
|
||||
'channel_affinity_setting.rules': string
|
||||
|
||||
@@ -231,10 +231,10 @@ export function ClaudeSettingsCard({ defaultValues }: ClaudeSettingsCardProps) {
|
||||
render={({ field }) => (
|
||||
<SettingsSwitchItem>
|
||||
<SettingsSwitchContent>
|
||||
<FormLabel>{t('Thinking Adapter')}</FormLabel>
|
||||
<FormLabel>{t('Thinking Suffix Adapter')}</FormLabel>
|
||||
<FormDescription>
|
||||
{t(
|
||||
'Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.'
|
||||
'Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.'
|
||||
)}
|
||||
</FormDescription>
|
||||
</SettingsSwitchContent>
|
||||
|
||||
@@ -307,7 +307,7 @@ export function GeminiSettingsCard({ defaultValues }: GeminiSettingsCardProps) {
|
||||
render={({ field }) => (
|
||||
<SettingsSwitchItem>
|
||||
<SettingsSwitchContent>
|
||||
<FormLabel>{t('Thinking Adapter')}</FormLabel>
|
||||
<FormLabel>{t('Thinking Suffix Adapter')}</FormLabel>
|
||||
<FormDescription>
|
||||
{t('Supports `-thinking`, `-thinking-')}
|
||||
{'{{budget}}'}
|
||||
|
||||
@@ -227,7 +227,9 @@ export function GlobalSettingsCard({ defaultValues }: GlobalSettingsCardProps) {
|
||||
name='global.thinking_model_blacklist'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('Disable thinking processing models')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('Models that skip thinking suffix processing')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
rows={4}
|
||||
|
||||
@@ -64,6 +64,7 @@ const defaultModelSettings: ModelSettings = {
|
||||
'group_ratio_setting.group_special_usable_group': '{}',
|
||||
'channel_affinity_setting.enabled': false,
|
||||
'channel_affinity_setting.switch_on_success': true,
|
||||
'channel_affinity_setting.keep_on_channel_disabled': false,
|
||||
'channel_affinity_setting.max_entries': 100000,
|
||||
'channel_affinity_setting.default_ttl_seconds': 3600,
|
||||
'channel_affinity_setting.rules': '[]',
|
||||
|
||||
@@ -130,6 +130,8 @@ const MODELS_SECTIONS = [
|
||||
settings['channel_affinity_setting.enabled'],
|
||||
'channel_affinity_setting.switch_on_success':
|
||||
settings['channel_affinity_setting.switch_on_success'],
|
||||
'channel_affinity_setting.keep_on_channel_disabled':
|
||||
settings['channel_affinity_setting.keep_on_channel_disabled'],
|
||||
'channel_affinity_setting.max_entries':
|
||||
settings['channel_affinity_setting.max_entries'],
|
||||
'channel_affinity_setting.default_ttl_seconds':
|
||||
|
||||
@@ -176,6 +176,7 @@ export type ModelSettings = {
|
||||
'group_ratio_setting.group_special_usable_group': string
|
||||
'channel_affinity_setting.enabled': boolean
|
||||
'channel_affinity_setting.switch_on_success': boolean
|
||||
'channel_affinity_setting.keep_on_channel_disabled': boolean
|
||||
'channel_affinity_setting.max_entries': number
|
||||
'channel_affinity_setting.default_ttl_seconds': number
|
||||
'channel_affinity_setting.rules': string
|
||||
|
||||
@@ -183,7 +183,7 @@ function CommonLogsCard<TData>({
|
||||
|
||||
const modelCell = cells.get('model_name')
|
||||
const quotaCell = cells.get('quota')
|
||||
const createdAtCellOriginal = cells.get('created_at')?.row.original as
|
||||
const rowData = cells.get('created_at')?.row.original as
|
||||
| Record<string, unknown>
|
||||
| undefined
|
||||
|
||||
@@ -203,8 +203,8 @@ function CommonLogsCard<TData>({
|
||||
{t('Time')}
|
||||
</div>
|
||||
<MobileLogTimeStatus
|
||||
createdAt={createdAtCellOriginal?.created_at}
|
||||
type={createdAtCellOriginal?.type}
|
||||
createdAt={rowData?.created_at}
|
||||
type={rowData?.type}
|
||||
/>
|
||||
</div>
|
||||
<SummaryField
|
||||
|
||||
Vendored
+9
-5
@@ -134,6 +134,7 @@
|
||||
"Actual Amount": "Actual Amount",
|
||||
"Actual Model": "Actual Model",
|
||||
"Actual Model:": "Actual Model:",
|
||||
"Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.": "Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.",
|
||||
"Add": "Add",
|
||||
"Add \"{{value}}\"": "Add \"{{value}}\"",
|
||||
"Add {{title}}": "Add {{title}}",
|
||||
@@ -268,6 +269,7 @@
|
||||
"All-time": "All-time",
|
||||
"Allocated Memory": "Allocated Memory",
|
||||
"Allow accountFilter parameter": "Allow accountFilter parameter",
|
||||
"Allow balance redemption": "Allow balance redemption",
|
||||
"Allow Claude beta query passthrough": "Allow Claude beta query passthrough",
|
||||
"Allow clients to query configured ratios via `/api/ratio`.": "Allow clients to query configured ratios via `/api/ratio`.",
|
||||
"Allow HTTP image requests": "Allow HTTP image requests",
|
||||
@@ -643,6 +645,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",
|
||||
"Keep affinity when channel is disabled": "Keep affinity when channel is disabled",
|
||||
"Channel copied successfully": "Channel copied successfully",
|
||||
"Channel created successfully": "Channel created successfully",
|
||||
"Channel deleted successfully": "Channel deleted successfully",
|
||||
@@ -1190,7 +1193,6 @@
|
||||
"Disable selected channels": "Disable selected channels",
|
||||
"Disable selected models": "Disable selected models",
|
||||
"Disable store passthrough": "Disable store passthrough",
|
||||
"Disable thinking processing models": "Disable thinking processing models",
|
||||
"Disable this key?": "Disable this key?",
|
||||
"Disable threshold (seconds)": "Disable threshold (seconds)",
|
||||
"Disable Two-Factor Authentication": "Disable Two-Factor Authentication",
|
||||
@@ -1993,6 +1995,7 @@
|
||||
"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 default auto group is enabled, newly created tokens start with auto instead of an empty group.": "If default auto group is enabled, newly created tokens start with auto instead of an empty group.",
|
||||
"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.",
|
||||
"When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.": "When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.",
|
||||
"If this keeps happening, please report it on GitHub Issues.": "If this keeps happening, please report it on GitHub Issues.",
|
||||
"If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.": "If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.",
|
||||
"Ignored upstream models": "Ignored upstream models",
|
||||
@@ -2388,6 +2391,7 @@
|
||||
"Models losing the most positions": "Models losing the most positions",
|
||||
"Models not in list, may fail to invoke": "Models not in list, may fail to invoke",
|
||||
"Models that are being used but not configured in the system": "Models that are being used but not configured in the system",
|
||||
"Models that skip thinking suffix processing": "Models that skip thinking suffix processing",
|
||||
"Models updated successfully": "Models updated successfully",
|
||||
"Modify existing subscription plan configuration": "Modify existing subscription plan configuration",
|
||||
"Module availability": "Module availability",
|
||||
@@ -2853,8 +2857,8 @@
|
||||
"Path Regex (one per line)": "Path Regex (one per line)",
|
||||
"Path:": "Path:",
|
||||
"Pay": "Pay",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Pay-as-you-go with real-time usage monitoring",
|
||||
"Pay with Balance": "Pay with Balance",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Pay-as-you-go with real-time usage monitoring",
|
||||
"Payment": "Payment",
|
||||
"Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.": "Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.",
|
||||
"Payment Channel": "Payment Channel",
|
||||
@@ -3767,10 +3771,10 @@
|
||||
"Subscription First": "Subscription First",
|
||||
"Subscription Management": "Subscription Management",
|
||||
"Subscription Only": "Subscription Only",
|
||||
"Subscription purchased successfully": "Subscription purchased successfully",
|
||||
"Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.": "Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.",
|
||||
"Subscription Plans": "Subscription Plans",
|
||||
"Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).": "Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).",
|
||||
"Subscription purchased successfully": "Subscription purchased successfully",
|
||||
"Subtract": "Subtract",
|
||||
"Success": "Success",
|
||||
"Success rate": "Success rate",
|
||||
@@ -3925,7 +3929,7 @@
|
||||
"There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?": "There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?",
|
||||
"These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.": "These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.",
|
||||
"These toggles affect whether certain request fields are passed through to the upstream provider.": "These toggles affect whether certain request fields are passed through to the upstream provider.",
|
||||
"Thinking Adapter": "Thinking Adapter",
|
||||
"Thinking Suffix Adapter": "Thinking Suffix Adapter",
|
||||
"Thinking to Content": "Thinking to Content",
|
||||
"Third-party account bindings (read-only, managed by user in profile settings)": "Third-party account bindings (read-only, managed by user in profile settings)",
|
||||
"Third-party Payment Config": "Third-party Payment Config",
|
||||
@@ -3951,6 +3955,7 @@
|
||||
"This model is not available in any group, or no group pricing information is configured.": "This model is not available in any group, or no group pricing information is configured.",
|
||||
"This month": "This month",
|
||||
"This page has not been created yet.": "This page has not been created yet.",
|
||||
"This plan does not allow balance redemption": "This plan does not allow balance redemption",
|
||||
"This project must be used in compliance with the": "This project must be used in compliance with the",
|
||||
"This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.": "This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.",
|
||||
"This site currently has {{count}} models enabled": "This site currently has {{count}} models enabled",
|
||||
@@ -4103,7 +4108,6 @@
|
||||
"Transfer Rewards": "Transfer Rewards",
|
||||
"Transfer successful": "Transfer successful",
|
||||
"Transfer to Balance": "Transfer to Balance",
|
||||
"Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.": "Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.",
|
||||
"Translation": "Translation",
|
||||
"Transparent Billing": "Transparent Billing",
|
||||
"Trend": "Trend",
|
||||
|
||||
Vendored
+9
-5
@@ -134,6 +134,7 @@
|
||||
"Actual Amount": "Montant réel",
|
||||
"Actual Model": "Modèle réel",
|
||||
"Actual Model:": "Modèle réel :",
|
||||
"Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.": "Adapter les requêtes avec le suffixe `-thinking` au comportement de pensée natif d’Anthropic tout en gardant une facturation prévisible.",
|
||||
"Add": "Ajouter",
|
||||
"Add \"{{value}}\"": "Ajouter \"{{value}}\"",
|
||||
"Add {{title}}": "Ajouter {{title}}",
|
||||
@@ -268,6 +269,7 @@
|
||||
"All-time": "Tous temps",
|
||||
"Allocated Memory": "Mémoire allouée",
|
||||
"Allow accountFilter parameter": "Autoriser le paramètre accountFilter",
|
||||
"Allow balance redemption": "Autoriser le paiement avec le solde",
|
||||
"Allow Claude beta query passthrough": "Autoriser le passage des requêtes bêta Claude",
|
||||
"Allow clients to query configured ratios via `/api/ratio`.": "Autoriser les clients à interroger les ratios configurés via `/api/ratio`.",
|
||||
"Allow HTTP image requests": "Autoriser les requêtes d'images HTTP",
|
||||
@@ -643,6 +645,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",
|
||||
"Keep affinity when channel is disabled": "Conserver l'affinité lorsque le canal est désactivé",
|
||||
"Channel copied successfully": "Canal copié avec succès",
|
||||
"Channel created successfully": "Canal créé avec succès",
|
||||
"Channel deleted successfully": "Canal supprimé avec succès",
|
||||
@@ -1190,7 +1193,6 @@
|
||||
"Disable selected channels": "Désactiver les canaux sélectionnés",
|
||||
"Disable selected models": "Désactiver les modèles sélectionnés",
|
||||
"Disable store passthrough": "Désactiver la transmission du champ store",
|
||||
"Disable thinking processing models": "Désactiver les modèles de traitement de la pensée",
|
||||
"Disable this key?": "Désactiver cette clé ?",
|
||||
"Disable threshold (seconds)": "Seuil de désactivation (secondes)",
|
||||
"Disable Two-Factor Authentication": "Désactiver l'authentification à deux facteurs",
|
||||
@@ -1993,6 +1995,7 @@
|
||||
"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 default auto group is enabled, newly created tokens start with auto instead of an empty group.": "Si le groupe auto par défaut est activé, les nouveaux jetons commencent avec auto au lieu d’un groupe vide.",
|
||||
"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.",
|
||||
"When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.": "Lorsque cette option est activée, conserver l'entrée d'affinité même si le canal affinitaire est désactivé ou n'est plus utilisable pour le groupe/modèle actuel. Laissez-la désactivée pour supprimer l'entrée et sélectionner un autre canal.",
|
||||
"If this keeps happening, please report it on GitHub Issues.": "Si cela continue, veuillez le signaler sur GitHub Issues.",
|
||||
"If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.": "Si vous fournissez des services d’IA générative au public en Chine continentale, vous remplirez les obligations légales applicables, notamment le dépôt, l’évaluation de sécurité, la sécurité du contenu, le traitement des plaintes, l’étiquetage du contenu généré, la conservation des journaux et la protection des informations personnelles.",
|
||||
"Ignored upstream models": "Modèles amont ignorés",
|
||||
@@ -2388,6 +2391,7 @@
|
||||
"Models losing the most positions": "Modèles qui perdent le plus de places",
|
||||
"Models not in list, may fail to invoke": "Modèles non listés, peut échouer lors de l'invocation",
|
||||
"Models that are being used but not configured in the system": "Modèles utilisés mais non configurés dans le système",
|
||||
"Models that skip thinking suffix processing": "Modèles qui ignorent le traitement des suffixes thinking",
|
||||
"Models updated successfully": "Modèles mis à jour avec succès",
|
||||
"Modify existing subscription plan configuration": "Modifier la configuration du plan d'abonnement existant",
|
||||
"Module availability": "Disponibilité du module",
|
||||
@@ -2853,8 +2857,8 @@
|
||||
"Path Regex (one per line)": "Regex du chemin (un par ligne)",
|
||||
"Path:": "Chemin :",
|
||||
"Pay": "Pay",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Paiement à l'usage avec suivi de la consommation en temps réel",
|
||||
"Pay with Balance": "Payer avec le solde",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Paiement à l'usage avec suivi de la consommation en temps réel",
|
||||
"Payment": "Paiement",
|
||||
"Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.": "Mode agrégateur de paiement — embarquez avec votre propre société enregistrée (entité offshore). Conçu pour les entreprises.",
|
||||
"Payment Channel": "Canal de paiement",
|
||||
@@ -3767,10 +3771,10 @@
|
||||
"Subscription First": "Abonnement en priorité",
|
||||
"Subscription Management": "Gestion des abonnements",
|
||||
"Subscription Only": "Abonnement uniquement",
|
||||
"Subscription purchased successfully": "Abonnement acheté avec succès",
|
||||
"Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.": "La création et la modification des forfaits d’abonnement sont verrouillées jusqu’à ce que l’administrateur confirme les conditions de conformité dans les paramètres de la passerelle de paiement.",
|
||||
"Subscription Plans": "Plans d'abonnement",
|
||||
"Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).": "Les forfaits d’abonnement n’utilisent PAS le produit associé : chaque forfait dispose de son propre produit Pancake dédié, défini dans l’administration des abonnements (ou créé automatiquement via le bouton « + Créer »).",
|
||||
"Subscription purchased successfully": "Abonnement acheté avec succès",
|
||||
"Subtract": "Soustraire",
|
||||
"Success": "Succès",
|
||||
"Success rate": "Taux de réussite",
|
||||
@@ -3925,7 +3929,7 @@
|
||||
"There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?": "Il y a à la fois des modèles à ajouter et à supprimer, mais vous n'avez sélectionné qu'un seul type. Confirmer l'envoi uniquement des éléments sélectionnés ?",
|
||||
"These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.": "Ces modèles restent encore sélectionnés mais ne figurent pas dans la liste renvoyée par l'amont ; les noms qui sont uniquement des clés sources de model_mapping sont exclus. Modifiez la sélection avant d'enregistrer.",
|
||||
"These toggles affect whether certain request fields are passed through to the upstream provider.": "Ces bascules déterminent si certains champs de demande sont transmis au fournisseur en amont.",
|
||||
"Thinking Adapter": "Adaptateur de réflexion",
|
||||
"Thinking Suffix Adapter": "Adaptateur de suffixe thinking",
|
||||
"Thinking to Content": "Réflexion vers Contenu",
|
||||
"Third-party account bindings (read-only, managed by user in profile settings)": "Liaisons de comptes tiers (lecture seule, gérées par l'utilisateur dans les paramètres de profil)",
|
||||
"Third-party Payment Config": "Configuration de paiement tiers",
|
||||
@@ -3951,6 +3955,7 @@
|
||||
"This model is not available in any group, or no group pricing information is configured.": "Ce modèle n'est disponible dans aucun groupe, ou aucune information de tarification de groupe n'est configurée.",
|
||||
"This month": "Ce mois-ci",
|
||||
"This page has not been created yet.": "Cette page n'a pas encore été créée.",
|
||||
"This plan does not allow balance redemption": "Ce forfait ne permet pas le paiement avec le solde",
|
||||
"This project must be used in compliance with the": "Ce projet doit être utilisé conformément aux",
|
||||
"This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.": "Cet enregistrement provient d’une instance avant la mise à niveau et n’inclut pas d’audits. Mettez à jour l’instance pour enregistrer l’IP du serveur, l’IP de callback, le moyen de paiement et la version du système.",
|
||||
"This site currently has {{count}} models enabled": "Ce site compte actuellement {{count}} modèles activés",
|
||||
@@ -4103,7 +4108,6 @@
|
||||
"Transfer Rewards": "Transférer les récompenses",
|
||||
"Transfer successful": "Transfert réussi",
|
||||
"Transfer to Balance": "Transférer vers le solde",
|
||||
"Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.": "Traduire les suffixes `-thinking` en modèles de réflexion natifs Anthropic tout en gardant une tarification prévisible.",
|
||||
"Translation": "Traduction",
|
||||
"Transparent Billing": "Facturation transparente",
|
||||
"Trend": "Tendance",
|
||||
|
||||
Vendored
+9
-5
@@ -134,6 +134,7 @@
|
||||
"Actual Amount": "実際の金額",
|
||||
"Actual Model": "実際のモデル",
|
||||
"Actual Model:": "実際のモデル:",
|
||||
"Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.": "`-thinking` サフィックス付きリクエストを Anthropic ネイティブの思考動作に適配し、課金を予測可能に保ちます。",
|
||||
"Add": "追加",
|
||||
"Add \"{{value}}\"": "\"{{value}}\" を追加",
|
||||
"Add {{title}}": "{{title}}を追加",
|
||||
@@ -268,6 +269,7 @@
|
||||
"All-time": "全期間",
|
||||
"Allocated Memory": "割り当て済みメモリ",
|
||||
"Allow accountFilter parameter": "accountFilter パラメータを許可",
|
||||
"Allow balance redemption": "残高での交換を許可",
|
||||
"Allow Claude beta query passthrough": "Claude ベータクエリのパススルーを許可",
|
||||
"Allow clients to query configured ratios via `/api/ratio`.": "クライアントが `/api/ratio` 経由で設定された比率を照会できるようにします。",
|
||||
"Allow HTTP image requests": "HTTP画像リクエストを許可",
|
||||
@@ -643,6 +645,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": "チャネルアフィニティ:上流キャッシュヒット",
|
||||
"Keep affinity when channel is disabled": "チャネル無効時にアフィニティを保持",
|
||||
"Channel copied successfully": "チャンネルが正常にコピーされました",
|
||||
"Channel created successfully": "チャンネルが正常に作成されました",
|
||||
"Channel deleted successfully": "チャンネルが正常に削除されました",
|
||||
@@ -1190,7 +1193,6 @@
|
||||
"Disable selected channels": "選択したチャネルを無効にする",
|
||||
"Disable selected models": "選択したモデルを無効にする",
|
||||
"Disable store passthrough": "ストアパススルーを無効にする",
|
||||
"Disable thinking processing models": "思考処理モデルを無効にする",
|
||||
"Disable this key?": "このキーを無効にしますか?",
|
||||
"Disable threshold (seconds)": "無効化しきい値(秒)",
|
||||
"Disable Two-Factor Authentication": "二要素認証を無効にする",
|
||||
@@ -1993,6 +1995,7 @@
|
||||
"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 default auto group is enabled, newly created tokens start with auto instead of an empty group.": "デフォルト auto グループを有効にすると、新規トークンは空グループではなく auto で開始します。",
|
||||
"If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "アフィニティチャネルが失敗し、別のチャネルでリトライが成功した場合、アフィニティを成功したチャネルに更新します。",
|
||||
"When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.": "有効にすると、アフィニティチャネルが無効化された、または現在のグループ/モデルで利用できなくなった場合でも、そのアフィニティエントリを保持します。無効のままにすると、エントリを削除して別のチャネルを選択します。",
|
||||
"If this keeps happening, please report it on GitHub Issues.": "この問題が続く場合は、GitHub Issues で報告してください。",
|
||||
"If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.": "中国本土で一般向けに生成 AI サービスを提供する場合、届出、セキュリティ評価、コンテンツ安全、苦情対応、生成コンテンツのラベル表示、ログ保存、個人情報保護などの法的義務を履行します。",
|
||||
"Ignored upstream models": "無視する上流モデル",
|
||||
@@ -2388,6 +2391,7 @@
|
||||
"Models losing the most positions": "順位を最も落としているモデル",
|
||||
"Models not in list, may fail to invoke": "リストにないモデル、呼び出しに失敗する可能性があります",
|
||||
"Models that are being used but not configured in the system": "使用されているがシステムに設定されていないモデル",
|
||||
"Models that skip thinking suffix processing": "thinking サフィックス処理をスキップするモデル",
|
||||
"Models updated successfully": "モデルが正常に更新されました",
|
||||
"Modify existing subscription plan configuration": "既存のサブスクリプションプラン設定を変更",
|
||||
"Module availability": "モジュールの可用性",
|
||||
@@ -2853,8 +2857,8 @@
|
||||
"Path Regex (one per line)": "パス正規表現(1行に1つ)",
|
||||
"Path:": "パス:",
|
||||
"Pay": "Pay",
|
||||
"Pay-as-you-go with real-time usage monitoring": "リアルタイム使用量監視付き従量課金制",
|
||||
"Pay with Balance": "残高で支払う",
|
||||
"Pay-as-you-go with real-time usage monitoring": "リアルタイム使用量監視付き従量課金制",
|
||||
"Payment": "支払い",
|
||||
"Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.": "決済アグリゲーターモード — 自社の登録済み法人(オフショア法人)でオンボーディングします。エンタープライズ向けです。",
|
||||
"Payment Channel": "決済チャネル",
|
||||
@@ -3767,10 +3771,10 @@
|
||||
"Subscription First": "サブスクリプション優先",
|
||||
"Subscription Management": "サブスクリプション管理",
|
||||
"Subscription Only": "サブスクリプションのみ",
|
||||
"Subscription purchased successfully": "サブスクリプションを購入しました",
|
||||
"Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.": "管理者が支払いゲートウェイ設定でコンプライアンス条件を確認するまで、サブスクリプションプランの作成と変更はロックされます。",
|
||||
"Subscription Plans": "サブスクリプションプラン",
|
||||
"Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).": "サブスクリプションプランは紐付け済み商品を使用しません。各プランには専用の Pancake 商品があり、サブスクリプション管理画面で設定します(または「+ 作成」ボタンで自動作成します)。",
|
||||
"Subscription purchased successfully": "サブスクリプションを購入しました",
|
||||
"Subtract": "減算",
|
||||
"Success": "成功",
|
||||
"Success rate": "成功率",
|
||||
@@ -3925,7 +3929,7 @@
|
||||
"There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?": "追加と削除の両方のモデルが保留中ですが、一方のタイプのみ選択されています。選択した項目のみ送信してよろしいですか?",
|
||||
"These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.": "これらはまだ選択中ですが上流のリストにありません。model_mapping にのみソース別名として載る名前は除外されています。保存前に選択を調整してください。",
|
||||
"These toggles affect whether certain request fields are passed through to the upstream provider.": "これらの切り替えは、特定の要求フィールドがアップストリームプロバイダーに渡されるかどうかに影響します。",
|
||||
"Thinking Adapter": "思考アダプター",
|
||||
"Thinking Suffix Adapter": "思考サフィックスアダプター",
|
||||
"Thinking to Content": "思考からコンテンツへ",
|
||||
"Third-party account bindings (read-only, managed by user in profile settings)": "サードパーティアカウントのバインディング(読み取り専用、プロファイル設定でユーザーが管理)",
|
||||
"Third-party Payment Config": "サードパーティ決済設定",
|
||||
@@ -3951,6 +3955,7 @@
|
||||
"This model is not available in any group, or no group pricing information is configured.": "このモデルはどのグループでも利用できないか、グループの料金情報が設定されていません。",
|
||||
"This month": "今月",
|
||||
"This page has not been created yet.": "このページはまだ作成されていません。",
|
||||
"This plan does not allow balance redemption": "このプランでは残高での交換は許可されていません",
|
||||
"This project must be used in compliance with the": "このプロジェクトは、以下を遵守して使用する必要があります",
|
||||
"This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.": "古いバージョンのインスタンスがこの記録を書き込み、監査情報がありません。最新に更新し、サーバーIP・コールバックIP・支払方法・OSバージョンの記録を有効にしてください。",
|
||||
"This site currently has {{count}} models enabled": "このサイトでは現在 {{count}} 個のモデルが有効です",
|
||||
@@ -4103,7 +4108,6 @@
|
||||
"Transfer Rewards": "報酬の振替",
|
||||
"Transfer successful": "転送が成功しました",
|
||||
"Transfer to Balance": "残高への振替",
|
||||
"Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.": "`-thinking` サフィックスをAnthropicネイティブの思考モデルに変換し、価格設定を予測可能に保ちます。",
|
||||
"Translation": "翻訳",
|
||||
"Transparent Billing": "透明性のある請求",
|
||||
"Trend": "トレンド",
|
||||
|
||||
Vendored
+9
-5
@@ -134,6 +134,7 @@
|
||||
"Actual Amount": "Фактическая сумма",
|
||||
"Actual Model": "Фактическая модель",
|
||||
"Actual Model:": "Фактическая модель:",
|
||||
"Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.": "Адаптировать запросы с суффиксом `-thinking` к собственному режиму размышления Anthropic, сохраняя предсказуемость биллинга.",
|
||||
"Add": "Добавить",
|
||||
"Add \"{{value}}\"": "Добавить \"{{value}}\"",
|
||||
"Add {{title}}": "Добавить {{title}}",
|
||||
@@ -268,6 +269,7 @@
|
||||
"All-time": "За всё время",
|
||||
"Allocated Memory": "Выделенная память",
|
||||
"Allow accountFilter parameter": "Разрешить параметр accountFilter",
|
||||
"Allow balance redemption": "Разрешить оплату балансом",
|
||||
"Allow Claude beta query passthrough": "Разрешить проброс бета-запросов Claude",
|
||||
"Allow clients to query configured ratios via `/api/ratio`.": "Разрешить клиентам запрашивать настроенные соотношения через `/api/ratio`.",
|
||||
"Allow HTTP image requests": "Разрешить HTTP-запросы изображений",
|
||||
@@ -643,6 +645,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",
|
||||
"Keep affinity when channel is disabled": "Сохранять привязку при отключении канала",
|
||||
"Channel copied successfully": "Канал успешно скопирован",
|
||||
"Channel created successfully": "Канал успешно создан",
|
||||
"Channel deleted successfully": "Канал успешно удалён",
|
||||
@@ -1190,7 +1193,6 @@
|
||||
"Disable selected channels": "Отключить выбранные каналы",
|
||||
"Disable selected models": "Отключить выбранные модели",
|
||||
"Disable store passthrough": "Отключить сквозной переход магазина",
|
||||
"Disable thinking processing models": "Отключить модели с обработкой размышлений",
|
||||
"Disable this key?": "Отключить этот ключ?",
|
||||
"Disable threshold (seconds)": "Порог отключения (секунды)",
|
||||
"Disable Two-Factor Authentication": "Отключить двухфакторную аутентификацию",
|
||||
@@ -1993,6 +1995,7 @@
|
||||
"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 default auto group is enabled, newly created tokens start with auto instead of an empty group.": "Если группа auto включена по умолчанию, новые токены создаются с auto вместо пустой группы.",
|
||||
"If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "Если привязанный канал не работает и повторная попытка удалась через другой канал, привязка обновляется на успешный канал.",
|
||||
"When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.": "Если включено, запись привязки сохраняется, даже когда привязанный канал отключён или больше не подходит для текущей группы/модели. Оставьте выключенным, чтобы удалять запись и выбирать другой канал.",
|
||||
"If this keeps happening, please report it on GitHub Issues.": "Если проблема повторяется, сообщите о ней в GitHub Issues.",
|
||||
"If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.": "Если вы предоставляете услуги генеративного ИИ населению материкового Китая, вы будете выполнять юридические обязанности, включая регистрацию, оценку безопасности, безопасность контента, обработку жалоб, маркировку сгенерированного контента, хранение журналов и защиту персональных данных.",
|
||||
"Ignored upstream models": "Игнорируемые upstream-модели",
|
||||
@@ -2388,6 +2391,7 @@
|
||||
"Models losing the most positions": "Модели, потерявшие больше всего позиций",
|
||||
"Models not in list, may fail to invoke": "Модели не в списке, вызов может не сработать",
|
||||
"Models that are being used but not configured in the system": "Модели, которые используются, но не настроены в системе",
|
||||
"Models that skip thinking suffix processing": "Модели, пропускающие обработку суффиксов thinking",
|
||||
"Models updated successfully": "Модели успешно обновлены",
|
||||
"Modify existing subscription plan configuration": "Изменить конфигурацию существующего плана",
|
||||
"Module availability": "Доступность модуля",
|
||||
@@ -2853,8 +2857,8 @@
|
||||
"Path Regex (one per line)": "Регулярное выражение пути (по одному на строку)",
|
||||
"Path:": "Путь:",
|
||||
"Pay": "Pay",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Оплата по мере использования с мониторингом в реальном времени",
|
||||
"Pay with Balance": "Оплатить балансом",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Оплата по мере использования с мониторингом в реальном времени",
|
||||
"Payment": "Платеж",
|
||||
"Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.": "Режим платежного агрегатора — подключение через вашу зарегистрированную компанию (офшорное юрлицо). Создано для Enterprise.",
|
||||
"Payment Channel": "Платёжный канал",
|
||||
@@ -3767,10 +3771,10 @@
|
||||
"Subscription First": "Подписка в приоритете",
|
||||
"Subscription Management": "Управление подписками",
|
||||
"Subscription Only": "Только подписка",
|
||||
"Subscription purchased successfully": "Подписка успешно приобретена",
|
||||
"Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.": "Создание и изменение планов подписки заблокированы, пока администратор не подтвердит условия соответствия в настройках платежного шлюза.",
|
||||
"Subscription Plans": "Планы подписки",
|
||||
"Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).": "Планы подписки НЕ используют привязанный продукт — у каждого плана есть собственный продукт Pancake, задаваемый в администрировании подписок (или автоматически создаваемый кнопкой «+ Создать»).",
|
||||
"Subscription purchased successfully": "Подписка успешно приобретена",
|
||||
"Subtract": "Вычесть",
|
||||
"Success": "Успешно",
|
||||
"Success rate": "Доля успешных запросов",
|
||||
@@ -3925,7 +3929,7 @@
|
||||
"There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?": "Есть модели для добавления и удаления, но вы выбрали только один тип. Подтвердить отправку только выбранных элементов?",
|
||||
"These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.": "Эти имена всё ещё отмечены в выборе, но не возвращены в списке upstream; ключи только как источники model_mapping исключены. Скорректируйте выбор перед сохранением.",
|
||||
"These toggles affect whether certain request fields are passed through to the upstream provider.": "Эти переключатели влияют на то, передаются ли определенные поля запроса вышестоящему поставщику.",
|
||||
"Thinking Adapter": "Адаптер мышления",
|
||||
"Thinking Suffix Adapter": "Адаптер суффикса thinking",
|
||||
"Thinking to Content": "Мышление в контент",
|
||||
"Third-party account bindings (read-only, managed by user in profile settings)": "Привязки сторонних учетных записей (только для чтения, управляется пользователем в настройках профиля)",
|
||||
"Third-party Payment Config": "Настройка стороннего платежа",
|
||||
@@ -3951,6 +3955,7 @@
|
||||
"This model is not available in any group, or no group pricing information is configured.": "Эта модель недоступна ни в одной группе, или информация о ценах для групп не настроена.",
|
||||
"This month": "В этом месяце",
|
||||
"This page has not been created yet.": "Эта страница еще не создана.",
|
||||
"This plan does not allow balance redemption": "Этот план не разрешает оплату балансом",
|
||||
"This project must be used in compliance with the": "Этот проект должен использоваться в соответствии с",
|
||||
"This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.": "Запись создана экземпляром до обновления и не содержит сведений аудита. Обновите экземпляр, чтобы фиксировать IP сервера, IP callback, способ оплаты и версию ОС.",
|
||||
"This site currently has {{count}} models enabled": "На этом сайте сейчас включено моделей: {{count}}",
|
||||
@@ -4103,7 +4108,6 @@
|
||||
"Transfer Rewards": "Перевести награды",
|
||||
"Transfer successful": "Перевод успешен",
|
||||
"Transfer to Balance": "Перевести на баланс",
|
||||
"Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.": "Преобразовывать суффиксы `-thinking` в собственные модели мышления Anthropic, сохраняя при этом предсказуемость ценообразования.",
|
||||
"Translation": "Перевод",
|
||||
"Transparent Billing": "Прозрачная тарификация",
|
||||
"Trend": "Тренд",
|
||||
|
||||
Vendored
+9
-5
@@ -134,6 +134,7 @@
|
||||
"Actual Amount": "Số tiền thực tế",
|
||||
"Actual Model": "Mô hình thực tế",
|
||||
"Actual Model:": "Mô hình thực tế:",
|
||||
"Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.": "Điều chỉnh các yêu cầu có hậu tố `-thinking` sang hành vi suy luận gốc của Anthropic trong khi vẫn giữ tính phí dễ dự đoán.",
|
||||
"Add": "Add",
|
||||
"Add \"{{value}}\"": "Thêm \"{{value}}\"",
|
||||
"Add {{title}}": "Thêm {{title}}",
|
||||
@@ -268,6 +269,7 @@
|
||||
"All-time": "Mọi thời điểm",
|
||||
"Allocated Memory": "Bộ nhớ đã cấp phát",
|
||||
"Allow accountFilter parameter": "Cho phép tham số accountFilter",
|
||||
"Allow balance redemption": "Cho phép thanh toán bằng số dư",
|
||||
"Allow Claude beta query passthrough": "Cho phép chuyển tiếp truy vấn beta Claude",
|
||||
"Allow clients to query configured ratios via `/api/ratio`.": "Cho phép khách hàng truy vấn các tỷ lệ đã cấu hình thông qua `/api/ratio`.",
|
||||
"Allow HTTP image requests": "Cho phép yêu cầu hình ảnh HTTP",
|
||||
@@ -643,6 +645,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",
|
||||
"Keep affinity when channel is disabled": "Giữ ưu tiên khi kênh bị tắt",
|
||||
"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",
|
||||
@@ -1190,7 +1193,6 @@
|
||||
"Disable selected channels": "Vô hiệu hóa các kênh đã chọn",
|
||||
"Disable selected models": "Vô hiệu hóa các mô hình đã chọn",
|
||||
"Disable store passthrough": "Vô hiệu hóa chuyển tiếp store",
|
||||
"Disable thinking processing models": "Tắt mô hình xử lý suy nghĩ",
|
||||
"Disable this key?": "Vô hiệu hóa khóa này?",
|
||||
"Disable threshold (seconds)": "Vô hiệu hóa ngưỡng (giây)",
|
||||
"Disable Two-Factor Authentication": "Vô hiệu hóa Xác thực hai yếu tố",
|
||||
@@ -1993,6 +1995,7 @@
|
||||
"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 default auto group is enabled, newly created tokens start with auto instead of an empty group.": "Nếu bật nhóm auto mặc định, token mới sẽ bắt đầu với auto thay vì nhóm trống.",
|
||||
"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.",
|
||||
"When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.": "Khi bật, giữ mục ưu tiên ngay cả khi kênh ưu tiên bị tắt hoặc không còn dùng được cho nhóm/mô hình hiện tại. Để tắt để xóa mục đó và chọn kênh khác.",
|
||||
"If this keeps happening, please report it on GitHub Issues.": "Nếu sự cố tiếp tục xảy ra, vui lòng báo cáo trên GitHub Issues.",
|
||||
"If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.": "Nếu bạn cung cấp dịch vụ AI tạo sinh cho công chúng tại Trung Quốc đại lục, bạn sẽ thực hiện các nghĩa vụ pháp lý bao gồm đăng ký, đánh giá an toàn, an toàn nội dung, xử lý khiếu nại, gắn nhãn nội dung được tạo, lưu giữ nhật ký và bảo vệ thông tin cá nhân.",
|
||||
"Ignored upstream models": "Mô hình upstream bị bỏ qua",
|
||||
@@ -2388,6 +2391,7 @@
|
||||
"Models losing the most positions": "Mô hình tụt hạng nhiều nhất",
|
||||
"Models not in list, may fail to invoke": "Các mô hình không có trong danh sách, có thể gọi thất bại",
|
||||
"Models that are being used but not configured in the system": "Mô hình đang được sử dụng nhưng chưa được cấu hình trong hệ thống",
|
||||
"Models that skip thinking suffix processing": "Mô hình bỏ qua xử lý hậu tố thinking",
|
||||
"Models updated successfully": "Mô hình đã được cập nhật thành công",
|
||||
"Modify existing subscription plan configuration": "Sửa đổi cấu hình gói đăng ký hiện có",
|
||||
"Module availability": "Khả dụng của mô-đun",
|
||||
@@ -2853,8 +2857,8 @@
|
||||
"Path Regex (one per line)": "Regex đường dẫn (mỗi dòng một mục)",
|
||||
"Path:": "Đường dẫn:",
|
||||
"Pay": "Pay",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Thanh toán theo mức sử dụng với theo dõi mức sử dụng theo thời gian thực",
|
||||
"Pay with Balance": "Thanh toán bằng số dư",
|
||||
"Pay-as-you-go with real-time usage monitoring": "Thanh toán theo mức sử dụng với theo dõi mức sử dụng theo thời gian thực",
|
||||
"Payment": "Thanh toán",
|
||||
"Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.": "Chế độ tổng hợp thanh toán — đăng ký bằng công ty đã đăng ký của bạn (pháp nhân offshore). Dành cho doanh nghiệp.",
|
||||
"Payment Channel": "Kênh thanh toán",
|
||||
@@ -3767,10 +3771,10 @@
|
||||
"Subscription First": "Ưu tiên đăng ký",
|
||||
"Subscription Management": "Quản lý đăng ký",
|
||||
"Subscription Only": "Chỉ đăng ký",
|
||||
"Subscription purchased successfully": "Đã mua gói đăng ký thành công",
|
||||
"Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.": "Việc tạo và thay đổi gói đăng ký bị khóa cho đến khi quản trị viên xác nhận điều khoản tuân thủ trong cài đặt Cổng thanh toán.",
|
||||
"Subscription Plans": "Gói đăng ký",
|
||||
"Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).": "Gói đăng ký KHÔNG dùng Sản phẩm đã liên kết — mỗi gói có một sản phẩm Pancake riêng, được đặt trong quản trị Đăng ký (hoặc tự động tạo bằng nút \"+ Create\" tại đó).",
|
||||
"Subscription purchased successfully": "Đã mua gói đăng ký thành công",
|
||||
"Subtract": "Trừ",
|
||||
"Success": "Thành công",
|
||||
"Success rate": "Tỷ lệ thành công",
|
||||
@@ -3925,7 +3929,7 @@
|
||||
"There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?": "Có cả mô hình cần thêm và xóa đang chờ, nhưng bạn chỉ chọn một loại. Xác nhận chỉ gửi các mục đã chọn?",
|
||||
"These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.": "Các model này vẫn được chọn nhưng không còn xuất hiện trong danh sách upstream; tên chỉ là khóa nguồn trong model_mapping đã được loại. Điều chỉnh trước khi lưu.",
|
||||
"These toggles affect whether certain request fields are passed through to the upstream provider.": "Các chuyển đổi này ảnh hưởng đến việc các trường yêu cầu nhất định có được chuyển đến nhà cung cấp dịch vụ đầu vào hay không.",
|
||||
"Thinking Adapter": "Adapter tư duy",
|
||||
"Thinking Suffix Adapter": "Adapter hậu tố thinking",
|
||||
"Thinking to Content": "Suy nghĩ thành Nội dung",
|
||||
"Third-party account bindings (read-only, managed by user in profile settings)": "Liên kết tài khoản bên thứ ba (chỉ đọc, do người dùng quản lý trong cài đặt hồ sơ)",
|
||||
"Third-party Payment Config": "Cấu hình thanh toán bên thứ ba",
|
||||
@@ -3951,6 +3955,7 @@
|
||||
"This model is not available in any group, or no group pricing information is configured.": "Mô hình này không khả dụng trong bất kỳ nhóm nào, hoặc thông tin giá nhóm chưa được cấu hình.",
|
||||
"This month": "Tháng này",
|
||||
"This page has not been created yet.": "Trang này chưa được tạo.",
|
||||
"This plan does not allow balance redemption": "Gói này không cho phép thanh toán bằng số dư",
|
||||
"This project must be used in compliance with the": "Dự án này phải được sử dụng tuân thủ theo",
|
||||
"This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.": "Bản ghi này do bản cũ tạo và thiếu thông tin audit. Nâng cấp bản cài để lưu IP máy chủ, IP callback, hình thức thanh toán và phiên bản hệ thống.",
|
||||
"This site currently has {{count}} models enabled": "Trang này hiện đã bật {{count}} mô hình",
|
||||
@@ -4103,7 +4108,6 @@
|
||||
"Transfer Rewards": "Chuyển thưởng",
|
||||
"Transfer successful": "Chuyển thành công",
|
||||
"Transfer to Balance": "Chuyển vào số dư",
|
||||
"Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.": "Dịch các hậu tố `-thinking` sang các mô hình tư duy gốc của Anthropic đồng thời giữ giá cả có thể dự đoán được.",
|
||||
"Translation": "Dịch thuật",
|
||||
"Transparent Billing": "Thanh toán minh bạch",
|
||||
"Trend": "Xu hướng",
|
||||
|
||||
Vendored
+9
-5
@@ -134,6 +134,7 @@
|
||||
"Actual Amount": "实付金额",
|
||||
"Actual Model": "实际模型",
|
||||
"Actual Model:": "实际模型:",
|
||||
"Adapt `-thinking` suffix requests to Anthropic native thinking behavior while keeping billing predictable.": "将带 `-thinking` 后缀的请求适配为 Anthropic 原生思考请求,并保持计费可预测。",
|
||||
"Add": "添加",
|
||||
"Add \"{{value}}\"": "添加 \"{{value}}\"",
|
||||
"Add {{title}}": "添加{{title}}",
|
||||
@@ -268,6 +269,7 @@
|
||||
"All-time": "全部时间",
|
||||
"Allocated Memory": "已分配内存",
|
||||
"Allow accountFilter parameter": "允许 accountFilter 参数",
|
||||
"Allow balance redemption": "允许余额兑换",
|
||||
"Allow Claude beta query passthrough": "允许 Claude beta 查询透传",
|
||||
"Allow clients to query configured ratios via `/api/ratio`.": "允许客户端通过 `/api/ratio` 查询配置的比例。",
|
||||
"Allow HTTP image requests": "允许 HTTP 图像请求",
|
||||
@@ -643,6 +645,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": "渠道亲和性:上游缓存命中",
|
||||
"Keep affinity when channel is disabled": "渠道禁用后保留亲和",
|
||||
"Channel copied successfully": "渠道复制成功",
|
||||
"Channel created successfully": "渠道创建成功",
|
||||
"Channel deleted successfully": "渠道删除成功",
|
||||
@@ -1190,7 +1193,6 @@
|
||||
"Disable selected channels": "禁用选定的渠道",
|
||||
"Disable selected models": "禁用选定的模型",
|
||||
"Disable store passthrough": "禁止透传 store",
|
||||
"Disable thinking processing models": "禁用思考处理模型",
|
||||
"Disable this key?": "禁用此密钥?",
|
||||
"Disable threshold (seconds)": "禁用阈值(秒)",
|
||||
"Disable Two-Factor Authentication": "禁用双重身份验证",
|
||||
@@ -1993,6 +1995,7 @@
|
||||
"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 default auto group is enabled, newly created tokens start with auto instead of an empty group.": "如果启用默认 auto 分组,新建令牌会默认使用 auto,而不是空分组。",
|
||||
"If the affinity channel fails and retry succeeds on another channel, update affinity to the successful channel.": "如果亲和到的渠道失败,重试到其他渠道成功后,将亲和更新到成功的渠道。",
|
||||
"When enabled, keep the affinity entry even if the affinity channel is disabled or no longer usable for the current group/model. Leave it off to delete the entry and select another channel.": "开启后,亲和到的渠道被禁用,或不再适用于当前分组/模型时,仍保留这条亲和;关闭时会删除并重新选择渠道。",
|
||||
"If this keeps happening, please report it on GitHub Issues.": "如果问题持续出现,请到 GitHub Issues 反馈。",
|
||||
"If you provide generative AI services to the public in mainland China, you will fulfill legal obligations including filing, security assessment, content safety, complaint handling, generated content labeling, log retention, and personal information protection.": "如果你在中国大陆向公众提供生成式人工智能服务,你将履行备案、安全评估、内容安全、投诉处理、生成内容标识、日志留存和个人信息保护等法律义务。",
|
||||
"Ignored upstream models": "已忽略上游模型",
|
||||
@@ -2388,6 +2391,7 @@
|
||||
"Models losing the most positions": "名次下滑最多的模型",
|
||||
"Models not in list, may fail to invoke": "模型未加入列表,可能无法调用",
|
||||
"Models that are being used but not configured in the system": "正在使用但未在系统中配置的模型",
|
||||
"Models that skip thinking suffix processing": "不自动处理思考后缀的模型",
|
||||
"Models updated successfully": "模型更新成功",
|
||||
"Modify existing subscription plan configuration": "修改现有订阅套餐的配置",
|
||||
"Module availability": "模块可用性",
|
||||
@@ -2853,8 +2857,8 @@
|
||||
"Path Regex (one per line)": "路径正则(每行一个)",
|
||||
"Path:": "路径:",
|
||||
"Pay": "支付",
|
||||
"Pay-as-you-go with real-time usage monitoring": "按量付费,实时监控使用情况",
|
||||
"Pay with Balance": "使用余额支付",
|
||||
"Pay-as-you-go with real-time usage monitoring": "按量付费,实时监控使用情况",
|
||||
"Payment": "支付",
|
||||
"Payment aggregator mode — onboard with your own registered company (offshore entity). Built for Enterprise.": "支付聚合模式:使用你自己的注册公司(离岸实体)入驻。面向企业场景构建。",
|
||||
"Payment Channel": "支付渠道",
|
||||
@@ -3767,10 +3771,10 @@
|
||||
"Subscription First": "优先订阅",
|
||||
"Subscription Management": "订阅管理",
|
||||
"Subscription Only": "仅用订阅",
|
||||
"Subscription purchased successfully": "订阅购买成功",
|
||||
"Subscription plan creation and changes are locked until the administrator confirms compliance terms in Payment Gateway settings.": "管理员在支付网关设置中确认合规条款之前,订阅套餐的创建和修改会被锁定。",
|
||||
"Subscription Plans": "订阅套餐",
|
||||
"Subscription plans do NOT use the bound Product — each plan has its own dedicated Pancake product, set in the Subscriptions admin (or auto-minted via the \"+ Create\" button there).": "订阅套餐不会使用已绑定的产品。每个套餐都有独立的 Pancake 产品,可在订阅管理中设置,或通过其中的“+ 创建”按钮自动生成。",
|
||||
"Subscription purchased successfully": "订阅购买成功",
|
||||
"Subtract": "减少",
|
||||
"Success": "成功",
|
||||
"Success rate": "成功率",
|
||||
@@ -3925,7 +3929,7 @@
|
||||
"There are both add and remove models pending, but you only selected one type. Confirm submitting only the selected items?": "当前有新增和删除两类待处理模型,但您只勾选了其中一类。确认仅提交已勾选的部分吗?",
|
||||
"These models are still in your selection but were not returned by the upstream listing. Entries that are only model_mapping source aliases are omitted. Toggle to adjust before saving.": "这些模型仍然在您的勾选列表中,但上游已不再返回该名称;仅作为 model_mapping 来源键而不会出现在 upstream 列表的别名已从本视图排除,请在保存前调整勾选。",
|
||||
"These toggles affect whether certain request fields are passed through to the upstream provider.": "这些开关控制某些请求字段是否透传到上游服务。",
|
||||
"Thinking Adapter": "思维适配器",
|
||||
"Thinking Suffix Adapter": "思考后缀适配器",
|
||||
"Thinking to Content": "思维到内容",
|
||||
"Third-party account bindings (read-only, managed by user in profile settings)": "第三方账户绑定(只读,由用户在个人资料设置中管理)",
|
||||
"Third-party Payment Config": "第三方支付配置",
|
||||
@@ -3951,6 +3955,7 @@
|
||||
"This model is not available in any group, or no group pricing information is configured.": "此模型在任何分组中均不可用,或未配置分组定价信息。",
|
||||
"This month": "本月获得",
|
||||
"This page has not been created yet.": "此页面尚未创建。",
|
||||
"This plan does not allow balance redemption": "该套餐不允许使用余额兑换",
|
||||
"This project must be used in compliance with the": "此项目的使用必须遵守",
|
||||
"This record was written by a pre-upgrade instance and lacks audit info. Upgrade the instance to record server IP, callback IP, payment method and system version.": "该记录由旧版本实例写入,缺少审计信息,建议将实例升级至最新版本以便记录服务器 IP、回调 IP、支付方式与系统版本等审计字段。",
|
||||
"This site currently has {{count}} models enabled": "本站当前已启用模型,总计 {{count}} 个",
|
||||
@@ -4103,7 +4108,6 @@
|
||||
"Transfer Rewards": "转移奖励",
|
||||
"Transfer successful": "转账成功",
|
||||
"Transfer to Balance": "转移到余额",
|
||||
"Translate `-thinking` suffixes into Anthropic native thinking models while keeping pricing predictable.": "将 `-thinking` 后缀转换为 Anthropic 原生思维模型,同时保持价格可预测性。",
|
||||
"Translation": "翻译",
|
||||
"Transparent Billing": "透明计费",
|
||||
"Trend": "趋势",
|
||||
|
||||
Reference in New Issue
Block a user