Commit 57865fc1 by CaIon

fix: restore default channel connection paste

parent 6ce7305c
...@@ -24,6 +24,7 @@ import { ...@@ -24,6 +24,7 @@ import {
Boxes, Boxes,
CheckCircle2, CheckCircle2,
Circle, Circle,
ClipboardPaste,
HelpCircle, HelpCircle,
KeyRound, KeyRound,
Loader2, Loader2,
...@@ -115,6 +116,10 @@ import { ...@@ -115,6 +116,10 @@ import {
ADMIN_PERMISSION_RESOURCES, ADMIN_PERMISSION_RESOURCES,
hasPermission, hasPermission,
} from '@/lib/admin-permissions' } from '@/lib/admin-permissions'
import {
parseChannelConnectionInfo,
type ChannelConnectionInfo,
} from '@/lib/channel-connection-info'
import { getLobeIcon } from '@/lib/lobe-icon' import { getLobeIcon } from '@/lib/lobe-icon'
import { ROLE } from '@/lib/roles' import { ROLE } from '@/lib/roles'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
...@@ -626,6 +631,8 @@ export function ChannelMutateDrawer({ ...@@ -626,6 +631,8 @@ export function ChannelMutateDrawer({
const [paramOverrideEditorOpen, setParamOverrideEditorOpen] = useState(false) const [paramOverrideEditorOpen, setParamOverrideEditorOpen] = useState(false)
const [advancedCustomEditorOpen, setAdvancedCustomEditorOpen] = const [advancedCustomEditorOpen, setAdvancedCustomEditorOpen] =
useState(false) useState(false)
const [clipboardConnectionInfo, setClipboardConnectionInfo] =
useState<ChannelConnectionInfo | null>(null)
const isEditing = Boolean(currentRow) const isEditing = Boolean(currentRow)
const channelId = currentRow?.id ?? null const channelId = currentRow?.id ?? null
...@@ -757,6 +764,67 @@ export function ChannelMutateDrawer({ ...@@ -757,6 +764,67 @@ export function ChannelMutateDrawer({
} }
}, [open, resetDoubaoApiUnlock]) }, [open, resetDoubaoApiUnlock])
const applyConnectionInfo = useCallback(
(connectionInfo: ChannelConnectionInfo) => {
form.setValue('key', connectionInfo.key, {
shouldDirty: true,
shouldValidate: true,
})
form.setValue('base_url', connectionInfo.url, {
shouldDirty: true,
shouldValidate: true,
})
setClipboardConnectionInfo(null)
toast.success(t('Connection info filled in'))
},
[form, t]
)
const pasteConnectionInfoFromClipboard = useCallback(async () => {
if (typeof navigator === 'undefined' || !navigator.clipboard?.readText) {
toast.error(t('Unable to read clipboard'))
return
}
try {
const text = await navigator.clipboard.readText()
const parsed = parseChannelConnectionInfo(text)
if (parsed) {
applyConnectionInfo(parsed)
return
}
toast.info(t('No connection info found in clipboard'))
} catch {
toast.error(t('Unable to read clipboard'))
}
}, [applyConnectionInfo, t])
useEffect(() => {
if (!open || isEditing) {
setClipboardConnectionInfo(null)
return
}
if (typeof navigator === 'undefined' || !navigator.clipboard?.readText) {
return
}
let cancelled = false
void navigator.clipboard
.readText()
.then((text) => {
if (cancelled) return
setClipboardConnectionInfo(parseChannelConnectionInfo(text))
})
.catch(() => {
/* Clipboard detection is best-effort on drawer open. */
})
return () => {
cancelled = true
}
}, [isEditing, open])
// Helper computed values // Helper computed values
const isBatchMode = const isBatchMode =
multiKeyMode === 'batch' || multiKeyMode === 'multi_to_single' multiKeyMode === 'batch' || multiKeyMode === 'multi_to_single'
...@@ -1741,6 +1809,7 @@ export function ChannelMutateDrawer({ ...@@ -1741,6 +1809,7 @@ export function ChannelMutateDrawer({
setActiveEditorSectionId(CHANNEL_EDITOR_SECTION_IDS.identity) setActiveEditorSectionId(CHANNEL_EDITOR_SECTION_IDS.identity)
setExpandedEditorNavItemId(undefined) setExpandedEditorNavItemId(undefined)
setAdvancedSettingsOpen(false) setAdvancedSettingsOpen(false)
setClipboardConnectionInfo(null)
} }
}, },
[onOpenChange, form] [onOpenChange, form]
...@@ -1751,26 +1820,42 @@ export function ChannelMutateDrawer({ ...@@ -1751,26 +1820,42 @@ export function ChannelMutateDrawer({
<Sheet open={open} onOpenChange={handleOpenChange}> <Sheet open={open} onOpenChange={handleOpenChange}>
<SheetContent className={sideDrawerContentClassName('sm:max-w-5xl')}> <SheetContent className={sideDrawerContentClassName('sm:max-w-5xl')}>
<SheetHeader className={sideDrawerHeaderClassName()}> <SheetHeader className={sideDrawerHeaderClassName()}>
<SheetTitle className='flex items-center gap-3'> <div className='flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between'>
<span className='bg-muted flex size-9 shrink-0 items-center justify-center rounded-md'> <div className='min-w-0'>
<ChannelTypeLogo type={currentType} size={22} /> <SheetTitle className='flex items-center gap-3'>
</span> <span className='bg-muted flex size-9 shrink-0 items-center justify-center rounded-md'>
<span> <ChannelTypeLogo type={currentType} size={22} />
{isEditing ? t('Edit Channel') : t('Create Channel')} </span>
<span className='text-muted-foreground ml-2 text-sm font-normal'> <span>
{t(currentTypeLabel)} {isEditing ? t('Edit Channel') : t('Create Channel')}
</span> <span className='text-muted-foreground ml-2 text-sm font-normal'>
</span> {t(currentTypeLabel)}
</SheetTitle> </span>
<SheetDescription> </span>
{isEditing </SheetTitle>
? t( <SheetDescription className='mt-1'>
"Update channel configuration and click save when you're done." {isEditing
) ? t(
: t( "Update channel configuration and click save when you're done."
'Add a new channel by providing the necessary information.' )
)} : t(
</SheetDescription> 'Add a new channel by providing the necessary information.'
)}
</SheetDescription>
</div>
{!isEditing && (
<Button
type='button'
variant='outline'
size='sm'
className='shrink-0'
onClick={pasteConnectionInfoFromClipboard}
>
<ClipboardPaste className='size-4' />
<span>{t('Paste Connection Info')}</span>
</Button>
)}
</div>
</SheetHeader> </SheetHeader>
{sensitiveLocked && ( {sensitiveLocked && (
...@@ -1786,6 +1871,31 @@ export function ChannelMutateDrawer({ ...@@ -1786,6 +1871,31 @@ export function ChannelMutateDrawer({
</Alert> </Alert>
)} )}
{!isEditing && clipboardConnectionInfo && (
<Alert>
<AlertDescription className='flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between'>
<span>{t('Connection info detected in clipboard')}</span>
<span className='flex shrink-0 gap-2'>
<Button
type='button'
size='sm'
onClick={() => applyConnectionInfo(clipboardConnectionInfo)}
>
{t('Fill in')}
</Button>
<Button
type='button'
variant='ghost'
size='sm'
onClick={() => setClipboardConnectionInfo(null)}
>
{t('Ignore')}
</Button>
</span>
</AlertDescription>
</Alert>
)}
<Form {...form}> <Form {...form}>
<form <form
id='channel-form' id='channel-form'
......
...@@ -50,6 +50,7 @@ import { ...@@ -50,6 +50,7 @@ import {
import { useChatPresets } from '@/features/chat/hooks/use-chat-presets' import { useChatPresets } from '@/features/chat/hooks/use-chat-presets'
import { resolveChatUrl, type ChatPreset } from '@/features/chat/lib/chat-links' import { resolveChatUrl, type ChatPreset } from '@/features/chat/lib/chat-links'
import { sendToFluent } from '@/features/chat/lib/send-to-fluent' import { sendToFluent } from '@/features/chat/lib/send-to-fluent'
import { encodeChannelConnectionInfo } from '@/lib/channel-connection-info'
import { copyToClipboard } from '@/lib/copy-to-clipboard' import { copyToClipboard } from '@/lib/copy-to-clipboard'
import { updateApiKeyStatus } from '../api' import { updateApiKeyStatus } from '../api'
...@@ -70,14 +71,6 @@ function getServerAddress(): string { ...@@ -70,14 +71,6 @@ function getServerAddress(): string {
return window.location.origin return window.location.origin
} }
function encodeConnectionString(key: string, url: string): string {
return JSON.stringify({
_type: 'newapi_channel_conn',
key,
url,
})
}
type DataTableRowActionsProps<TData> = { type DataTableRowActionsProps<TData> = {
row: Row<TData> row: Row<TData>
} }
...@@ -262,7 +255,10 @@ export function DataTableRowActions<TData>({ ...@@ -262,7 +255,10 @@ export function DataTableRowActions<TData>({
onClick={async () => { onClick={async () => {
const realKey = getCachedRealKey() const realKey = getCachedRealKey()
if (!realKey) return if (!realKey) return
const connStr = encodeConnectionString(realKey, getServerAddress()) const connStr = encodeChannelConnectionInfo(
realKey,
getServerAddress()
)
const ok = await copyToClipboard(connStr) const ok = await copyToClipboard(connStr)
if (ok) toast.success(t('Copied')) if (ok) toast.success(t('Copied'))
}} }}
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "Connection closed", "Connection closed": "Connection closed",
"Connection error": "Connection error", "Connection error": "Connection error",
"Connection failed": "Connection failed", "Connection failed": "Connection failed",
"Connection info detected in clipboard": "Connection info detected in clipboard",
"Connection info filled in": "Connection info filled in",
"Connection successful": "Connection successful", "Connection successful": "Connection successful",
"Console": "Console", "Console": "Console",
"Console area": "Console area", "Console area": "Console area",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "Fill Codex CLI / Claude CLI Templates", "Fill Codex CLI / Claude CLI Templates": "Fill Codex CLI / Claude CLI Templates",
"Fill example (all channels)": "Fill example (all channels)", "Fill example (all channels)": "Fill example (all channels)",
"Fill example (specific channels)": "Fill example (specific channels)", "Fill example (specific channels)": "Fill example (specific channels)",
"Fill in": "Fill in",
"Fill in both Merchant ID and API Private Key before creating.": "Fill in both Merchant ID and API Private Key before creating.", "Fill in both Merchant ID and API Private Key before creating.": "Fill in both Merchant ID and API Private Key before creating.",
"Fill in the credentials above to begin.": "Fill in the credentials above to begin.", "Fill in the credentials above to begin.": "Fill in the credentials above to begin.",
"Fill in the following info to create a new subscription plan": "Fill in the following info to create a new subscription plan", "Fill in the following info to create a new subscription plan": "Fill in the following info to create a new subscription plan",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.", "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.",
"If this keeps happening, please report it on GitHub Issues.": "If this keeps happening, please report it on GitHub Issues.", "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.", "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.",
"Ignore": "Ignore",
"Ignored upstream models": "Ignored upstream models", "Ignored upstream models": "Ignored upstream models",
"Image": "Image", "Image": "Image",
"Image Generation": "Image Generation", "Image Generation": "Image Generation",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "No chat presets match your search", "No chat presets match your search": "No chat presets match your search",
"No conflict entries available.": "No conflict entries available.", "No conflict entries available.": "No conflict entries available.",
"No conflicts match your search.": "No conflicts match your search.", "No conflicts match your search.": "No conflicts match your search.",
"No connection info found in clipboard": "No connection info found in clipboard",
"No console output": "No console output", "No console output": "No console output",
"No containers": "No containers", "No containers": "No containers",
"No content to copy": "No content to copy", "No content to copy": "No content to copy",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "Password reset: {{password}}", "Password reset: {{password}}": "Password reset: {{password}}",
"Passwords do not match": "Passwords do not match", "Passwords do not match": "Passwords do not match",
"Passwords don't match.": "Passwords don't match.", "Passwords don't match.": "Passwords don't match.",
"Paste Connection Info": "Paste Connection Info",
"Path": "Path", "Path": "Path",
"Path not set": "Path not set", "Path not set": "Path not set",
"Path Regex (one per line)": "Path Regex (one per line)", "Path Regex (one per line)": "Path Regex (one per line)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "Unable to open chat", "Unable to open chat": "Unable to open chat",
"Unable to parse structured pricing": "Unable to parse structured pricing", "Unable to parse structured pricing": "Unable to parse structured pricing",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "Unable to prepare chat link. Please ensure you have an enabled API key.", "Unable to prepare chat link. Please ensure you have an enabled API key.": "Unable to prepare chat link. Please ensure you have an enabled API key.",
"Unable to read clipboard": "Unable to read clipboard",
"Unauthorized": "Unauthorized", "Unauthorized": "Unauthorized",
"Unauthorized Access": "Unauthorized Access", "Unauthorized Access": "Unauthorized Access",
"Unbind": "Unbind", "Unbind": "Unbind",
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "Connexion fermée", "Connection closed": "Connexion fermée",
"Connection error": "Erreur de connexion", "Connection error": "Erreur de connexion",
"Connection failed": "Connexion échouée", "Connection failed": "Connexion échouée",
"Connection info detected in clipboard": "Infos de connexion détectées dans le presse-papiers",
"Connection info filled in": "Infos de connexion remplies",
"Connection successful": "Connexion réussie", "Connection successful": "Connexion réussie",
"Console": "Console", "Console": "Console",
"Console area": "Zone de console", "Console area": "Zone de console",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "Remplir les modèles Codex CLI / Claude CLI", "Fill Codex CLI / Claude CLI Templates": "Remplir les modèles Codex CLI / Claude CLI",
"Fill example (all channels)": "Remplir l'exemple (tous les canaux)", "Fill example (all channels)": "Remplir l'exemple (tous les canaux)",
"Fill example (specific channels)": "Remplir l'exemple (canaux spécifiques)", "Fill example (specific channels)": "Remplir l'exemple (canaux spécifiques)",
"Fill in": "Remplir",
"Fill in both Merchant ID and API Private Key before creating.": "Renseignez l’ID marchand et la clé privée API avant de créer.", "Fill in both Merchant ID and API Private Key before creating.": "Renseignez l’ID marchand et la clé privée API avant de créer.",
"Fill in the credentials above to begin.": "Renseignez les identifiants ci-dessus pour commencer.", "Fill in the credentials above to begin.": "Renseignez les identifiants ci-dessus pour commencer.",
"Fill in the following info to create a new subscription plan": "Remplissez les informations suivantes pour créer un nouveau plan d'abonnement", "Fill in the following info to create a new subscription plan": "Remplissez les informations suivantes pour créer un nouveau plan d'abonnement",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.", "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.",
"If this keeps happening, please report it on GitHub Issues.": "Si cela continue, veuillez le signaler sur GitHub Issues.", "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.", "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.",
"Ignore": "Ignorer",
"Ignored upstream models": "Modèles amont ignorés", "Ignored upstream models": "Modèles amont ignorés",
"Image": "Image", "Image": "Image",
"Image Generation": "Génération d'images", "Image Generation": "Génération d'images",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "Aucun préréglage de chat ne correspond à votre recherche", "No chat presets match your search": "Aucun préréglage de chat ne correspond à votre recherche",
"No conflict entries available.": "Aucune entrée de conflit disponible.", "No conflict entries available.": "Aucune entrée de conflit disponible.",
"No conflicts match your search.": "Aucun conflit ne correspond à votre recherche.", "No conflicts match your search.": "Aucun conflit ne correspond à votre recherche.",
"No connection info found in clipboard": "Aucune info de connexion trouvée dans le presse-papiers",
"No console output": "Aucune sortie console", "No console output": "Aucune sortie console",
"No containers": "Aucun conteneur", "No containers": "Aucun conteneur",
"No content to copy": "Aucun contenu à copier", "No content to copy": "Aucun contenu à copier",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "Mot de passe réinitialisé : {{password}}", "Password reset: {{password}}": "Mot de passe réinitialisé : {{password}}",
"Passwords do not match": "Les mots de passe ne correspondent pas", "Passwords do not match": "Les mots de passe ne correspondent pas",
"Passwords don't match.": "Les mots de passe ne correspondent pas.", "Passwords don't match.": "Les mots de passe ne correspondent pas.",
"Paste Connection Info": "Coller les infos de connexion",
"Path": "Chemin", "Path": "Chemin",
"Path not set": "Chemin non défini", "Path not set": "Chemin non défini",
"Path Regex (one per line)": "Regex du chemin (un par ligne)", "Path Regex (one per line)": "Regex du chemin (un par ligne)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "Impossible d'ouvrir la discussion", "Unable to open chat": "Impossible d'ouvrir la discussion",
"Unable to parse structured pricing": "Impossible d'analyser la tarification structurée", "Unable to parse structured pricing": "Impossible d'analyser la tarification structurée",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "Impossible de préparer le lien de chat. Veuillez vous assurer d'avoir une clé API activée.", "Unable to prepare chat link. Please ensure you have an enabled API key.": "Impossible de préparer le lien de chat. Veuillez vous assurer d'avoir une clé API activée.",
"Unable to read clipboard": "Impossible de lire le presse-papiers",
"Unauthorized": "Non autorisé", "Unauthorized": "Non autorisé",
"Unauthorized Access": "Accès non autorisé", "Unauthorized Access": "Accès non autorisé",
"Unbind": "Dissocier", "Unbind": "Dissocier",
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "接続が閉じられました", "Connection closed": "接続が閉じられました",
"Connection error": "接続エラー", "Connection error": "接続エラー",
"Connection failed": "接続に失敗しました", "Connection failed": "接続に失敗しました",
"Connection info detected in clipboard": "クリップボードに接続情報が見つかりました",
"Connection info filled in": "接続情報を入力しました",
"Connection successful": "接続に成功しました", "Connection successful": "接続に成功しました",
"Console": "コンソール", "Console": "コンソール",
"Console area": "コンソールエリア", "Console area": "コンソールエリア",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "Codex CLI / Claude CLI テンプレートを入力", "Fill Codex CLI / Claude CLI Templates": "Codex CLI / Claude CLI テンプレートを入力",
"Fill example (all channels)": "例を入力(全チャネル)", "Fill example (all channels)": "例を入力(全チャネル)",
"Fill example (specific channels)": "例を入力(特定チャネル)", "Fill example (specific channels)": "例を入力(特定チャネル)",
"Fill in": "入力",
"Fill in both Merchant ID and API Private Key before creating.": "作成前に Merchant ID と API 秘密鍵の両方を入力してください。", "Fill in both Merchant ID and API Private Key before creating.": "作成前に Merchant ID と API 秘密鍵の両方を入力してください。",
"Fill in the credentials above to begin.": "開始するには上記の認証情報を入力してください。", "Fill in the credentials above to begin.": "開始するには上記の認証情報を入力してください。",
"Fill in the following info to create a new subscription plan": "以下の情報を入力して新しいサブスクリプションプランを作成", "Fill in the following info to create a new subscription plan": "以下の情報を入力して新しいサブスクリプションプランを作成",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.": "アフィニティチャネルが失敗し、別のチャネルでリトライが成功した場合、アフィニティを成功したチャネルに更新します。",
"If this keeps happening, please report it on GitHub Issues.": "この問題が続く場合は、GitHub Issues で報告してください。", "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 サービスを提供する場合、届出、セキュリティ評価、コンテンツ安全、苦情対応、生成コンテンツのラベル表示、ログ保存、個人情報保護などの法的義務を履行します。", "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 サービスを提供する場合、届出、セキュリティ評価、コンテンツ安全、苦情対応、生成コンテンツのラベル表示、ログ保存、個人情報保護などの法的義務を履行します。",
"Ignore": "無視",
"Ignored upstream models": "無視する上流モデル", "Ignored upstream models": "無視する上流モデル",
"Image": "画像", "Image": "画像",
"Image Generation": "画像生成", "Image Generation": "画像生成",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "検索に一致するチャットプリセットがありません", "No chat presets match your search": "検索に一致するチャットプリセットがありません",
"No conflict entries available.": "利用可能な競合エントリはありません。", "No conflict entries available.": "利用可能な競合エントリはありません。",
"No conflicts match your search.": "検索条件に一致する競合はありません。", "No conflicts match your search.": "検索条件に一致する競合はありません。",
"No connection info found in clipboard": "クリップボードに接続情報が見つかりません",
"No console output": "コンソール出力なし", "No console output": "コンソール出力なし",
"No containers": "コンテナがありません", "No containers": "コンテナがありません",
"No content to copy": "コピーする内容がありません", "No content to copy": "コピーする内容がありません",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "パスワードがリセットされました:{{password}}", "Password reset: {{password}}": "パスワードがリセットされました:{{password}}",
"Passwords do not match": "パスワードが一致しません", "Passwords do not match": "パスワードが一致しません",
"Passwords don't match.": "パスワードが一致しません。", "Passwords don't match.": "パスワードが一致しません。",
"Paste Connection Info": "接続情報を貼り付け",
"Path": "パス", "Path": "パス",
"Path not set": "パス未設定", "Path not set": "パス未設定",
"Path Regex (one per line)": "パス正規表現(1行に1つ)", "Path Regex (one per line)": "パス正規表現(1行に1つ)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "チャットを開けません", "Unable to open chat": "チャットを開けません",
"Unable to parse structured pricing": "構造化された価格を解析できません", "Unable to parse structured pricing": "構造化された価格を解析できません",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "チャットリンクを準備できません。有効な API キーが設定されていることを確認してください。", "Unable to prepare chat link. Please ensure you have an enabled API key.": "チャットリンクを準備できません。有効な API キーが設定されていることを確認してください。",
"Unable to read clipboard": "クリップボードを読み取れません",
"Unauthorized": "未認証", "Unauthorized": "未認証",
"Unauthorized Access": "不正アクセス", "Unauthorized Access": "不正アクセス",
"Unbind": "連携解除", "Unbind": "連携解除",
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "Соединение закрыто", "Connection closed": "Соединение закрыто",
"Connection error": "Ошибка соединения", "Connection error": "Ошибка соединения",
"Connection failed": "Не удалось подключиться", "Connection failed": "Не удалось подключиться",
"Connection info detected in clipboard": "В буфере обмена найдены данные подключения",
"Connection info filled in": "Данные подключения заполнены",
"Connection successful": "Подключение успешно", "Connection successful": "Подключение успешно",
"Console": "Консоль", "Console": "Консоль",
"Console area": "Область консоли", "Console area": "Область консоли",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "Заполнить шаблоны Codex CLI / Claude CLI", "Fill Codex CLI / Claude CLI Templates": "Заполнить шаблоны Codex CLI / Claude CLI",
"Fill example (all channels)": "Подставить пример (все каналы)", "Fill example (all channels)": "Подставить пример (все каналы)",
"Fill example (specific channels)": "Подставить пример (указанные каналы)", "Fill example (specific channels)": "Подставить пример (указанные каналы)",
"Fill in": "Заполнить",
"Fill in both Merchant ID and API Private Key before creating.": "Перед созданием заполните Merchant ID и приватный ключ API.", "Fill in both Merchant ID and API Private Key before creating.": "Перед созданием заполните Merchant ID и приватный ключ API.",
"Fill in the credentials above to begin.": "Чтобы начать, заполните учетные данные выше.", "Fill in the credentials above to begin.": "Чтобы начать, заполните учетные данные выше.",
"Fill in the following info to create a new subscription plan": "Заполните следующую информацию для создания нового плана подписки", "Fill in the following info to create a new subscription plan": "Заполните следующую информацию для создания нового плана подписки",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.": "Если привязанный канал не работает и повторная попытка удалась через другой канал, привязка обновляется на успешный канал.",
"If this keeps happening, please report it on GitHub Issues.": "Если проблема повторяется, сообщите о ней в GitHub Issues.", "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.": "Если вы предоставляете услуги генеративного ИИ населению материкового Китая, вы будете выполнять юридические обязанности, включая регистрацию, оценку безопасности, безопасность контента, обработку жалоб, маркировку сгенерированного контента, хранение журналов и защиту персональных данных.", "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.": "Если вы предоставляете услуги генеративного ИИ населению материкового Китая, вы будете выполнять юридические обязанности, включая регистрацию, оценку безопасности, безопасность контента, обработку жалоб, маркировку сгенерированного контента, хранение журналов и защиту персональных данных.",
"Ignore": "Игнорировать",
"Ignored upstream models": "Игнорируемые upstream-модели", "Ignored upstream models": "Игнорируемые upstream-модели",
"Image": "Изображение", "Image": "Изображение",
"Image Generation": "Генерация изображений", "Image Generation": "Генерация изображений",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "Нет пресетов чата, соответствующих вашему поиску", "No chat presets match your search": "Нет пресетов чата, соответствующих вашему поиску",
"No conflict entries available.": "Нет доступных записей конфликтов.", "No conflict entries available.": "Нет доступных записей конфликтов.",
"No conflicts match your search.": "Конфликты, соответствующие вашему поиску, не найдены.", "No conflicts match your search.": "Конфликты, соответствующие вашему поиску, не найдены.",
"No connection info found in clipboard": "В буфере обмена нет данных подключения",
"No console output": "Нет вывода консоли", "No console output": "Нет вывода консоли",
"No containers": "Нет контейнеров", "No containers": "Нет контейнеров",
"No content to copy": "Нет содержимого для копирования", "No content to copy": "Нет содержимого для копирования",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "Пароль сброшен: {{password}}", "Password reset: {{password}}": "Пароль сброшен: {{password}}",
"Passwords do not match": "Пароли не совпадают", "Passwords do not match": "Пароли не совпадают",
"Passwords don't match.": "Пароли не совпадают.", "Passwords don't match.": "Пароли не совпадают.",
"Paste Connection Info": "Вставить данные подключения",
"Path": "Путь", "Path": "Путь",
"Path not set": "Путь не задан", "Path not set": "Путь не задан",
"Path Regex (one per line)": "Регулярное выражение пути (по одному на строку)", "Path Regex (one per line)": "Регулярное выражение пути (по одному на строку)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "Не удалось открыть чат", "Unable to open chat": "Не удалось открыть чат",
"Unable to parse structured pricing": "Не удалось разобрать структурированные цены", "Unable to parse structured pricing": "Не удалось разобрать структурированные цены",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "Не удается подготовить ссылку для чата. Убедитесь, что у вас есть активированный API-ключ.", "Unable to prepare chat link. Please ensure you have an enabled API key.": "Не удается подготовить ссылку для чата. Убедитесь, что у вас есть активированный API-ключ.",
"Unable to read clipboard": "Не удалось прочитать буфер обмена",
"Unauthorized": "Не авторизован", "Unauthorized": "Не авторизован",
"Unauthorized Access": "Несанкционированный доступ", "Unauthorized Access": "Несанкционированный доступ",
"Unbind": "Отвязать", "Unbind": "Отвязать",
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "Kết nối đã đóng", "Connection closed": "Kết nối đã đóng",
"Connection error": "Lỗi kết nối", "Connection error": "Lỗi kết nối",
"Connection failed": "Kết nối thất bại", "Connection failed": "Kết nối thất bại",
"Connection info detected in clipboard": "Đã phát hiện thông tin kết nối trong bảng tạm",
"Connection info filled in": "Đã điền thông tin kết nối",
"Connection successful": "Kết nối thành công", "Connection successful": "Kết nối thành công",
"Console": "Bảng điều khiển", "Console": "Bảng điều khiển",
"Console area": "Khu vực bảng điều khiển", "Console area": "Khu vực bảng điều khiển",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "Điền mẫu Codex CLI / Claude CLI", "Fill Codex CLI / Claude CLI Templates": "Điền mẫu Codex CLI / Claude CLI",
"Fill example (all channels)": "Điền ví dụ (tất cả kênh)", "Fill example (all channels)": "Điền ví dụ (tất cả kênh)",
"Fill example (specific channels)": "Điền ví dụ (kênh cụ thể)", "Fill example (specific channels)": "Điền ví dụ (kênh cụ thể)",
"Fill in": "Điền",
"Fill in both Merchant ID and API Private Key before creating.": "Nhập cả Merchant ID và khóa riêng API trước khi tạo.", "Fill in both Merchant ID and API Private Key before creating.": "Nhập cả Merchant ID và khóa riêng API trước khi tạo.",
"Fill in the credentials above to begin.": "Nhập thông tin xác thực ở trên để bắt đầu.", "Fill in the credentials above to begin.": "Nhập thông tin xác thực ở trên để bắt đầu.",
"Fill in the following info to create a new subscription plan": "Điền thông tin sau để tạo gói đăng ký mới", "Fill in the following info to create a new subscription plan": "Điền thông tin sau để tạo gói đăng ký mới",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.", "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.",
"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 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.", "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.",
"Ignore": "Bỏ qua",
"Ignored upstream models": "Mô hình upstream bị bỏ qua", "Ignored upstream models": "Mô hình upstream bị bỏ qua",
"Image": "Hình ảnh", "Image": "Hình ảnh",
"Image Generation": "Tạo hình ảnh", "Image Generation": "Tạo hình ảnh",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "Không có cài đặt trước trò chuyện nào khớp với tìm kiếm của bạn", "No chat presets match your search": "Không có cài đặt trước trò chuyện nào khớp với tìm kiếm của bạn",
"No conflict entries available.": "Không có mục xung đột nào khả dụng.", "No conflict entries available.": "Không có mục xung đột nào khả dụng.",
"No conflicts match your search.": "Không có xung đột nào khớp với tìm kiếm của bạn.", "No conflicts match your search.": "Không có xung đột nào khớp với tìm kiếm của bạn.",
"No connection info found in clipboard": "Không tìm thấy thông tin kết nối trong bảng tạm",
"No console output": "Không có đầu ra console", "No console output": "Không có đầu ra console",
"No containers": "Không có container", "No containers": "Không có container",
"No content to copy": "Không có nội dung để sao chép", "No content to copy": "Không có nội dung để sao chép",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "Mật khẩu đã đặt lại: {{password}}", "Password reset: {{password}}": "Mật khẩu đã đặt lại: {{password}}",
"Passwords do not match": "Mật khẩu không khớp", "Passwords do not match": "Mật khẩu không khớp",
"Passwords don't match.": "Mật khẩu không khớp.", "Passwords don't match.": "Mật khẩu không khớp.",
"Paste Connection Info": "Dán thông tin kết nối",
"Path": "Đường dẫn", "Path": "Đường dẫn",
"Path not set": "Chưa đặt đường dẫn", "Path not set": "Chưa đặt đường dẫn",
"Path Regex (one per line)": "Regex đường dẫn (mỗi dòng một mục)", "Path Regex (one per line)": "Regex đường dẫn (mỗi dòng một mục)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "Không thể mở trò chuyện", "Unable to open chat": "Không thể mở trò chuyện",
"Unable to parse structured pricing": "Không thể phân tích giá có cấu trúc", "Unable to parse structured pricing": "Không thể phân tích giá có cấu trúc",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "Không thể chuẩn bị liên kết chat. Vui lòng đảm bảo bạn có khóa API được kích hoạt.", "Unable to prepare chat link. Please ensure you have an enabled API key.": "Không thể chuẩn bị liên kết chat. Vui lòng đảm bảo bạn có khóa API được kích hoạt.",
"Unable to read clipboard": "Không thể đọc bảng tạm",
"Unauthorized": "Chưa xác thực", "Unauthorized": "Chưa xác thực",
"Unauthorized Access": "Truy cập trái phép", "Unauthorized Access": "Truy cập trái phép",
"Unbind": "Hủy liên kết", "Unbind": "Hủy liên kết",
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "連接已關閉", "Connection closed": "連接已關閉",
"Connection error": "連接錯誤", "Connection error": "連接錯誤",
"Connection failed": "連接失敗", "Connection failed": "連接失敗",
"Connection info detected in clipboard": "偵測到剪貼簿中的連線資訊",
"Connection info filled in": "連線資訊已填入",
"Connection successful": "連接成功", "Connection successful": "連接成功",
"Console": "控制台", "Console": "控制台",
"Console area": "控制台區域", "Console area": "控制台區域",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "填充 Codex CLI / Claude CLI 模板", "Fill Codex CLI / Claude CLI Templates": "填充 Codex CLI / Claude CLI 模板",
"Fill example (all channels)": "填充示例(全部渠道)", "Fill example (all channels)": "填充示例(全部渠道)",
"Fill example (specific channels)": "填充示例(指定渠道)", "Fill example (specific channels)": "填充示例(指定渠道)",
"Fill in": "填入",
"Fill in both Merchant ID and API Private Key before creating.": "建立前請填寫 Merchant ID 和 API 私鑰。", "Fill in both Merchant ID and API Private Key before creating.": "建立前請填寫 Merchant ID 和 API 私鑰。",
"Fill in the credentials above to begin.": "請先填寫上方憑證。", "Fill in the credentials above to begin.": "請先填寫上方憑證。",
"Fill in the following info to create a new subscription plan": "填寫以下資訊建立新的訂閱套餐", "Fill in the following info to create a new subscription plan": "填寫以下資訊建立新的訂閱套餐",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.": "如果親和到的渠道失敗,重試到其他渠道成功後,將親和更新到成功的渠道。",
"If this keeps happening, please report it on GitHub Issues.": "如果問題持續出現,請到 GitHub Issues 反饋。", "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.": "如果你在中國大陸向公眾提供生成式人工智能服務,你將履行備案、安全評估、內容安全、投訴處理、生成內容標識、日誌留存和個人資訊保護等法律義務。", "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.": "如果你在中國大陸向公眾提供生成式人工智能服務,你將履行備案、安全評估、內容安全、投訴處理、生成內容標識、日誌留存和個人資訊保護等法律義務。",
"Ignore": "忽略",
"Ignored upstream models": "已忽略上游模型", "Ignored upstream models": "已忽略上游模型",
"Image": "圖片", "Image": "圖片",
"Image Generation": "圖片生成", "Image Generation": "圖片生成",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "沒有匹配的聊天預設", "No chat presets match your search": "沒有匹配的聊天預設",
"No conflict entries available.": "沒有可用的衝突條目。", "No conflict entries available.": "沒有可用的衝突條目。",
"No conflicts match your search.": "沒有衝突匹配您的搜尋。", "No conflicts match your search.": "沒有衝突匹配您的搜尋。",
"No connection info found in clipboard": "剪貼簿中未找到連線資訊",
"No console output": "無控制台輸出", "No console output": "無控制台輸出",
"No containers": "無容器", "No containers": "無容器",
"No content to copy": "沒有可複製的內容", "No content to copy": "沒有可複製的內容",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "密碼已重置:{{password}}", "Password reset: {{password}}": "密碼已重置:{{password}}",
"Passwords do not match": "密碼不匹配", "Passwords do not match": "密碼不匹配",
"Passwords don't match.": "兩次輸入的密碼不一致。", "Passwords don't match.": "兩次輸入的密碼不一致。",
"Paste Connection Info": "貼上連線資訊",
"Path": "路徑", "Path": "路徑",
"Path not set": "未設定路徑", "Path not set": "未設定路徑",
"Path Regex (one per line)": "路徑正則(每行一個)", "Path Regex (one per line)": "路徑正則(每行一個)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "無法打開聊天", "Unable to open chat": "無法打開聊天",
"Unable to parse structured pricing": "無法解析為結構化價格", "Unable to parse structured pricing": "無法解析為結構化價格",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "無法準備聊天連結。請確保您有一個已啟用的 API 金鑰。", "Unable to prepare chat link. Please ensure you have an enabled API key.": "無法準備聊天連結。請確保您有一個已啟用的 API 金鑰。",
"Unable to read clipboard": "無法讀取剪貼簿",
"Unauthorized": "未經授權", "Unauthorized": "未經授權",
"Unauthorized Access": "未經授權的存取", "Unauthorized Access": "未經授權的存取",
"Unbind": "解綁", "Unbind": "解綁",
......
...@@ -1011,6 +1011,8 @@ ...@@ -1011,6 +1011,8 @@
"Connection closed": "连接已关闭", "Connection closed": "连接已关闭",
"Connection error": "连接错误", "Connection error": "连接错误",
"Connection failed": "连接失败", "Connection failed": "连接失败",
"Connection info detected in clipboard": "检测到剪贴板中的连接信息",
"Connection info filled in": "连接信息已填入",
"Connection successful": "连接成功", "Connection successful": "连接成功",
"Console": "控制台", "Console": "控制台",
"Console area": "控制台区域", "Console area": "控制台区域",
...@@ -1923,6 +1925,7 @@ ...@@ -1923,6 +1925,7 @@
"Fill Codex CLI / Claude CLI Templates": "填充 Codex CLI / Claude CLI 模板", "Fill Codex CLI / Claude CLI Templates": "填充 Codex CLI / Claude CLI 模板",
"Fill example (all channels)": "填充示例(全部渠道)", "Fill example (all channels)": "填充示例(全部渠道)",
"Fill example (specific channels)": "填充示例(指定渠道)", "Fill example (specific channels)": "填充示例(指定渠道)",
"Fill in": "填入",
"Fill in both Merchant ID and API Private Key before creating.": "创建前请填写 Merchant ID 和 API 私钥。", "Fill in both Merchant ID and API Private Key before creating.": "创建前请填写 Merchant ID 和 API 私钥。",
"Fill in the credentials above to begin.": "请先填写上方凭证。", "Fill in the credentials above to begin.": "请先填写上方凭证。",
"Fill in the following info to create a new subscription plan": "填写以下信息创建新的订阅套餐", "Fill in the following info to create a new subscription plan": "填写以下信息创建新的订阅套餐",
...@@ -2232,6 +2235,7 @@ ...@@ -2232,6 +2235,7 @@
"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.": "如果亲和到的渠道失败,重试到其他渠道成功后,将亲和更新到成功的渠道。",
"If this keeps happening, please report it on GitHub Issues.": "如果问题持续出现,请到 GitHub Issues 反馈。", "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.": "如果你在中国大陆向公众提供生成式人工智能服务,你将履行备案、安全评估、内容安全、投诉处理、生成内容标识、日志留存和个人信息保护等法律义务。", "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.": "如果你在中国大陆向公众提供生成式人工智能服务,你将履行备案、安全评估、内容安全、投诉处理、生成内容标识、日志留存和个人信息保护等法律义务。",
"Ignore": "忽略",
"Ignored upstream models": "已忽略上游模型", "Ignored upstream models": "已忽略上游模型",
"Image": "图片", "Image": "图片",
"Image Generation": "图片生成", "Image Generation": "图片生成",
...@@ -2809,6 +2813,7 @@ ...@@ -2809,6 +2813,7 @@
"No chat presets match your search": "没有匹配的聊天预设", "No chat presets match your search": "没有匹配的聊天预设",
"No conflict entries available.": "没有可用的冲突条目。", "No conflict entries available.": "没有可用的冲突条目。",
"No conflicts match your search.": "没有冲突匹配您的搜索。", "No conflicts match your search.": "没有冲突匹配您的搜索。",
"No connection info found in clipboard": "剪贴板中未找到连接信息",
"No console output": "无控制台输出", "No console output": "无控制台输出",
"No containers": "无容器", "No containers": "无容器",
"No content to copy": "没有可复制的内容", "No content to copy": "没有可复制的内容",
...@@ -3202,6 +3207,7 @@ ...@@ -3202,6 +3207,7 @@
"Password reset: {{password}}": "密码已重置:{{password}}", "Password reset: {{password}}": "密码已重置:{{password}}",
"Passwords do not match": "密码不匹配", "Passwords do not match": "密码不匹配",
"Passwords don't match.": "两次输入的密码不一致。", "Passwords don't match.": "两次输入的密码不一致。",
"Paste Connection Info": "粘贴连接信息",
"Path": "路径", "Path": "路径",
"Path not set": "未设置路径", "Path not set": "未设置路径",
"Path Regex (one per line)": "路径正则(每行一个)", "Path Regex (one per line)": "路径正则(每行一个)",
...@@ -4658,6 +4664,7 @@ ...@@ -4658,6 +4664,7 @@
"Unable to open chat": "无法打开聊天", "Unable to open chat": "无法打开聊天",
"Unable to parse structured pricing": "无法解析为结构化价格", "Unable to parse structured pricing": "无法解析为结构化价格",
"Unable to prepare chat link. Please ensure you have an enabled API key.": "无法准备聊天链接。请确保您有一个已启用的 API 密钥。", "Unable to prepare chat link. Please ensure you have an enabled API key.": "无法准备聊天链接。请确保您有一个已启用的 API 密钥。",
"Unable to read clipboard": "无法读取剪贴板",
"Unauthorized": "未授权", "Unauthorized": "未授权",
"Unauthorized Access": "未经授权的访问", "Unauthorized Access": "未经授权的访问",
"Unbind": "解绑", "Unbind": "解绑",
......
/*
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
*/
export const CHANNEL_CONNECTION_INFO_TYPE = 'newapi_channel_conn'
export type ChannelConnectionInfo = {
key: string
url: string
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null
}
export function encodeChannelConnectionInfo(key: string, url: string): string {
return JSON.stringify({
_type: CHANNEL_CONNECTION_INFO_TYPE,
key,
url,
})
}
export function parseChannelConnectionInfo(
text: string | null | undefined
): ChannelConnectionInfo | null {
if (!text || typeof text !== 'string') return null
try {
const parsed: unknown = JSON.parse(text.trim())
if (
isRecord(parsed) &&
parsed._type === CHANNEL_CONNECTION_INFO_TYPE &&
typeof parsed.key === 'string' &&
typeof parsed.url === 'string'
) {
return { key: parsed.key, url: parsed.url }
}
} catch {
/* not valid connection info JSON */
}
return null
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment