fix: localize provider source config UI (#4933)

* fix: localize provider source ui

* feat: localize provider metadata keys

* chore: add provider metadata translations

* chore: format provider i18n changes

* fix: preserve metadata fields in i18n conversion

* fix: internationalize platform config and dialog

* fix: add Weixin official account platform icon

---------

Co-authored-by: Soulter <905617992@qq.com>
This commit is contained in:
letr
2026-02-08 10:40:26 +08:00
committed by GitHub
parent 5e5207da95
commit e48950d260
13 changed files with 1621 additions and 125 deletions
+56 -47
View File
@@ -42,6 +42,55 @@ class ConfigMetadataI18n:
"""
result = {}
def convert_items(
group: str, section: str, items: dict[str, Any], prefix: str = ""
) -> dict[str, Any]:
items_result: dict[str, Any] = {}
for field_key, field_data in items.items():
if not isinstance(field_data, dict):
items_result[field_key] = field_data
continue
field_name = field_key
field_path = f"{prefix}.{field_name}" if prefix else field_name
field_result = {
key: value
for key, value in field_data.items()
if key not in {"description", "hint", "labels", "name"}
}
if "description" in field_data:
field_result["description"] = (
f"{group}.{section}.{field_path}.description"
)
if "hint" in field_data:
field_result["hint"] = f"{group}.{section}.{field_path}.hint"
if "labels" in field_data:
field_result["labels"] = f"{group}.{section}.{field_path}.labels"
if "name" in field_data:
field_result["name"] = f"{group}.{section}.{field_path}.name"
if "items" in field_data and isinstance(field_data["items"], dict):
field_result["items"] = convert_items(
group, section, field_data["items"], field_path
)
if "template_schema" in field_data and isinstance(
field_data["template_schema"], dict
):
field_result["template_schema"] = convert_items(
group,
section,
field_data["template_schema"],
f"{field_path}.template_schema",
)
items_result[field_key] = field_result
return items_result
for group_key, group_data in metadata.items():
group_result = {
"name": f"{group_key}.name",
@@ -50,59 +99,19 @@ class ConfigMetadataI18n:
for section_key, section_data in group_data.get("metadata", {}).items():
section_result = {
"description": f"{group_key}.{section_key}.description",
"type": section_data.get("type"),
key: value
for key, value in section_data.items()
if key not in {"description", "hint", "labels", "name"}
}
section_result["description"] = f"{group_key}.{section_key}.description"
# 复制其他属性
for key in ["items", "condition", "_special", "invisible"]:
if key in section_data:
section_result[key] = section_data[key]
# 处理 hint
if "hint" in section_data:
section_result["hint"] = f"{group_key}.{section_key}.hint"
# 处理 items 中的字段
if "items" in section_data and isinstance(section_data["items"], dict):
items_result = {}
for field_key, field_data in section_data["items"].items():
# 处理嵌套的点号字段名(如 provider_settings.enable
field_name = field_key
field_result = {}
# 复制基本属性
for attr in [
"type",
"condition",
"_special",
"invisible",
"options",
"slider",
]:
if attr in field_data:
field_result[attr] = field_data[attr]
# 转换文本属性为国际化键
if "description" in field_data:
field_result["description"] = (
f"{group_key}.{section_key}.{field_name}.description"
)
if "hint" in field_data:
field_result["hint"] = (
f"{group_key}.{section_key}.{field_name}.hint"
)
if "labels" in field_data:
field_result["labels"] = (
f"{group_key}.{section_key}.{field_name}.labels"
)
items_result[field_key] = field_result
section_result["items"] = items_result
section_result["items"] = convert_items(
group_key, section_key, section_data["items"]
)
group_result["metadata"][section_key] = section_result
+33 -8
View File
@@ -1,4 +1,5 @@
import asyncio
import copy
import inspect
import os
import traceback
@@ -407,8 +408,19 @@ class ConfigRoute(Route):
return Response().ok(message="更新 provider source 成功").__dict__
async def get_provider_template(self):
provider_metadata = ConfigMetadataI18n.convert_to_i18n_keys(
{
"provider_group": {
"metadata": {
"provider": CONFIG_METADATA_2["provider_group"]["metadata"][
"provider"
]
}
}
}
)
config_schema = {
"provider": CONFIG_METADATA_2["provider_group"]["metadata"]["provider"]
"provider": provider_metadata["provider_group"]["metadata"]["provider"]
}
data = {
"config_schema": config_schema,
@@ -1278,11 +1290,24 @@ class ConfigRoute(Route):
async def _get_astrbot_config(self):
config = self.config
metadata = copy.deepcopy(CONFIG_METADATA_2)
platform_i18n = ConfigMetadataI18n.convert_to_i18n_keys(
{
"platform_group": {
"metadata": {
"platform": metadata["platform_group"]["metadata"]["platform"]
}
}
}
)
metadata["platform_group"]["metadata"]["platform"] = platform_i18n[
"platform_group"
]["metadata"]["platform"]
# 平台适配器的默认配置模板注入
platform_default_tmpl = CONFIG_METADATA_2["platform_group"]["metadata"][
"platform"
]["config_template"]
platform_default_tmpl = metadata["platform_group"]["metadata"]["platform"][
"config_template"
]
# 收集需要注册logo的平台
logo_registration_tasks = []
@@ -1300,14 +1325,14 @@ class ConfigRoute(Route):
await asyncio.gather(*logo_registration_tasks, return_exceptions=True)
# 服务提供商的默认配置模板注入
provider_default_tmpl = CONFIG_METADATA_2["provider_group"]["metadata"][
"provider"
]["config_template"]
provider_default_tmpl = metadata["provider_group"]["metadata"]["provider"][
"config_template"
]
for provider in provider_registry:
if provider.default_config_tmpl:
provider_default_tmpl[provider.type] = provider.default_config_tmpl
return {"metadata": CONFIG_METADATA_2, "config": config}
return {"metadata": metadata, "config": config}
async def _get_plugin_config(self, plugin_name: str):
ret: dict = {"metadata": None, "config": None}
@@ -9,14 +9,14 @@
</div>
<div style="flex: 1;">
<h3>
选择消息平台类别
{{ tm('createDialog.step1Title') }}
</h3>
<small style="color: grey;">想把机器人接入到哪里 QQ企业微信飞书DiscordTelegram </small>
<small style="color: grey;">{{ tm('createDialog.step1Hint') }}</small>
<div>
<div v-if="!updatingMode">
<v-select v-model="selectedPlatformType" :items="Object.keys(platformTemplates)" item-title="name"
item-value="name" label="消息平台类别" variant="outlined" rounded="md" dense hide-details class="mt-6"
item-value="name" :label="tm('createDialog.platformTypeLabel')" variant="outlined" rounded="md" dense hide-details class="mt-6"
style="max-width: 30%; min-width: 300px;">
<template v-slot:item="{ props: itemProps, item }">
@@ -41,7 +41,7 @@
</div>
</div>
<div v-else>
<v-text-field label="消息平台类别" variant="outlined" rounded="md" dense hide-details class="mt-6"
<v-text-field :label="tm('createDialog.platformTypeLabel')" variant="outlined" rounded="md" dense hide-details class="mt-6"
style="max-width: 30%; min-width: 300px;" v-model="updatingPlatformConfig.type"
disabled></v-text-field>
<div class="mt-3">
@@ -65,13 +65,13 @@
<div>
<div class="d-flex align-center">
<h3>
配置文件
{{ tm('createDialog.configFileTitle') }}
</h3>
<v-chip size="x-small" color="primary" variant="tonal" rounded="sm" class="ml-2"
v-if="!updatingMode">可选</v-chip>
v-if="!updatingMode">{{ tm('createDialog.optional') }}</v-chip>
</div>
<small style="color: grey;">想如何配置机器人配置文件包含了聊天模型人格知识库插件范围等丰富的机器人配置项</small>
<small style="color: grey;" v-if="!updatingMode">默认使用默认配置文件 default您也可以稍后配置</small>
<small style="color: grey;">{{ tm('createDialog.configHint') }}</small>
<small style="color: grey;" v-if="!updatingMode">{{ tm('createDialog.configDefaultHint') }}</small>
</div>
<div>
<v-btn variant="plain" icon @click="toggleConfigSection" class="mt-2">
@@ -86,12 +86,12 @@
<v-radio-group class="mt-2" v-model="aBConfigRadioVal" hide-details="true">
<v-radio value="0">
<template v-slot:label>
<span>使用现有配置文件</span>
<span>{{ tm('createDialog.useExistingConfig') }}</span>
</template>
</v-radio>
<div class="d-flex align-center ml-10 my-2" v-if="aBConfigRadioVal === '0'">
<v-select v-model="selectedAbConfId" :items="configInfoList" item-title="name"
item-value="id" label="选择配置文件" variant="outlined" rounded="md" dense hide-details
item-value="id" :label="tm('createDialog.selectConfigLabel')" variant="outlined" rounded="md" dense hide-details
style="max-width: 30%; min-width: 200px;">
</v-select>
<v-btn icon variant="text" density="comfortable" class="ml-2"
@@ -99,10 +99,10 @@
<v-icon>mdi-arrow-top-right-thick</v-icon>
</v-btn>
</div>
<v-radio value="1" label="创建新配置文件">
<v-radio value="1" :label="tm('createDialog.createNewConfig')">
</v-radio>
<div class="d-flex align-center" v-if="aBConfigRadioVal === '1'">
<v-text-field v-model="selectedAbConfId" label="新配置文件名称" variant="outlined" rounded="md" dense
<v-text-field v-model="selectedAbConfId" :label="tm('createDialog.newConfigNameLabel')" variant="outlined" rounded="md" dense
hide-details style="max-width: 30%; min-width: 200px;" class="ml-10 my-2">
</v-text-field>
</div>
@@ -131,12 +131,12 @@
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else-if="newConfigData && newConfigMetadata" class="config-preview-container">
<h4 class="mb-3">使用新的配置文件</h4>
<h4 class="mb-3">{{ tm('createDialog.newConfigTitle') }}</h4>
<AstrBotCoreConfigWrapper :metadata="newConfigMetadata" :config_data="newConfigData" />
</div>
<div v-else class="text-center py-4 text-grey">
<v-icon>mdi-information-outline</v-icon>
<p class="mt-2">无法加载默认配置模板</p>
<p class="mt-2">{{ tm('createDialog.newConfigLoadFailed') }}</p>
</div>
</div>
@@ -147,18 +147,18 @@
<div>
<v-btn v-if="isEditingRoutes" color="primary" variant="tonal" @click="addNewRoute" size="small">
<v-icon start>mdi-plus</v-icon>
添加路由规则
{{ tm('createDialog.addRouteRule') }}
</v-btn>
</div>
<v-btn :color="isEditingRoutes ? 'grey' : 'primary'" variant="tonal" size="small"
@click="toggleEditMode">
<v-icon start>{{ isEditingRoutes ? 'mdi-eye' : 'mdi-pencil' }}</v-icon>
{{ isEditingRoutes ? '查看' : '编辑' }}
{{ isEditingRoutes ? tm('createDialog.viewMode') : tm('createDialog.editMode') }}
</v-btn>
</div>
<v-data-table :headers="routeTableHeaders" :items="platformRoutes" item-value="umop"
no-data-text="该平台暂无路由规则将使用默认配置文件" hide-default-footer :items-per-page="-1" class="mt-2"
:no-data-text="tm('createDialog.noRouteRules')" hide-default-footer :items-per-page="-1" class="mt-2"
variant="outlined">
<template v-slot:item.source="{ item }">
@@ -170,9 +170,9 @@
<small v-else>{{ getMessageTypeLabel(item.messageType) }}</small>
<small class="mx-1">:</small>
<v-text-field v-if="isEditingRoutes" v-model="item.sessionId" variant="outlined" density="compact"
hide-details placeholder="会话ID或*">
hide-details :placeholder="tm('createDialog.sessionIdPlaceholder')">
</v-text-field>
<small v-else>{{ item.sessionId === '*' ? '全部会话' : item.sessionId }}</small>
<small v-else>{{ item.sessionId === '*' ? tm('createDialog.allSessions') : item.sessionId }}</small>
</div>
</template>
@@ -191,7 +191,7 @@
</v-btn>
</div>
<small v-if="configInfoList.findIndex(c => c.id === item.configId) === -1" style="color: red;"
class="ml-2">配置文件不存在</small>
class="ml-2">{{ tm('createDialog.configMissing') }}</small>
</template>
<template v-slot:item.actions="{ item, index }">
@@ -211,8 +211,7 @@
</template>
</v-data-table>
<small class="ml-2 mt-2 d-block" style="color: grey">*消息下发时根据会话来源按顺序从上到下匹配首个符合条件的配置文件使用 * 表示匹配所有使用 /sid 指令获取会话
ID全部不匹配时将使用默认配置文件</small>
<small class="ml-2 mt-2 d-block" style="color: grey">{{ tm('createDialog.routeHint') }}</small>
</div>
</div>
@@ -266,10 +265,10 @@
<v-card-actions class="px-4 pb-4">
<v-spacer></v-spacer>
<v-btn color="error" @click="handleOneBotEmptyTokenWarningDismiss(true)">
无视警告并继续创建
{{ tm('createDialog.warningContinue') }}
</v-btn>
<v-btn color="primary" @click="handleOneBotEmptyTokenWarningDismiss(false)">
重新修改
{{ tm('createDialog.warningEditAgain') }}
</v-btn>
</v-card-actions>
</v-card>
@@ -286,9 +285,9 @@
<v-card class="config-drawer-card" elevation="12">
<div class="config-drawer-header">
<div>
<span class="text-h6">配置文件管理</span>
<span class="text-h6">{{ tm('createDialog.configDrawerTitle') }}</span>
<div v-if="configDrawerTargetId" class="text-caption text-grey">
ID: {{ configDrawerTargetId }}
{{ tm('createDialog.configDrawerIdLabel') }}: {{ configDrawerTargetId }}
</div>
</div>
<v-btn icon variant="text" @click="closeConfigDrawer">
@@ -359,23 +358,9 @@ export default {
// 平台配置文件表格(已弃用,改用 platformRoutes
platformConfigs: [],
configTableHeaders: [
{ title: '与此实例关联的配置文件 ID', key: 'name', sortable: false },
{ title: '在此实例下的应用范围', key: 'scope', sortable: false },
],
// 平台路由表
platformRoutes: [],
routeTableHeaders: [
{ title: '消息会话来源(消息类型:会话 ID)', key: 'source', sortable: false, width: '60%' },
{ title: '使用配置文件', key: 'configId', sortable: false, width: '20%' },
{ title: '操作', key: 'actions', sortable: false, align: 'center', width: '20%' },
],
messageTypeOptions: [
{ label: '全部消息', value: '*' },
{ label: '群组消息(GroupMessage)', value: 'GroupMessage' },
{ label: '私聊消息(FriendMessage)', value: 'FriendMessage' },
],
isEditingRoutes: false, // 编辑模式开关
// ID冲突确认对话框
@@ -437,6 +422,26 @@ export default {
}
return false;
},
configTableHeaders() {
return [
{ title: this.tm('createDialog.configTableHeaders.configId'), key: 'name', sortable: false },
{ title: this.tm('createDialog.configTableHeaders.scope'), key: 'scope', sortable: false },
];
},
routeTableHeaders() {
return [
{ title: this.tm('createDialog.routeTableHeaders.source'), key: 'source', sortable: false, width: '60%' },
{ title: this.tm('createDialog.routeTableHeaders.config'), key: 'configId', sortable: false, width: '20%' },
{ title: this.tm('createDialog.routeTableHeaders.actions'), key: 'actions', sortable: false, align: 'center', width: '20%' },
];
},
messageTypeOptions() {
return [
{ label: this.tm('createDialog.messageTypeOptions.all'), value: '*' },
{ label: this.tm('createDialog.messageTypeOptions.group'), value: 'GroupMessage' },
{ label: this.tm('createDialog.messageTypeOptions.friend'), value: 'FriendMessage' },
];
}
},
watch: {
@@ -603,7 +608,7 @@ export default {
const targetId = configId || 'default';
if (configId && this.configInfoList.findIndex(c => c.id === configId) === -1) {
this.showError('目标配置文件不存在,已打开配置页面以便检查。');
this.showError(this.tm('messages.configNotFoundOpenConfig'));
}
this.configDrawerTargetId = targetId;
@@ -637,7 +642,7 @@ export default {
const id = this.originalUpdatingPlatformId || this.updatingPlatformConfig.id;
if (!id) {
this.loading = false;
this.showError('更新失败,缺少平台 ID。');
this.showError(this.tm('messages.updateMissingPlatformId'));
return;
}
@@ -655,7 +660,7 @@ export default {
})
if (resp.data.status === 'error') {
throw new Error(resp.data.message || '平台更新失败');
throw new Error(resp.data.message || this.tm('messages.platformUpdateFailed'));
}
// 同时更新路由表
@@ -665,7 +670,7 @@ export default {
this.showDialog = false;
this.resetForm();
this.$emit('refresh-config');
this.showSuccess('更新成功');
this.showSuccess(this.tm('messages.updateSuccess'));
} catch (err) {
this.loading = false;
this.showError(err.response?.data?.message || err.message);
@@ -710,7 +715,7 @@ export default {
this.showDialog = false;
this.resetForm();
this.$emit('refresh-config');
this.showSuccess(res.data.message || '平台添加成功,配置文件已更新');
this.showSuccess(res.data.message || this.tm('messages.addSuccessWithConfig'));
} catch (err) {
this.loading = false;
this.showError(err.response?.data?.message || err.message);
@@ -738,7 +743,7 @@ export default {
}
if (!configId) {
throw new Error('无法获取配置文件ID');
throw new Error(this.tm('messages.configIdMissing'));
}
// 第二步:统一更新路由表
@@ -755,7 +760,8 @@ export default {
console.log(`成功更新路由表: ${umop} -> ${configId}`);
} catch (err) {
console.error('更新路由表失败:', err);
throw new Error(`更新路由表失败: ${err.response?.data?.message || err.message}`);
const errorMessage = err.response?.data?.message || err.message;
throw new Error(this.tm('messages.routingUpdateFailed', { message: errorMessage }));
}
},
@@ -778,7 +784,8 @@ export default {
return newConfigId;
} catch (err) {
console.error('创建新配置文件失败:', err);
throw new Error(`创建新配置文件失败: ${err.response?.data?.message || err.message}`);
const errorMessage = err.response?.data?.message || err.message;
throw new Error(this.tm('messages.createConfigFailed', { message: errorMessage }));
}
},
@@ -922,7 +929,7 @@ export default {
const newPlatformId = this.updatingPlatformConfig?.id || originalPlatformId;
if (!originalPlatformId && !newPlatformId) {
throw new Error('无法获取平台 ID');
throw new Error(this.tm('messages.platformIdMissing'));
}
try {
@@ -958,7 +965,8 @@ export default {
});
} catch (err) {
console.error('保存路由表失败:', err);
throw new Error(`保存路由表失败: ${err.response?.data?.message || err.message}`);
const errorMessage = err.response?.data?.message || err.message;
throw new Error(this.tm('messages.routingSaveFailed', { message: errorMessage }));
}
},
@@ -987,10 +995,10 @@ export default {
// 获取消息类型标签
getMessageTypeLabel(messageType) {
const typeMap = {
'*': '全部消息',
'': '全部消息',
'GroupMessage': '群组消息',
'FriendMessage': '私聊消息'
'*': this.tm('createDialog.messageTypeLabels.all'),
'': this.tm('createDialog.messageTypeLabels.all'),
'GroupMessage': this.tm('createDialog.messageTypeLabels.group'),
'FriendMessage': this.tm('createDialog.messageTypeLabels.friend')
};
return typeMap[messageType] || messageType;
},
@@ -14,7 +14,7 @@
rounded="xl"
size="small"
>
新增
{{ tm('providerSources.add') }}
</v-btn>
</template>
<v-list density="compact">
@@ -3,7 +3,7 @@ import { VueMonacoEditor } from '@guolao/vue-monaco-editor'
import { ref, computed } from 'vue'
import ConfigItemRenderer from './ConfigItemRenderer.vue'
import TemplateListEditor from './TemplateListEditor.vue'
import { useI18n } from '@/i18n/composables'
import { useI18n, useModuleI18n } from '@/i18n/composables'
import axios from 'axios'
import { useToast } from '@/utils/toast'
@@ -35,6 +35,12 @@ const props = defineProps({
})
const { t } = useI18n()
const { tm, getRaw } = useModuleI18n('features/config-metadata')
const translateIfKey = (value) => {
if (!value || typeof value !== 'string') return value
return getRaw(value) ? tm(value) : value
}
const filteredIterable = computed(() => {
if (!props.iterable) return {}
@@ -134,11 +140,11 @@ function hasVisibleItemsAfter(items, currentIndex) {
<template>
<div class="config-section" v-if="iterable && metadata[metadataKey]?.type === 'object'">
<v-list-item-title class="config-title">
{{ metadata[metadataKey]?.description }} <span class="metadata-key">({{ metadataKey }})</span>
{{ translateIfKey(metadata[metadataKey]?.description) }} <span class="metadata-key">({{ metadataKey }})</span>
</v-list-item-title>
<v-list-item-subtitle class="config-hint">
<span v-if="metadata[metadataKey]?.obvious_hint && metadata[metadataKey]?.hint" class="important-hint"></span>
{{ metadata[metadataKey]?.hint }}
{{ translateIfKey(metadata[metadataKey]?.hint) }}
</v-list-item-subtitle>
</div>
@@ -180,14 +186,14 @@ function hasVisibleItemsAfter(items, currentIndex) {
<div class="config-section mb-2">
<v-list-item-title class="config-title">
<span v-if="metadata[metadataKey].items[key]?.description">
{{ metadata[metadataKey].items[key]?.description }}
{{ translateIfKey(metadata[metadataKey].items[key]?.description) }}
<span class="property-key">({{ key }})</span>
</span>
<span v-else>{{ key }}</span>
</v-list-item-title>
<v-list-item-subtitle class="config-hint">
<span v-if="metadata[metadataKey].items[key]?.obvious_hint && metadata[metadataKey].items[key]?.hint" class="important-hint"></span>
{{ metadata[metadataKey].items[key]?.hint }}
{{ translateIfKey(metadata[metadataKey].items[key]?.hint) }}
</v-list-item-subtitle>
</div>
<TemplateListEditor
@@ -205,7 +211,7 @@ function hasVisibleItemsAfter(items, currentIndex) {
<v-list-item density="compact">
<v-list-item-title class="property-name">
<span v-if="metadata[metadataKey].items[key]?.description">
{{ metadata[metadataKey].items[key]?.description }}
{{ translateIfKey(metadata[metadataKey].items[key]?.description) }}
<span class="property-key">({{ key }})</span>
</span>
<span v-else>{{ key }}</span>
@@ -214,7 +220,7 @@ function hasVisibleItemsAfter(items, currentIndex) {
<v-list-item-subtitle class="property-hint">
<span v-if="metadata[metadataKey].items[key]?.obvious_hint && metadata[metadataKey].items[key]?.hint"
class="important-hint"></span>
{{ metadata[metadataKey].items[key]?.hint }}
{{ translateIfKey(metadata[metadataKey].items[key]?.hint) }}
</v-list-item-subtitle>
</v-list-item>
</v-col>
@@ -59,14 +59,14 @@ export function useProviderSources(options: UseProviderSourcesOptions) {
let suppressSourceWatch = false
const providerTypes = [
const providerTypes = computed(() => [
{ value: 'chat_completion', label: tm('providers.tabs.chatCompletion'), icon: 'mdi-message-text' },
{ value: 'agent_runner', label: tm('providers.tabs.agentRunner'), icon: 'mdi-robot' },
{ value: 'speech_to_text', label: tm('providers.tabs.speechToText'), icon: 'mdi-microphone-message' },
{ value: 'text_to_speech', label: tm('providers.tabs.textToSpeech'), icon: 'mdi-volume-high' },
{ value: 'embedding', label: tm('providers.tabs.embedding'), icon: 'mdi-code-json' },
{ value: 'rerank', label: tm('providers.tabs.rerank'), icon: 'mdi-compare-vertical' }
]
])
// ===== Computed =====
const availableSourceTypes = computed(() => {
@@ -294,6 +294,235 @@
},
"platform_group": {
"name": "Platform",
"platform": {
"description": "Message Platform Adapters",
"active_send_mode": {
"description": "Use Proactive Send API"
},
"appid": {
"description": "App ID",
"hint": "Required. App ID for the QQ Official Bot platform. See the docs for how to obtain it."
},
"callback_server_host": {
"description": "Callback Server Host",
"hint": "Callback server host. Leave empty to disable the callback server."
},
"card_template_id": {
"description": "Card Template ID",
"hint": "Optional. DingTalk interactive card template ID. When enabled, streaming replies will use interactive cards."
},
"discord_activity_name": {
"description": "Discord Activity Name",
"hint": "Optional Discord activity name. Leave empty to disable."
},
"discord_command_register": {
"description": "Auto-register plugin commands as Discord slash commands"
},
"discord_proxy": {
"description": "Discord Proxy URL",
"hint": "Optional proxy URL: http://ip:port"
},
"discord_token": {
"description": "Discord Bot Token",
"hint": "Enter your Discord Bot Token here."
},
"enable": {
"description": "Enable",
"hint": "Whether to enable this adapter. Disabled adapters will not receive messages."
},
"enable_group_c2c": {
"description": "Enable Message List Private Chat",
"hint": "When enabled, the bot can receive private chats from QQ message list. You may need to add the bot as a friend by scanning a QR code in the QQ bot platform. See docs."
},
"enable_guild_direct_message": {
"description": "Enable Guild Direct Messages",
"hint": "When enabled, the bot can receive guild direct messages."
},
"id": {
"description": "Bot Name",
"hint": "Bot name"
},
"is_sandbox": {
"description": "Sandbox Mode"
},
"kf_name": {
"description": "WeChat Customer Service Account Name",
"hint": "Optional. Customer service account name (not ID). Get it at https://kf.weixin.qq.com/kf/frame#/accounts"
},
"lark_bot_name": {
"description": "Lark Bot Name",
"hint": "Must be correct; otherwise @ mentions will not wake the bot and only prefix wake will work."
},
"lark_connection_mode": {
"description": "Subscription Mode",
"labels": [
"Long Connection Mode",
"Webhook Server Mode"
]
},
"lark_encrypt_key": {
"description": "Encrypt Key",
"hint": "Encryption key for decrypting Lark callback data."
},
"lark_verification_token": {
"description": "Verification Token",
"hint": "Token for verifying Lark callback requests."
},
"misskey_allow_insecure_downloads": {
"description": "Allow Insecure Downloads (Disable SSL Verification)",
"hint": "If remote servers have certificate issues, SSL verification will be disabled as a fallback. Use only when necessary due to security risks."
},
"misskey_default_visibility": {
"description": "Default Post Visibility",
"hint": "Default visibility for bot posts. public: public, home: home timeline, followers: followers only."
},
"misskey_download_chunk_size": {
"description": "Stream Download Chunk Size (bytes)",
"hint": "Bytes read per chunk during streaming download and MD5 calculation. Too small increases overhead; too large uses more memory."
},
"misskey_download_timeout": {
"description": "Remote Download Timeout (seconds)",
"hint": "Timeout for downloading remote files (seconds), used when falling back to local upload."
},
"misskey_enable_chat": {
"description": "Enable Chat Message Responses",
"hint": "When enabled, the bot listens and responds to private chat messages."
},
"misskey_enable_file_upload": {
"description": "Enable File Upload to Misskey",
"hint": "When enabled, the adapter uploads files in message chains to Misskey. URL files try server-side upload first; if async upload fails, it falls back to local download and upload."
},
"misskey_instance_url": {
"description": "Misskey Instance URL",
"hint": "e.g. https://misskey.example. The Misskey instance where the bot account lives."
},
"misskey_local_only": {
"description": "Local Only (No Federation)",
"hint": "When enabled, bot posts are visible only on this instance and are not federated."
},
"misskey_max_download_bytes": {
"description": "Max Download Size (bytes)",
"hint": "To limit download size to prevent OOM, set the maximum bytes; empty or null means no limit."
},
"misskey_token": {
"description": "Misskey Access Token",
"hint": "API access token generated in the connection service settings."
},
"misskey_upload_concurrency": {
"description": "Upload Concurrency Limit",
"hint": "Max number of concurrent upload tasks (integer, default 3)."
},
"misskey_upload_folder": {
"description": "Target Drive Folder ID",
"hint": "Optional: ID of the target folder in Misskey drive. Leave empty to use the root folder."
},
"port": {
"description": "Callback Server Port",
"hint": "Callback server port. Leave empty to disable the callback server."
},
"satori_api_base_url": {
"description": "Satori API Endpoint",
"hint": "Base URL for the Satori API."
},
"satori_auto_reconnect": {
"description": "Enable Auto Reconnect",
"hint": "Automatically reconnect the WebSocket when disconnected."
},
"satori_endpoint": {
"description": "Satori WebSocket Endpoint",
"hint": "WebSocket endpoint for Satori events."
},
"satori_heartbeat_interval": {
"description": "Satori Heartbeat Interval",
"hint": "Interval in seconds between heartbeat messages."
},
"satori_reconnect_delay": {
"description": "Satori Reconnect Delay",
"hint": "Delay before attempting to reconnect (seconds)."
},
"satori_token": {
"description": "Satori Token",
"hint": "Token for Satori API authentication."
},
"secret": {
"description": "Secret",
"hint": "Required."
},
"slack_connection_mode": {
"description": "Slack Connection Mode",
"hint": "The connection mode for Slack. `webhook` uses a webhook server, `socket` uses Slack's Socket Mode."
},
"slack_webhook_host": {
"description": "Slack Webhook Host",
"hint": "Only valid when Slack connection mode is `webhook`."
},
"slack_webhook_path": {
"description": "Slack Webhook Path",
"hint": "Only valid when Slack connection mode is `webhook`."
},
"slack_webhook_port": {
"description": "Slack Webhook Port",
"hint": "Only valid when Slack connection mode is `webhook`."
},
"telegram_command_auto_refresh": {
"description": "Telegram Command Auto Refresh",
"hint": "When enabled, AstrBot automatically refreshes Telegram commands at runtime. (Setting this alone has no effect)"
},
"telegram_command_register": {
"description": "Telegram Command Registration",
"hint": "When enabled, AstrBot automatically registers Telegram commands."
},
"telegram_command_register_interval": {
"description": "Telegram Command Auto Refresh Interval",
"hint": "Telegram command auto-refresh interval in seconds."
},
"telegram_token": {
"description": "Bot Token",
"hint": "If you are in mainland China, set a proxy or change api_base in Other Settings."
},
"type": {
"description": "Adapter Type"
},
"unified_webhook_mode": {
"description": "Unified Webhook Mode",
"hint": "When enabled, use AstrBot unified webhook entry without opening a separate port. Callback URL is /api/platform/webhook/{webhook_uuid}."
},
"webhook_uuid": {
"description": "Webhook UUID",
"hint": "Unique identifier for unified webhook mode; generated when creating the platform."
},
"wecom_ai_bot_name": {
"description": "WeCom AI Bot Name",
"hint": "Must be correct; otherwise some commands won't work."
},
"wecomaibot_friend_message_welcome_text": {
"description": "WeCom AI Bot DM Welcome Message",
"hint": "When a user enters a DM session on that day, reply with a welcome message. Leave empty to disable."
},
"wecomaibot_init_respond_text": {
"description": "WeCom AI Bot Initial Response Text",
"hint": "First reply when the bot receives a message. Leave empty to use default."
},
"wpp_active_message_poll": {
"description": "Enable Proactive Message Polling",
"hint": "Only enable if WeChat messages are not syncing to AstrBot on time. Disabled by default."
},
"wpp_active_message_poll_interval": {
"description": "Proactive Message Poll Interval",
"hint": "Interval in seconds, default 3, should not exceed 60 or it may be considered old messages."
},
"ws_reverse_host": {
"description": "Reverse WebSocket Host",
"hint": "AstrBot acts as the server."
},
"ws_reverse_port": {
"description": "Reverse WebSocket Port"
},
"ws_reverse_token": {
"description": "Reverse WebSocket Token",
"hint": "Reverse WebSocket token. If not set, token verification is disabled."
}
},
"general": {
"description": "General",
"admins_id": {
@@ -619,6 +848,443 @@
}
}
},
"provider_group": {
"provider": {
"genie_onnx_model_dir": {
"description": "ONNX Model Directory",
"hint": "The directory path containing the ONNX model files"
},
"genie_language": {
"description": "Language"
},
"xai_native_search": {
"description": "Enable native search",
"hint": "When enabled, uses xAI Chat Completions native Live Search for web queries (billed on demand). Only applies to xAI providers."
},
"rerank_api_base": {
"description": "Rerank Model API Base URL",
"hint": "AstrBot appends /v1/rerank to the request URL."
},
"rerank_api_key": {
"description": "API Key",
"hint": "Leave empty if no API key is required."
},
"rerank_model": {
"description": "Rerank model name"
},
"return_documents": {
"description": "Return source documents in rerank results",
"hint": "Default is false to reduce network overhead."
},
"instruct": {
"description": "Custom rerank task description",
"hint": "Only effective for qwen3-rerank models. Recommended to write in English."
},
"launch_model_if_not_running": {
"description": "Auto-start model if not running",
"hint": "If the model is not running in Xinference, attempt to start it automatically. Recommended to disable in production."
},
"modalities": {
"description": "Model capabilities",
"hint": "Modalities supported by the model. If the model does not support images, uncheck image.",
"labels": [
"Text",
"Image",
"Tool use"
]
},
"custom_headers": {
"description": "Custom request headers",
"hint": "Key/value pairs added here are merged into the OpenAI SDK default_headers for custom HTTP headers. Values must be strings."
},
"custom_extra_body": {
"description": "Custom request body parameters",
"hint": "Add extra parameters to requests, such as temperature, top_p, max_tokens, etc.",
"template_schema": {
"temperature": {
"description": "Temperature",
"hint": "Controls randomness, typically 0-2. Higher is more random.",
"name": "Temperature"
},
"top_p": {
"description": "Top-p sampling",
"hint": "Nucleus sampling parameter, usually 0-1. Controls probability mass considered.",
"name": "Top-p"
},
"max_tokens": {
"description": "Max tokens",
"hint": "Maximum number of generated tokens.",
"name": "Max Tokens"
}
}
},
"gpt_weights_path": {
"description": "GPT model file path",
"hint": "The .ckpt file. Use an absolute path without quotes. Leave empty to use the GPT_SoVITS built-in SoVITS model (recommended to change defaults in GPT_SoVITS)."
},
"sovits_weights_path": {
"description": "SoVITS model file path",
"hint": "The .pth file. Use an absolute path without quotes. Leave empty to use the GPT_SoVITS built-in SoVITS model (recommended to change defaults in GPT_SoVITS)."
},
"gsv_default_parms": {
"description": "GPT_SoVITS default parameters",
"hint": "Reference audio file path and text are required; other parameters are optional.",
"gsv_ref_audio_path": {
"description": "Reference audio file path",
"hint": "Required! Use an absolute path without quotes."
},
"gsv_prompt_text": {
"description": "Reference audio text",
"hint": "Required! Provide the transcript of the reference audio."
},
"gsv_prompt_lang": {
"description": "Reference audio text language",
"hint": "Language of the reference audio text; default is Chinese."
},
"gsv_aux_ref_audio_paths": {
"description": "Auxiliary reference audio file paths",
"hint": "Auxiliary reference audio files; optional."
},
"gsv_text_lang": {
"description": "Text language",
"hint": "Default is Chinese."
},
"gsv_top_k": {
"description": "Speech diversity",
"hint": ""
},
"gsv_top_p": {
"description": "Nucleus sampling threshold",
"hint": ""
},
"gsv_temperature": {
"description": "Speech randomness",
"hint": ""
},
"gsv_text_split_method": {
"description": "Text splitting method",
"hint": "Options: `cut0` no split, `cut1` split every 4 sentences, `cut2` split every 50 chars, `cut3` split by Chinese period, `cut4` split by English period, `cut5` split by punctuation."
},
"gsv_batch_size": {
"description": "Batch size",
"hint": ""
},
"gsv_batch_threshold": {
"description": "Batch threshold",
"hint": ""
},
"gsv_split_bucket": {
"description": "Split text into buckets for parallel processing",
"hint": ""
},
"gsv_speed_factor": {
"description": "Speech playback speed",
"hint": "1 is the original speed."
},
"gsv_fragment_interval": {
"description": "Interval between speech segments",
"hint": ""
},
"gsv_streaming_mode": {
"description": "Enable streaming mode",
"hint": ""
},
"gsv_seed": {
"description": "Random seed",
"hint": "For reproducible results."
},
"gsv_parallel_infer": {
"description": "Run inference in parallel",
"hint": ""
},
"gsv_repetition_penalty": {
"description": "Repetition penalty",
"hint": ""
},
"gsv_media_type": {
"description": "Output media type",
"hint": "Recommended: wav"
}
},
"embedding_dimensions": {
"description": "Embedding dimensions",
"hint": "Embedding vector dimensions. May need adjustment per model; see model documentation. This must be correct or the vector database will not work."
},
"embedding_model": {
"description": "Embedding model",
"hint": "Embedding model name."
},
"embedding_api_key": {
"description": "API Key"
},
"embedding_api_base": {
"description": "API Base URL"
},
"volcengine_cluster": {
"description": "Volcengine cluster",
"hint": "For voice cloning models, choose volcano_icl or volcano_icl_concurr; default is volcano_tts."
},
"volcengine_voice_type": {
"description": "Volcengine voice",
"hint": "Enter voice id (Voice_type)."
},
"volcengine_speed_ratio": {
"description": "Speech rate",
"hint": "Speech rate, range 0.2 to 3.0, default 1.0."
},
"volcengine_volume_ratio": {
"description": "Volume",
"hint": "Volume, range 0.0 to 2.0, default 1.0."
},
"azure_tts_voice": {
"description": "Voice style",
"hint": "API voice name"
},
"azure_tts_style": {
"description": "Style",
"hint": "A voice-specific speaking style. Can express emotions like happy, sympathetic, and calm."
},
"azure_tts_role": {
"description": "Role (optional)",
"hint": "Speaking role-play. The voice can emulate different ages and genders without changing the voice name. For example, a male voice can raise pitch to simulate a female voice, but the voice name does not change. If the role is missing or unsupported, this attribute is ignored."
},
"azure_tts_rate": {
"description": "Speech rate",
"hint": "Controls speaking rate. You can apply the rate at word or sentence level. Rate should be 0.5x to 2x of original audio."
},
"azure_tts_volume": {
"description": "Speech volume",
"hint": "Controls volume level. You can apply changes at sentence level. Use 0.0 to 100.0 (quiet to loud, e.g., 75). Default is 100.0."
},
"azure_tts_region": {
"description": "API region",
"hint": "Region where Azure TTS processes data. See https://learn.microsoft.com/zh-cn/azure/ai-services/speech-service/regions"
},
"azure_tts_subscription_key": {
"description": "Service subscription key",
"hint": "Azure TTS subscription key (not a token)."
},
"dashscope_tts_voice": {
"description": "Voice"
},
"gm_resp_image_modal": {
"description": "Enable image modality",
"hint": "When enabled, responses can include images. Requires model support or it will error. See the Google Gemini website for supported models. Tip: if you need image generation, disable the `Enable member recognition` setting for better results."
},
"gm_native_search": {
"description": "Enable native search",
"hint": "When enabled, all function tools are disabled. Check official docs for free quota limits."
},
"gm_native_coderunner": {
"description": "Enable native code runner",
"hint": "When enabled, all function tools are disabled."
},
"gm_url_context": {
"description": "Enable URL context",
"hint": "When enabled, all function tools are disabled."
},
"gm_safety_settings": {
"description": "Safety filters",
"hint": "Set the safety filtering level for model input. Levels: NONE (no blocking), HIGH (block high risk), MEDIUM_AND_ABOVE (block medium risk and above), LOW_AND_ABOVE (block low risk and above). See Gemini API docs.",
"harassment": {
"description": "Harassment",
"hint": "Negative or harmful comments"
},
"hate_speech": {
"description": "Hate speech",
"hint": "Rude, disrespectful, or profane content"
},
"sexually_explicit": {
"description": "Sexually explicit content",
"hint": "References to sexual acts or other obscene content"
},
"dangerous_content": {
"description": "Dangerous content",
"hint": "Content that promotes, encourages, or assists harmful behavior"
}
},
"gm_thinking_config": {
"description": "Thinking Config",
"budget": {
"description": "Thinking Budget",
"hint": "Guides the model on the specific number of thinking tokens to use for reasoning. See: https://ai.google.dev/gemini-api/docs/thinking#set-budget"
},
"level": {
"description": "Thinking Level",
"hint": "Recommended for Gemini 3 models and onwards, lets you control reasoning behavior.See: https://ai.google.dev/gemini-api/docs/thinking#thinking-levels"
}
},
"anth_thinking_config": {
"description": "Thinking Config",
"budget": {
"description": "Thinking Budget",
"hint": "Anthropic thinking.budget_tokens param. Must >= 1024. See: https://platform.claude.com/docs/en/build-with-claude/extended-thinking"
}
},
"minimax-group-id": {
"description": "User group",
"hint": "Visible in Account Management -> Basic Info."
},
"minimax-langboost": {
"description": "Target language/dialect",
"hint": "Enhances recognition for specified languages/dialects and improves speech performance in those scenarios."
},
"minimax-voice-speed": {
"description": "Speech rate",
"hint": "Speech speed for synthesis, range [0.5, 2], default 1.0. Higher is faster."
},
"minimax-voice-vol": {
"description": "Volume",
"hint": "Volume for synthesis, range (0, 10], default 1.0. Higher is louder."
},
"minimax-voice-pitch": {
"description": "Pitch",
"hint": "Pitch for synthesis, range [-12, 12], default 0."
},
"minimax-is-timber-weight": {
"description": "Enable mixed voices",
"hint": "Enable mixing up to four voices with custom weights. When enabled, single voice settings are ignored."
},
"minimax-timber-weight": {
"description": "Mixed voices",
"hint": "Mixed voices and their weights. Up to four voices, integer weights in [1, 100]. Get presets and templates from the official API TTS debug console. Must be a JSON string; check the console to confirm parsing. See defaults and the official code preview for structure."
},
"minimax-voice-id": {
"description": "Single voice",
"hint": "Single voice ID; see the official documentation."
},
"minimax-voice-emotion": {
"description": "Emotion",
"hint": "Controls emotion of synthesized speech. When set to auto, it selects emotion based on text."
},
"minimax-voice-latex": {
"description": "Read LaTeX formulas",
"hint": "Read LaTeX formulas, but ensure input text is formatted per the official requirements."
},
"minimax-voice-english-normalization": {
"description": "English text normalization",
"hint": "Improves number-reading performance but slightly increases latency."
},
"rag_options": {
"description": "RAG options",
"hint": "Knowledge base retrieval settings, optional. Only supported for Agent app types (agent apps, including RAG apps). For Bailian apps, enabling this disables multi-turn conversations.",
"pipeline_ids": {
"description": "Knowledge base ID list",
"hint": "Retrieve all documents in the specified knowledge bases. Go to https://bailian.console.aliyun.com/ Data Apps -> Knowledge Index to create and get IDs."
},
"file_ids": {
"description": "Unstructured document IDs",
"hint": "Retrieve specified unstructured documents. Go to https://bailian.console.aliyun.com/ Data Management to create and get IDs."
},
"output_reference": {
"description": "Output knowledge base/document references",
"hint": "Append reference sources to the end of each answer. Default is False."
}
},
"sensevoice_hint": {
"description": "Deploy SenseVoice",
"hint": "Before enabling, install funasr, funasr_onnx, torchaudio, torch, modelscope, and jieba (CPU by default, about 1 GB download), and install ffmpeg. Otherwise STT will not work."
},
"is_emotion": {
"description": "Emotion recognition",
"hint": "Enable emotion recognition. happy?sad?angry?neutral?fearful?disgusted?surprised?unknown"
},
"stt_model": {
"description": "Model name",
"hint": "Model name on modelscope. Default: iic/SenseVoiceSmall."
},
"variables": {
"description": "Workflow fixed input variables",
"hint": "Optional. Fixed workflow input variables are used as workflow inputs. You can also set variables dynamically with /set during a chat. If names conflict, dynamic settings take precedence."
},
"dashscope_app_type": {
"description": "App type",
"hint": "Bailian app type."
},
"timeout": {
"description": "Timeout",
"hint": "Timeout in seconds."
},
"openai-tts-voice": {
"description": "voice",
"hint": "OpenAI TTS voice. OpenAI defaults: 'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'."
},
"fishaudio-tts-character": {
"description": "character",
"hint": "Fishaudio TTS character. Default is Klee. More roles: https://fish.audio/zh-CN/discovery"
},
"fishaudio-tts-reference-id": {
"description": "reference_id",
"hint": "Fishaudio TTS reference model ID (optional). If set, the model ID is used directly instead of looking up by role name. Example: 626bb6d3f3364c9cbc3aa6a67300a664. More models: https://fish.audio/zh-CN/discovery; open a model detail page to copy the model ID."
},
"whisper_hint": {
"description": "Notes for local Whisper deployment",
"hint": "Before enabling, install the openai-whisper library (NVIDIA users download ~2GB mainly for torch and cuda; CPU users download ~1GB), and install ffmpeg. Otherwise STT will not work."
},
"id": {
"description": "ID"
},
"type": {
"description": "Provider category"
},
"provider_type": {
"description": "Provider capability type"
},
"enable": {
"description": "Enable"
},
"key": {
"description": "API Key"
},
"api_base": {
"description": "API Base URL"
},
"model": {
"description": "Model ID",
"hint": "Model name, e.g., gpt-4o-mini, deepseek-chat."
},
"max_context_tokens": {
"description": "Model context window size",
"hint": "Maximum context tokens. If 0, it auto-fills from model metadata (if available); you can also edit manually."
},
"dify_api_key": {
"description": "API Key",
"hint": "Dify API Key. This field is required."
},
"dify_api_base": {
"description": "API Base URL",
"hint": "Dify API Base URL. Default: https://api.dify.ai/v1"
},
"dify_api_type": {
"description": "Dify app type",
"hint": "Dify API type. According to Dify docs, supported types are chat, chatflow, agent, workflow."
},
"dify_workflow_output_key": {
"description": "Dify workflow output variable name",
"hint": "Dify workflow output variable name. Only used when app type is workflow. Default: astrbot_wf_output."
},
"dify_query_input_key": {
"description": "Prompt input variable name",
"hint": "Input variable name for the message text. Default: astrbot_text_query."
},
"coze_api_key": {
"description": "Coze API Key",
"hint": "Coze API key for accessing Coze services."
},
"bot_id": {
"description": "Bot ID",
"hint": "Coze bot ID, obtained after creating a bot on the Coze platform."
},
"coze_api_base": {
"description": "API Base URL",
"hint": "Base URL for the Coze API. Default: https://api.coze.cn"
},
"auto_save_history": {
"description": "Conversation history managed by Coze",
"hint": "When enabled, Coze manages conversation history. AstrBot's locally saved context will not take effect (read-only), and operations on AstrBot context will not apply. If disabled, AstrBot manages the context."
}
}
},
"help": {
"documentation": "Official Documentation",
"support": "Join Support Group",
@@ -45,12 +45,67 @@
},
"invalidPlatformId": "Platform ID cannot contain ':' or '!'."
},
"createDialog": {
"step1Title": "Choose Platform Category",
"step1Hint": "Where do you want to connect the bot? e.g. QQ, WeCom, Feishu, Discord, Telegram.",
"platformTypeLabel": "Platform Category",
"configFileTitle": "Config File",
"optional": "Optional",
"configHint": "How do you want to configure the bot? The config file includes model, persona, knowledge base, plugins, and more.",
"configDefaultHint": "Uses the default config file \"default\" by default. You can configure it later.",
"useExistingConfig": "Use existing config file",
"selectConfigLabel": "Select config file",
"createNewConfig": "Create new config file",
"newConfigNameLabel": "New config name",
"newConfigTitle": "Use new config file",
"newConfigLoadFailed": "Failed to load default config template",
"addRouteRule": "Add route rule",
"viewMode": "View",
"editMode": "Edit",
"noRouteRules": "No route rules for this platform. The default config file will be used.",
"sessionIdPlaceholder": "Session ID or *",
"allSessions": "All sessions",
"configMissing": "Config file not found",
"routeHint": "When delivering messages, the first matching config file from top to bottom is used based on session source. Use * to match all. Use /sid to get the session ID. If none match, the default config file is used.",
"warningContinue": "Ignore warning and continue",
"warningEditAgain": "Edit again",
"configDrawerTitle": "Config File Management",
"configDrawerIdLabel": "ID",
"configTableHeaders": {
"configId": "Config ID linked to this instance",
"scope": "Scope in this instance"
},
"routeTableHeaders": {
"source": "Message Source (Type: Session ID)",
"config": "Config File",
"actions": "Actions"
},
"messageTypeOptions": {
"all": "All messages",
"group": "Group messages (GroupMessage)",
"friend": "Direct messages (FriendMessage)"
},
"messageTypeLabels": {
"all": "All messages",
"group": "Group messages",
"friend": "Direct messages"
}
},
"messages": {
"updateSuccess": "Update successful!",
"addSuccess": "Add successful!",
"deleteSuccess": "Delete successful!",
"statusUpdateSuccess": "Status update successful!",
"deleteConfirm": "Are you sure you want to delete platform adapter"
"deleteConfirm": "Are you sure you want to delete platform adapter",
"configNotFoundOpenConfig": "Target config file not found. Opened the config page for review.",
"updateMissingPlatformId": "Update failed: missing platform ID.",
"platformUpdateFailed": "Platform update failed.",
"addSuccessWithConfig": "Platform added. Config file updated.",
"configIdMissing": "Unable to get config file ID.",
"routingUpdateFailed": "Failed to update routing table: {message}",
"createConfigFailed": "Failed to create config file: {message}",
"platformIdMissing": "Unable to get platform ID.",
"routingSaveFailed": "Failed to save routing table: {message}"
},
"status": {
"enabled": "Enabled",
@@ -91,6 +91,7 @@
},
"providerSources": {
"title": "Provider Sources",
"add": "Add",
"empty": "No provider sources",
"selectHint": "Please select a provider source",
"save": "Save Configuration",
@@ -141,4 +142,4 @@
"modelId": "Model ID"
}
}
}
}
@@ -197,7 +197,10 @@
},
"context_limit_reached_strategy": {
"description": "超出模型上下文窗口时的处理方式",
"labels": ["按对话轮数截断", "由 LLM 压缩上下文"],
"labels": [
"按对话轮数截断",
"由 LLM 压缩上下文"
],
"hint": "当按对话轮数截断时,会根据上面\"丢弃对话轮数\"的配置丢弃最旧的 N 轮对话。当由 LLM 压缩上下文时,会使用指定的模型进行上下文压缩。"
},
"llm_compress_instruction": {
@@ -272,7 +275,6 @@
"关闭流式回复"
]
},
"wake_prefix": {
"description": "LLM 聊天额外唤醒前缀",
"hint": "如果唤醒前缀为 /, 额外聊天唤醒前缀为 chat,则需要 /chat 才会触发 LLM 请求"
@@ -295,6 +297,235 @@
},
"platform_group": {
"name": "平台配置",
"platform": {
"description": "消息平台适配器",
"active_send_mode": {
"description": "是否换用主动发送接口"
},
"appid": {
"description": "appid",
"hint": "必填项。QQ 官方机器人平台的 appid。如何获取请参考文档。"
},
"callback_server_host": {
"description": "回调服务器主机",
"hint": "回调服务器主机。留空则不启用回调服务器。"
},
"card_template_id": {
"description": "卡片模板 ID",
"hint": "可选。钉钉互动卡片模板 ID。启用后将使用互动卡片进行流式回复。"
},
"discord_activity_name": {
"description": "Discord 活动名称",
"hint": "可选的 Discord 活动名称。留空则不设置活动。"
},
"discord_command_register": {
"description": "是否自动将插件指令注册为 Discord 斜杠指令"
},
"discord_proxy": {
"description": "Discord 代理地址",
"hint": "可选的代理地址:http://ip:port"
},
"discord_token": {
"description": "Discord Bot Token",
"hint": "在此处填入你的 Discord Bot Token"
},
"enable": {
"description": "启用",
"hint": "是否启用该适配器。未启用的适配器对应的消息平台将不会接收到消息。"
},
"enable_group_c2c": {
"description": "启用消息列表单聊",
"hint": "启用后,机器人可以接收到 QQ 消息列表中的私聊消息。你可能需要在 QQ 机器人平台上通过扫描二维码的方式添加机器人为你的好友。详见文档。"
},
"enable_guild_direct_message": {
"description": "启用频道私聊",
"hint": "启用后,机器人可以接收到频道的私聊消息。"
},
"id": {
"description": "机器人名称",
"hint": "机器人名称"
},
"is_sandbox": {
"description": "沙箱模式"
},
"kf_name": {
"description": "微信客服账号名",
"hint": "可选。微信客服账号名(不是 ID)。可在 https://kf.weixin.qq.com/kf/frame#/accounts 获取"
},
"lark_bot_name": {
"description": "飞书机器人的名字",
"hint": "请务必填写正确,否则 @ 机器人将无法唤醒,只能通过前缀唤醒。"
},
"lark_connection_mode": {
"description": "订阅方式",
"labels": [
"长连接模式",
"推送至服务器模式"
]
},
"lark_encrypt_key": {
"description": "Encrypt Key",
"hint": "用于解密飞书回调数据的加密密钥"
},
"lark_verification_token": {
"description": "Verification Token",
"hint": "用于验证飞书回调请求的令牌"
},
"misskey_allow_insecure_downloads": {
"description": "允许不安全下载(禁用 SSL 验证)",
"hint": "当远端服务器存在证书问题导致无法正常下载时,自动禁用 SSL 验证作为回退方案。适用于某些图床的证书配置问题。启用有安全风险,仅在必要时使用。"
},
"misskey_default_visibility": {
"description": "默认帖子可见性",
"hint": "机器人发帖时的默认可见性设置。public:公开,home:主页时间线,followers:仅关注者。"
},
"misskey_download_chunk_size": {
"description": "流式下载分块大小(字节)",
"hint": "流式下载和计算 MD5 时使用的每次读取字节数,过小会增加开销,过大会占用内存。"
},
"misskey_download_timeout": {
"description": "远端下载超时时间(秒)",
"hint": "下载远程文件时的超时时间(秒),用于异步上传回退到本地上传的场景。"
},
"misskey_enable_chat": {
"description": "启用聊天消息响应",
"hint": "启用后,机器人将会监听和响应私信聊天消息"
},
"misskey_enable_file_upload": {
"description": "启用文件上传到 Misskey",
"hint": "启用后,适配器会尝试将消息链中的文件上传到 Misskey。URL 文件会先尝试服务器端上传,异步上传失败时会回退到下载后本地上传。"
},
"misskey_instance_url": {
"description": "Misskey 实例 URL",
"hint": "例如 https://misskey.example,填写 Bot 账号所在的 Misskey 实例地址"
},
"misskey_local_only": {
"description": "仅限本站(不参与联合)",
"hint": "启用后,机器人发出的帖子将仅在本实例可见,不会联合到其他实例"
},
"misskey_max_download_bytes": {
"description": "最大允许下载字节数(超出则中止)",
"hint": "如果希望限制下载文件的最大大小以防止 OOM,请填写最大字节数;留空或 null 表示不限制。"
},
"misskey_token": {
"description": "Misskey Access Token",
"hint": "连接服务设置生成的 API 鉴权访问令牌(Access token"
},
"misskey_upload_concurrency": {
"description": "并发上传限制",
"hint": "同时进行的文件上传任务上限(整数,默认 3)。"
},
"misskey_upload_folder": {
"description": "上传到网盘的目标文件夹 ID",
"hint": "可选:填写 Misskey 网盘中目标文件夹的 ID,上传的文件将放置到该文件夹内。留空则使用账号网盘根目录。"
},
"port": {
"description": "回调服务器端口",
"hint": "回调服务器端口。留空则不启用回调服务器。"
},
"satori_api_base_url": {
"description": "Satori API 终结点",
"hint": "Satori API 的基础地址。"
},
"satori_auto_reconnect": {
"description": "启用自动重连",
"hint": "断开连接时是否自动重新连接 WebSocket。"
},
"satori_endpoint": {
"description": "Satori WebSocket 终结点",
"hint": "Satori 事件的 WebSocket 端点。"
},
"satori_heartbeat_interval": {
"description": "Satori 心跳间隔",
"hint": "发送心跳消息的间隔(秒)。"
},
"satori_reconnect_delay": {
"description": "Satori 重连延迟",
"hint": "尝试重新连接前的延迟时间(秒)。"
},
"satori_token": {
"description": "Satori 令牌",
"hint": "用于 Satori API 身份验证的令牌。"
},
"secret": {
"description": "secret",
"hint": "必填项。"
},
"slack_connection_mode": {
"description": "Slack Connection Mode",
"hint": "The connection mode for Slack. `webhook` uses a webhook server, `socket` uses Slack's Socket Mode."
},
"slack_webhook_host": {
"description": "Slack Webhook Host",
"hint": "Only valid when Slack connection mode is `webhook`."
},
"slack_webhook_path": {
"description": "Slack Webhook Path",
"hint": "Only valid when Slack connection mode is `webhook`."
},
"slack_webhook_port": {
"description": "Slack Webhook Port",
"hint": "Only valid when Slack connection mode is `webhook`."
},
"telegram_command_auto_refresh": {
"description": "Telegram 命令自动刷新",
"hint": "启用后,AstrBot 将会在运行时自动刷新 Telegram 命令。(单独设置此项无效)"
},
"telegram_command_register": {
"description": "Telegram 命令注册",
"hint": "启用后,AstrBot 将会自动注册 Telegram 命令。"
},
"telegram_command_register_interval": {
"description": "Telegram 命令自动刷新间隔",
"hint": "Telegram 命令自动刷新间隔,单位为秒。"
},
"telegram_token": {
"description": "Bot Token",
"hint": "如果你的网络环境为中国大陆,请在 `其他配置` 处设置代理或更改 api_base。"
},
"type": {
"description": "适配器类型"
},
"unified_webhook_mode": {
"description": "统一 Webhook 模式",
"hint": "启用后,将使用 AstrBot 统一 Webhook 入口,无需单独开启端口。回调地址为 /api/platform/webhook/{webhook_uuid}。"
},
"webhook_uuid": {
"description": "Webhook UUID",
"hint": "统一 Webhook 模式下的唯一标识符,创建平台时自动生成。"
},
"wecom_ai_bot_name": {
"description": "企业微信智能机器人的名字",
"hint": "请务必填写正确,否则无法使用一些指令。"
},
"wecomaibot_friend_message_welcome_text": {
"description": "企业微信智能机器人私聊欢迎语",
"hint": "当用户当天进入智能机器人单聊会话,回复欢迎语,留空则不回复。"
},
"wecomaibot_init_respond_text": {
"description": "企业微信智能机器人初始响应文本",
"hint": "当机器人收到消息时,首先回复的文本内容。留空则使用默认值。"
},
"wpp_active_message_poll": {
"description": "是否启用主动消息轮询",
"hint": "只有当你发现微信消息没有按时同步到 AstrBot 时,才需要启用这个功能,默认不启用。"
},
"wpp_active_message_poll_interval": {
"description": "主动消息轮询间隔",
"hint": "主动消息轮询间隔,单位为秒,默认 3 秒,最大不要超过 60 秒,否则可能被认为是旧消息。"
},
"ws_reverse_host": {
"description": "反向 Websocket 主机",
"hint": "AstrBot 将作为服务器端。"
},
"ws_reverse_port": {
"description": "反向 Websocket 端口"
},
"ws_reverse_token": {
"description": "反向 Websocket Token",
"hint": "反向 Websocket Token。未设置则不启用 Token 验证。"
}
},
"general": {
"description": "基本",
"admins_id": {
@@ -620,6 +851,443 @@
}
}
},
"provider_group": {
"provider": {
"genie_onnx_model_dir": {
"description": "ONNX Model Directory",
"hint": "The directory path containing the ONNX model files"
},
"genie_language": {
"description": "Language"
},
"xai_native_search": {
"description": "启用原生搜索功能",
"hint": "启用后,将通过 xAI 的 Chat Completions 原生 Live Search 进行联网检索(按需计费)。仅对 xAI 提供商生效。"
},
"rerank_api_base": {
"description": "重排序模型 API Base URL",
"hint": "AstrBot 会在请求时在末尾加上 /v1/rerank。"
},
"rerank_api_key": {
"description": "API Key",
"hint": "如果不需要 API Key, 请留空。"
},
"rerank_model": {
"description": "重排序模型名称"
},
"return_documents": {
"description": "是否在排序结果中返回文档原文",
"hint": "默认值false,以减少网络传输开销。"
},
"instruct": {
"description": "自定义排序任务类型说明",
"hint": "仅在使用 qwen3-rerank 模型时生效。建议使用英文撰写。"
},
"launch_model_if_not_running": {
"description": "模型未运行时自动启动",
"hint": "如果模型当前未在 Xinference 服务中运行,是否尝试自动启动它。在生产环境中建议关闭。"
},
"modalities": {
"description": "模型能力",
"hint": "模型支持的模态。如所填写的模型不支持图像,请取消勾选图像。",
"labels": [
"文本",
"图像",
"工具使用"
]
},
"custom_headers": {
"description": "自定义添加请求头",
"hint": "此处添加的键值对将被合并到 OpenAI SDK 的 default_headers 中,用于自定义 HTTP 请求头。值必须为字符串。"
},
"custom_extra_body": {
"description": "自定义请求体参数",
"hint": "用于在请求时添加额外的参数,如 temperature、top_p、max_tokens 等。",
"template_schema": {
"temperature": {
"description": "温度参数",
"hint": "控制输出的随机性,范围通常为 0-2。值越高越随机。",
"name": "Temperature"
},
"top_p": {
"description": "Top-p 采样",
"hint": "核采样参数,范围通常为 0-1。控制模型考虑的概率质量。",
"name": "Top-p"
},
"max_tokens": {
"description": "最大令牌数",
"hint": "生成的最大令牌数。",
"name": "Max Tokens"
}
}
},
"gpt_weights_path": {
"description": "GPT模型文件路径",
"hint": "即“.ckpt”后缀的文件,请使用绝对路径,路径两端不要带双引号,不填则默认用GPT_SoVITS内置的SoVITS模型(建议直接在GPT_SoVITS中改默认模型)"
},
"sovits_weights_path": {
"description": "SoVITS模型文件路径",
"hint": "即“.pth”后缀的文件,请使用绝对路径,路径两端不要带双引号,不填则默认用GPT_SoVITS内置的SoVITS模型(建议直接在GPT_SoVITS中改默认模型)"
},
"gsv_default_parms": {
"description": "GPT_SoVITS默认参数",
"hint": "参考音频文件路径、参考音频文本必填,其他参数根据个人爱好自行填写",
"gsv_ref_audio_path": {
"description": "参考音频文件路径",
"hint": "必填!请使用绝对路径!路径两端不要带双引号!"
},
"gsv_prompt_text": {
"description": "参考音频文本",
"hint": "必填!请填写参考音频讲述的文本"
},
"gsv_prompt_lang": {
"description": "参考音频文本语言",
"hint": "请填写参考音频讲述的文本的语言,默认为中文"
},
"gsv_aux_ref_audio_paths": {
"description": "辅助参考音频文件路径",
"hint": "辅助参考音频文件,可不填"
},
"gsv_text_lang": {
"description": "文本语言",
"hint": "默认为中文"
},
"gsv_top_k": {
"description": "生成语音的多样性",
"hint": ""
},
"gsv_top_p": {
"description": "核采样的阈值",
"hint": ""
},
"gsv_temperature": {
"description": "生成语音的随机性",
"hint": ""
},
"gsv_text_split_method": {
"description": "切分文本的方法",
"hint": "可选值: `cut0`:不切分 `cut1`:四句一切 `cut2`50字一切 `cut3`:按中文句号切 `cut4`:按英文句号切 `cut5`:按标点符号切"
},
"gsv_batch_size": {
"description": "批处理大小",
"hint": ""
},
"gsv_batch_threshold": {
"description": "批处理阈值",
"hint": ""
},
"gsv_split_bucket": {
"description": "将文本分割成桶以便并行处理",
"hint": ""
},
"gsv_speed_factor": {
"description": "语音播放速度",
"hint": "1为原始语速"
},
"gsv_fragment_interval": {
"description": "语音片段之间的间隔时间",
"hint": ""
},
"gsv_streaming_mode": {
"description": "启用流模式",
"hint": ""
},
"gsv_seed": {
"description": "随机种子",
"hint": "用于结果的可重复性"
},
"gsv_parallel_infer": {
"description": "并行执行推理",
"hint": ""
},
"gsv_repetition_penalty": {
"description": "重复惩罚因子",
"hint": ""
},
"gsv_media_type": {
"description": "输出媒体的类型",
"hint": "建议用wav"
}
},
"embedding_dimensions": {
"description": "嵌入维度",
"hint": "嵌入向量的维度。根据模型不同,可能需要调整,请参考具体模型的文档。此配置项请务必填写正确,否则将导致向量数据库无法正常工作。"
},
"embedding_model": {
"description": "嵌入模型",
"hint": "嵌入模型名称。"
},
"embedding_api_key": {
"description": "API Key"
},
"embedding_api_base": {
"description": "API Base URL"
},
"volcengine_cluster": {
"description": "火山引擎集群",
"hint": "若使用语音复刻大模型,可选volcano_icl或volcano_icl_concurr,默认使用volcano_tts"
},
"volcengine_voice_type": {
"description": "火山引擎音色",
"hint": "输入声音id(Voice_type)"
},
"volcengine_speed_ratio": {
"description": "语速设置",
"hint": "语速设置,范围为 0.2 到 3.0,默认值为 1.0"
},
"volcengine_volume_ratio": {
"description": "音量设置",
"hint": "音量设置,范围为 0.0 到 2.0,默认值为 1.0"
},
"azure_tts_voice": {
"description": "音色设置",
"hint": "API 音色"
},
"azure_tts_style": {
"description": "风格设置",
"hint": "声音特定的讲话风格。 可以表达快乐、同情和平静等情绪。"
},
"azure_tts_role": {
"description": "模仿设置(可选)",
"hint": "讲话角色扮演。 声音可以模仿不同的年龄和性别,但声音名称不会更改。 例如,男性语音可以提高音调和改变语调来模拟女性语音,但语音名称不会更改。 如果角色缺失或不受声音的支持,则会忽略此属性。"
},
"azure_tts_rate": {
"description": "语速设置",
"hint": "指示文本的讲出速率。可在字词或句子层面应用语速。 速率变化应为原始音频的 0.5 到 2 倍。"
},
"azure_tts_volume": {
"description": "语音音量设置",
"hint": "指示语音的音量级别。 可在句子层面应用音量的变化。以从 0.0 到 100.0(从最安静到最大声,例如 75)的数字表示。 默认值为 100.0。"
},
"azure_tts_region": {
"description": "API 地区",
"hint": "Azure_TTS 处理数据所在区域,具体参考 https://learn.microsoft.com/zh-cn/azure/ai-services/speech-service/regions"
},
"azure_tts_subscription_key": {
"description": "服务订阅密钥",
"hint": "Azure_TTS 服务的订阅密钥(注意不是令牌)"
},
"dashscope_tts_voice": {
"description": "音色"
},
"gm_resp_image_modal": {
"description": "启用图片模态",
"hint": "启用后,将支持返回图片内容。需要模型支持,否则会报错。具体支持模型请查看 Google Gemini 官方网站。温馨提示,如果您需要生成图片,请关闭 `启用群员识别` 配置获得更好的效果。"
},
"gm_native_search": {
"description": "启用原生搜索功能",
"hint": "启用后所有函数工具将全部失效,免费次数限制请查阅官方文档"
},
"gm_native_coderunner": {
"description": "启用原生代码执行器",
"hint": "启用后所有函数工具将全部失效"
},
"gm_url_context": {
"description": "启用URL上下文功能",
"hint": "启用后所有函数工具将全部失效"
},
"gm_safety_settings": {
"description": "安全过滤器",
"hint": "设置模型输入的内容安全过滤级别。过滤级别分类为NONE(不屏蔽)、HIGH(高风险时屏蔽)、MEDIUM_AND_ABOVE(中等风险及以上屏蔽)、LOW_AND_ABOVE(低风险及以上时屏蔽),具体参见Gemini API文档。",
"harassment": {
"description": "骚扰内容",
"hint": "负面或有害评论"
},
"hate_speech": {
"description": "仇恨言论",
"hint": "粗鲁、无礼或亵渎性质内容"
},
"sexually_explicit": {
"description": "露骨色情内容",
"hint": "包含性行为或其他淫秽内容的引用"
},
"dangerous_content": {
"description": "危险内容",
"hint": "宣扬、助长或鼓励有害行为的信息"
}
},
"gm_thinking_config": {
"description": "思考配置",
"budget": {
"description": "思考预算",
"hint": "用于指定模型推理时使用的思考 token 数量上限。参见: https://ai.google.dev/gemini-api/docs/thinking#set-budget"
},
"level": {
"description": "思考级别",
"hint": "推荐用于 Gemini 3 及以上模型,可控制推理行为。参见: https://ai.google.dev/gemini-api/docs/thinking#thinking-levels"
}
},
"anth_thinking_config": {
"description": "思考配置",
"budget": {
"description": "思考预算",
"hint": "Anthropic thinking.budget_tokens 参数。必须 >= 1024。参见: https://platform.claude.com/docs/en/build-with-claude/extended-thinking"
}
},
"minimax-group-id": {
"description": "用户组",
"hint": "于账户管理->基本信息中可见"
},
"minimax-langboost": {
"description": "指定语言/方言",
"hint": "增强对指定的小语种和方言的识别能力,设置后可以提升在指定小语种/方言场景下的语音表现"
},
"minimax-voice-speed": {
"description": "语速",
"hint": "生成声音的语速, 取值[0.5, 2], 默认为1.0, 取值越大,语速越快"
},
"minimax-voice-vol": {
"description": "音量",
"hint": "生成声音的音量, 取值(0, 10], 默认为1.0, 取值越大,音量越高"
},
"minimax-voice-pitch": {
"description": "语调",
"hint": "生成声音的语调, 取值[-12, 12], 默认为0"
},
"minimax-is-timber-weight": {
"description": "启用混合音色",
"hint": "启用混合音色, 支持以自定义权重混合最多四种音色, 启用后自动忽略单一音色设置"
},
"minimax-timber-weight": {
"description": "混合音色",
"hint": "混合音色及其权重, 最多支持四种音色, 权重为整数, 取值[1, 100]. 可在官网API语音调试台预览代码获得预设以及编写模板, 需要严格按照json字符串格式编写, 可以查看控制台判断是否解析成功. 具体结构可参照默认值以及官网代码预览."
},
"minimax-voice-id": {
"description": "单一音色",
"hint": "单一音色编号, 详见官网文档"
},
"minimax-voice-emotion": {
"description": "情绪",
"hint": "控制合成语音的情绪。当为 auto 时,将根据文本内容自动选择情绪。"
},
"minimax-voice-latex": {
"description": "支持朗读latex公式",
"hint": "朗读latex公式, 但是需要确保输入文本按官网要求格式化"
},
"minimax-voice-english-normalization": {
"description": "支持英语文本规范化",
"hint": "可提升数字阅读场景的性能,但会略微增加延迟"
},
"rag_options": {
"description": "RAG 选项",
"hint": "检索知识库设置, 非必填。仅 Agent 应用类型支持(智能体应用, 包括 RAG 应用)。阿里云百炼应用开启此功能后将无法多轮对话。",
"pipeline_ids": {
"description": "知识库 ID 列表",
"hint": "对指定知识库内所有文档进行检索, 前往 https://bailian.console.aliyun.com/ 数据应用->知识索引创建和获取 ID。"
},
"file_ids": {
"description": "非结构化文档 ID, 传入该参数将对指定非结构化文档进行检索。",
"hint": "对指定非结构化文档进行检索。前往 https://bailian.console.aliyun.com/ 数据管理创建和获取 ID。"
},
"output_reference": {
"description": "是否输出知识库/文档的引用",
"hint": "在每次回答尾部加上引用源。默认为 False。"
}
},
"sensevoice_hint": {
"description": "部署SenseVoice",
"hint": "启用前请 pip 安装 funasr、funasr_onnx、torchaudio、torch、modelscope、jieba 库(默认使用CPU,大约下载 1 GB),并且安装 ffmpeg。否则将无法正常转文字。"
},
"is_emotion": {
"description": "情绪识别",
"hint": "是否开启情绪识别。happysadangryneutralfearfuldisgustedsurprisedunknown"
},
"stt_model": {
"description": "模型名称",
"hint": "modelscope 上的模型名称。默认:iic/SenseVoiceSmall。"
},
"variables": {
"description": "工作流固定输入变量",
"hint": "可选。工作流固定输入变量,将会作为工作流的输入。也可以在对话时使用 /set 指令动态设置变量。如果变量名冲突,优先使用动态设置的变量。"
},
"dashscope_app_type": {
"description": "应用类型",
"hint": "百炼应用的应用类型。"
},
"timeout": {
"description": "超时时间",
"hint": "超时时间,单位为秒。"
},
"openai-tts-voice": {
"description": "voice",
"hint": "OpenAI TTS 的声音。OpenAI 默认支持:'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'"
},
"fishaudio-tts-character": {
"description": "character",
"hint": "fishaudio TTS 的角色。默认为可莉。更多角色请访问:https://fish.audio/zh-CN/discovery"
},
"fishaudio-tts-reference-id": {
"description": "reference_id",
"hint": "fishaudio TTS 的参考模型ID(可选)。如果填入此字段,将直接使用模型ID而不通过角色名称查询。例如:626bb6d3f3364c9cbc3aa6a67300a664。更多模型请访问:https://fish.audio/zh-CN/discovery,进入模型详情界面后可复制模型ID"
},
"whisper_hint": {
"description": "本地部署 Whisper 模型须知",
"hint": "启用前请 pip 安装 openai-whisper 库(N卡用户大约下载 2GB,主要是 torch 和 cudaCPU 用户大约下载 1 GB),并且安装 ffmpeg。否则将无法正常转文字。"
},
"id": {
"description": "ID"
},
"type": {
"description": "模型提供商种类"
},
"provider_type": {
"description": "模型提供商能力种类"
},
"enable": {
"description": "启用"
},
"key": {
"description": "API Key"
},
"api_base": {
"description": "API Base URL"
},
"model": {
"description": "模型 ID",
"hint": "模型名称,如 gpt-4o-mini, deepseek-chat。"
},
"max_context_tokens": {
"description": "模型上下文窗口大小",
"hint": "模型最大上下文 Token 大小。如果为 0,则会自动从模型元数据填充(如有),也可手动修改。"
},
"dify_api_key": {
"description": "API Key",
"hint": "Dify API Key。此项必填。"
},
"dify_api_base": {
"description": "API Base URL",
"hint": "Dify API Base URL。默认为 https://api.dify.ai/v1"
},
"dify_api_type": {
"description": "Dify 应用类型",
"hint": "Dify API 类型。根据 Dify 官网,目前支持 chat, chatflow, agent, workflow 三种应用类型。"
},
"dify_workflow_output_key": {
"description": "Dify Workflow 输出变量名",
"hint": "Dify Workflow 输出变量名。当应用类型为 workflow 时才使用。默认为 astrbot_wf_output。"
},
"dify_query_input_key": {
"description": "Prompt 输入变量名",
"hint": "发送的消息文本内容对应的输入变量名。默认为 astrbot_text_query。"
},
"coze_api_key": {
"description": "Coze API Key",
"hint": "Coze API 密钥,用于访问 Coze 服务。"
},
"bot_id": {
"description": "Bot ID",
"hint": "Coze 机器人的 ID,在 Coze 平台上创建机器人后获得。"
},
"coze_api_base": {
"description": "API Base URL",
"hint": "Coze API 的基础 URL 地址,默认为 https://api.coze.cn"
},
"auto_save_history": {
"description": "由 Coze 管理对话记录",
"hint": "启用后,将由 Coze 进行对话历史记录管理, 此时 AstrBot 本地保存的上下文不会生效(仅供浏览), 对 AstrBot 的上下文进行的操作也不会生效。如果为禁用, 则使用 AstrBot 管理上下文。"
}
}
},
"help": {
"documentation": "官方文档",
"support": "加群询问",
@@ -45,12 +45,67 @@
},
"invalidPlatformId": "平台 ID 不能包含 ':' 或 '!'。"
},
"createDialog": {
"step1Title": "选择消息平台类别",
"step1Hint": "想把机器人接入到哪里?如 QQ、企业微信、飞书、Discord、Telegram 等。",
"platformTypeLabel": "消息平台类别",
"configFileTitle": "配置文件",
"optional": "可选",
"configHint": "想如何配置机器人?配置文件包含了聊天模型、人格、知识库、插件范围等丰富的机器人配置项。",
"configDefaultHint": "默认使用默认配置文件 “default”。您也可以稍后配置。",
"useExistingConfig": "使用现有配置文件",
"selectConfigLabel": "选择配置文件",
"createNewConfig": "创建新配置文件",
"newConfigNameLabel": "新配置文件名称",
"newConfigTitle": "使用新的配置文件",
"newConfigLoadFailed": "无法加载默认配置模板",
"addRouteRule": "添加路由规则",
"viewMode": "查看",
"editMode": "编辑",
"noRouteRules": "该平台暂无路由规则,将使用默认配置文件",
"sessionIdPlaceholder": "会话ID或*",
"allSessions": "全部会话",
"configMissing": "配置文件不存在",
"routeHint": "*消息下发时,根据会话来源按顺序从上到下匹配首个符合条件的配置文件。使用 * 表示匹配所有。使用 /sid 指令获取会话 ID。全部不匹配时将使用默认配置文件。",
"warningContinue": "无视警告并继续创建",
"warningEditAgain": "重新修改",
"configDrawerTitle": "配置文件管理",
"configDrawerIdLabel": "ID",
"configTableHeaders": {
"configId": "与此实例关联的配置文件 ID",
"scope": "在此实例下的应用范围"
},
"routeTableHeaders": {
"source": "消息会话来源(消息类型:会话 ID)",
"config": "使用配置文件",
"actions": "操作"
},
"messageTypeOptions": {
"all": "全部消息",
"group": "群组消息(GroupMessage)",
"friend": "私聊消息(FriendMessage)"
},
"messageTypeLabels": {
"all": "全部消息",
"group": "群组消息",
"friend": "私聊消息"
}
},
"messages": {
"updateSuccess": "更新成功!",
"addSuccess": "添加成功!",
"deleteSuccess": "删除成功!",
"statusUpdateSuccess": "状态更新成功!",
"deleteConfirm": "确定要删除平台适配器"
"deleteConfirm": "确定要删除平台适配器",
"configNotFoundOpenConfig": "目标配置文件不存在,已打开配置页面以便检查。",
"updateMissingPlatformId": "更新失败,缺少平台 ID。",
"platformUpdateFailed": "平台更新失败。",
"addSuccessWithConfig": "平台添加成功,配置文件已更新",
"configIdMissing": "无法获取配置文件ID。",
"routingUpdateFailed": "更新路由表失败: {message}",
"createConfigFailed": "创建新配置文件失败: {message}",
"platformIdMissing": "无法获取平台 ID。",
"routingSaveFailed": "保存路由表失败: {message}"
},
"status": {
"enabled": "已启用",
@@ -92,6 +92,7 @@
},
"providerSources": {
"title": "提供商源",
"add": "新增",
"empty": "暂无提供商源",
"selectHint": "请选择一个提供商源",
"save": "保存配置",
@@ -142,4 +143,4 @@
"modelId": "模型 ID"
}
}
}
}
+2
View File
@@ -14,6 +14,8 @@ export function getPlatformIcon(name) {
return new URL('@/assets/images/platform_logos/qq.png', import.meta.url).href
} else if (name === 'wecom' || name === 'wecom_ai_bot') {
return new URL('@/assets/images/platform_logos/wecom.png', import.meta.url).href
} else if (name === 'weixin_official_account') {
return new URL('@/assets/images/platform_logos/wechat.png', import.meta.url).href
} else if (name === 'lark') {
return new URL('@/assets/images/platform_logos/lark.png', import.meta.url).href
} else if (name === 'dingtalk') {