Compare commits

..

2 Commits

20 changed files with 77 additions and 330 deletions
+1 -1
View File
@@ -1 +1 @@
__version__ = "4.17.4"
__version__ = "4.17.3"
+1 -1
View File
@@ -90,7 +90,7 @@ class LocalPythonTool(FunctionTool):
if context.context.event.role != "admin":
return (
"error: Permission denied. Local Python execution is only allowed for admin users. "
"Tell user to set admins in `AstrBot WebUI -> Config -> General Config` by adding their user ID to the admins list if they need this feature."
"Tell user to set admins in AstrBot WebUI by adding their user ID to the admins list if they need this feature."
f"User's ID is: {context.context.event.get_sender_id()}. User's ID can be found by using /sid command."
)
sb = get_local_booter()
+1 -1
View File
@@ -49,7 +49,7 @@ class ExecuteShellTool(FunctionTool):
if context.context.event.role != "admin":
return (
"error: Permission denied. Local shell execution is only allowed for admin users. "
"Tell user to set admins in `AstrBot WebUI -> Config -> General Config` by adding their user ID to the admins list if they need this feature."
"Tell user to set admins in AstrBot WebUI by adding their user ID to the admins list if they need this feature."
f"User's ID is: {context.context.event.get_sender_id()}. User's ID can be found by using /sid command."
)
+1 -1
View File
@@ -5,7 +5,7 @@ from typing import Any, TypedDict
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
VERSION = "4.17.4"
VERSION = "4.17.3"
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
WEBHOOK_SUPPORTED_PLATFORMS = [
-32
View File
@@ -1,32 +0,0 @@
## What's Changed
### 新增
- 新增 NVIDIA Provider 模板,便于快速接入 NVIDIA 模型服务 ([#5157](https://github.com/AstrBotDevs/AstrBot/issues/5157))。
- 支持在 WebUI 搜索配置
### 修复
- 修复 CronJob 页面操作列按钮重叠问题,提升任务管理可用性 ([#5163](https://github.com/AstrBotDevs/AstrBot/issues/5163))。
### 优化
- 优化 Python / Shell 本地执行工具的权限拒绝提示信息引导,提升排障可读性。
- Provider 来源面板样式升级,新增菜单交互并完善移动端适配。
- PersonaForm 组件增强响应式布局与样式细节,改进不同屏幕下的编辑体验 ([#5162](https://github.com/AstrBotDevs/AstrBot/issues/5162))。
- 配置页面新增未保存变更提示,减少误操作导致的配置丢失。
- 配置相关组件新增搜索能力并同步更新界面交互,提升配置项定位效率 ([#5168](https://github.com/AstrBotDevs/AstrBot/issues/5168))。
## What's Changed (EN)
### New Features
- Added an NVIDIA provider template for faster integration with NVIDIA model services ([#5157](https://github.com/AstrBotDevs/AstrBot/issues/5157)).
- Added an announcement section to the Welcome page, with localized announcement title support.
- Added an FAQ link to the vertical sidebar and updated navigation for localization.
### Fixes
- Fixed overlapping action buttons in the CronJob page action column to improve task management usability ([#5163](https://github.com/AstrBotDevs/AstrBot/issues/5163)).
- Improved permission-denied messages for local execution in Python and shell tools for better troubleshooting clarity.
### Improvements
- Enhanced the provider sources panel with a refined menu style and better mobile support.
- Improved PersonaForm with responsive layout and styling updates for better editing experience across screen sizes ([#5162](https://github.com/AstrBotDevs/AstrBot/issues/5162)).
- Added an unsaved-changes notice on the configuration page to reduce accidental config loss.
- Added search functionality to configuration components and updated related UI interactions for faster settings discovery ([#5168](https://github.com/AstrBotDevs/AstrBot/issues/5168)).
@@ -2,22 +2,18 @@
<div :class="$vuetify.display.mobile ? '' : 'd-flex'">
<v-tabs v-model="tab" :direction="$vuetify.display.mobile ? 'horizontal' : 'vertical'"
:align-tabs="$vuetify.display.mobile ? 'left' : 'start'" color="deep-purple-accent-4" class="config-tabs">
<v-tab v-for="section in visibleSections" :key="section.key" :value="section.key"
<v-tab v-for="(val, key, index) in metadata" :key="index" :value="index"
style="font-weight: 1000; font-size: 15px">
{{ tm(section.value['name']) }}
{{ tm(metadata[key]['name']) }}
</v-tab>
</v-tabs>
<v-tabs-window v-model="tab" class="config-tabs-window" :style="readonly ? 'pointer-events: none; opacity: 0.6;' : ''">
<v-tabs-window-item v-for="section in visibleSections" :key="section.key" :value="section.key">
<v-tabs-window-item v-for="(val, key, index) in metadata" v-show="index == tab" :key="index">
<v-container fluid>
<div v-for="(val2, key2, index2) in section.value['metadata']" :key="key2">
<div v-for="(val2, key2, index2) in metadata[key]['metadata']" :key="key2">
<!-- Support both traditional and JSON selector metadata -->
<AstrBotConfigV4
:metadata="{ [key2]: section.value['metadata'][key2] }"
:iterable="config_data"
:metadataKey="key2"
:search-keyword="searchKeyword"
>
<AstrBotConfigV4 :metadata="{ [key2]: metadata[key]['metadata'][key2] }" :iterable="config_data"
:metadataKey="key2">
</AstrBotConfigV4>
</div>
</v-container>
@@ -35,11 +31,6 @@
</v-tabs-window>
</div>
<v-container v-if="visibleSections.length === 0" fluid class="px-0">
<v-alert type="info" variant="tonal">
{{ tm('search.noResult') }}
</v-alert>
</v-container>
</template>
<script>
@@ -65,10 +56,6 @@ export default {
readonly: {
type: Boolean,
default: false
},
searchKeyword: {
type: String,
default: ''
}
},
setup() {
@@ -89,63 +76,11 @@ export default {
},
data() {
return {
tab: null, // 当前激活的配置标签页 key
tab: 0, // 用于切换配置标签页
}
},
computed: {
normalizedSearchKeyword() {
return String(this.searchKeyword || '').trim().toLowerCase();
},
visibleSections() {
if (!this.metadata || typeof this.metadata !== 'object') {
return [];
}
const allSections = Object.entries(this.metadata).map(([key, value]) => ({ key, value }));
if (!this.normalizedSearchKeyword) {
return allSections;
}
return allSections.filter((section) => this.sectionHasSearchMatch(section.value));
}
},
watch: {
visibleSections(newSections) {
const sectionKeys = newSections.map((section) => section.key);
if (!sectionKeys.includes(this.tab)) {
this.tab = sectionKeys[0] ?? null;
}
}
},
mounted() {
const sectionKeys = this.visibleSections.map((section) => section.key);
this.tab = sectionKeys[0] ?? null;
},
methods: {
sectionHasSearchMatch(section) {
const keyword = this.normalizedSearchKeyword;
if (!keyword) {
return true;
}
const sectionMetadata = section?.metadata || {};
return Object.values(sectionMetadata).some((metaItem) => this.metaObjectHasSearchMatch(metaItem, keyword));
},
metaObjectHasSearchMatch(metaObject, keyword) {
if (!metaObject || typeof metaObject !== 'object') {
return false;
}
const target = [
this.tm(metaObject.description || ''),
this.tm(metaObject.hint || ''),
...Object.entries(metaObject.items || {}).flatMap(([itemKey, itemMeta]) => ([
itemKey,
this.tm(itemMeta?.description || ''),
this.tm(itemMeta?.hint || '')
]))
]
.join(' ')
.toLowerCase();
return target.includes(keyword);
}
// 如果需要添加其他方法,可以在这里添加
}
}
</script>
@@ -177,4 +112,4 @@ export default {
margin-top: 16px;
}
}
</style>
</style>
@@ -14,8 +14,13 @@
</div>
<!-- 选择对话框 -->
<v-dialog v-model="dialog" max-width="1000px" min-width="800px">
<v-card class="selector-dialog-card">
<v-dialog
v-model="dialog"
:max-width="$vuetify.display.smAndDown ? undefined : '1000px'"
:min-width="$vuetify.display.smAndDown ? undefined : '800px'"
scrollable
>
<v-card class="selector-dialog-card" :class="{ 'selector-dialog-card-mobile': $vuetify.display.smAndDown }">
<v-card-title class="dialog-title d-flex align-center py-4 px-5">
<v-icon class="mr-3" color="primary">mdi-account-circle</v-icon>
<span>{{ labels.dialogTitle || '选择项目' }}</span>
@@ -23,7 +28,7 @@
<v-divider />
<v-card-text class="pa-0" style="height: 600px; max-height: 80vh; overflow: hidden;">
<v-card-text class="selector-dialog-content pa-0">
<div class="selector-layout">
<!-- 左侧文件夹树 -->
<div class="folder-sidebar">
@@ -146,7 +151,7 @@
</div>
</v-card-text>
<v-card-actions class="pa-4">
<v-card-actions class="selector-dialog-actions pa-4">
<v-btn v-if="showCreateButton" variant="text" color="primary" prepend-icon="mdi-plus"
@click="$emit('create')">
{{ labels.createButton || '新建' }}
@@ -406,6 +411,12 @@ export default defineComponent({
overflow: hidden;
}
.selector-dialog-content {
height: 600px;
max-height: 80vh;
overflow: hidden;
}
.dialog-title {
font-size: 1.25rem;
font-weight: 500;
@@ -518,21 +529,44 @@ export default defineComponent({
}
@media (max-width: 600px) {
.selector-dialog-card-mobile {
border-radius: 0;
}
.selector-dialog-content {
height: calc(100vh - 132px);
max-height: none;
}
.dialog-title {
font-size: 1.05rem;
padding: 12px 16px !important;
}
.selector-dialog-actions {
padding: 12px 16px !important;
gap: 8px;
}
.selector-dialog-actions .v-btn {
min-width: 0;
}
.selector-layout {
flex-direction: column;
height: auto;
max-height: 500px;
height: 100%;
max-height: none;
}
.folder-sidebar {
width: 100%;
border-right: none;
border-bottom: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
max-height: 150px;
max-height: 35vh;
}
.items-list {
max-height: 300px;
max-height: none;
}
}
</style>
@@ -19,10 +19,6 @@ const props = defineProps({
metadataKey: {
type: String,
required: true
},
searchKeyword: {
type: String,
default: ''
}
})
@@ -128,27 +124,16 @@ function saveEditedContent() {
}
function shouldShowItem(itemMeta, itemKey) {
if (itemMeta?.condition) {
for (const [conditionKey, expectedValue] of Object.entries(itemMeta.condition)) {
const actualValue = getValueBySelector(props.iterable, conditionKey)
if (actualValue !== expectedValue) {
return false
}
}
}
const keyword = String(props.searchKeyword || '').trim().toLowerCase()
if (!keyword) {
if (!itemMeta?.condition) {
return true
}
const searchableText = [
itemKey,
translateIfKey(itemMeta?.description || ''),
translateIfKey(itemMeta?.hint || '')
].join(' ').toLowerCase()
return searchableText.includes(keyword)
for (const [conditionKey, expectedValue] of Object.entries(itemMeta.condition)) {
const actualValue = getValueBySelector(props.iterable, conditionKey)
if (actualValue !== expectedValue) {
return false
}
}
return true
}
// 检查最外层的 object 是否应该显示
@@ -163,10 +148,7 @@ function shouldShowSection() {
return false
}
}
const sectionItems = props.metadata?.[props.metadataKey]?.items || {}
const hasVisibleItems = Object.entries(sectionItems).some(([itemKey, itemMeta]) => shouldShowItem(itemMeta, itemKey))
return hasVisibleItems
return true
}
function hasVisibleItemsAfter(items, currentIndex) {
@@ -454,13 +436,9 @@ function getSpecialSubtype(value) {
}
.property-info,
.type-indicator {
padding: 4px 8px;
}
.type-indicator,
.config-input {
padding-left: 24px;
padding-right: 24px;
padding: 4px;
}
}
</style>
@@ -28,7 +28,6 @@
"settings": "Settings",
"changelog": "Changelog",
"documentation": "Documentation",
"faq": "FAQ",
"github": "GitHub",
"drag": "Drag",
"groups": {
@@ -28,7 +28,6 @@
"messages": {
"configApplied": "Configuration successfully applied. To save, you need to click the save button in the bottom right corner.",
"configApplyError": "Configuration not applied, JSON format error.",
"unsavedChangesNotice": "You have unsaved configuration changes. Click the save button in the bottom-right corner to apply them.",
"saveSuccess": "Configuration saved successfully",
"saveError": "Failed to save configuration",
"loadError": "Failed to load configuration",
@@ -69,10 +68,6 @@
"normalConfig": "Basic",
"systemConfig": "System"
},
"search": {
"placeholder": "Search config items (key/description/hint)",
"noResult": "No matching config items found"
},
"configManagement": {
"title": "Configuration Management",
"description": "AstrBot supports separate configuration files for different bots. The `default` configuration is used by default.",
@@ -6,9 +6,6 @@
"newYear": "Happy New Year!"
},
"subtitle": "You can complete the basic onboarding first. Platform and chat provider setup can both be skipped.",
"announcement": {
"title": "Announcement"
},
"onboard": {
"title": "Quick Onboarding",
"subtitle": "Complete initialization directly on the welcome page.",
@@ -28,7 +28,6 @@
"settings": "设置",
"changelog": "更新日志",
"documentation": "官方文档",
"faq": "FAQ",
"github": "GitHub",
"drag": "拖拽",
"groups": {
@@ -28,7 +28,6 @@
"messages": {
"configApplied": "配置成功应用。如要保存,需再点击右下角保存按钮。",
"configApplyError": "配置未应用,Json 格式错误。",
"unsavedChangesNotice": "当前配置有未保存修改。请点击右下角保存按钮以生效。",
"saveSuccess": "配置保存成功",
"saveError": "配置保存失败",
"loadError": "配置加载失败",
@@ -69,10 +68,6 @@
"normalConfig": "普通",
"systemConfig": "系统"
},
"search": {
"placeholder": "搜索配置项(字段名/描述/提示)",
"noResult": "未找到匹配的配置项"
},
"configManagement": {
"title": "配置文件管理",
"description": "AstrBot 支持针对不同机器人分别设置配置文件。默认会使用 `default` 配置。",
@@ -6,9 +6,6 @@
"newYear": "新年快乐!"
},
"subtitle": "可以先完成基础引导,平台和对话提供商都支持稍后再配置。",
"announcement": {
"title": "公告"
},
"onboard": {
"title": "快速引导",
"subtitle": "欢迎页可直接完成初始化。",
@@ -7,7 +7,7 @@ import NavItem from './NavItem.vue';
import { applySidebarCustomization } from '@/utils/sidebarCustomization';
import ChangelogDialog from '@/components/shared/ChangelogDialog.vue';
const { t, locale } = useI18n();
const { t } = useI18n();
const customizer = useCustomizerStore();
const sidebarMenu = shallowRef(sidebarItems);
@@ -109,13 +109,6 @@ function openIframeLink(url) {
}
}
function openFaqLink() {
const faqUrl = locale.value === 'en-US'
? 'https://docs.astrbot.app/en/faq.html'
: 'https://docs.astrbot.app/faq.html';
openIframeLink(faqUrl);
}
let offsetX = 0;
let offsetY = 0;
let isDragging = false;
@@ -271,10 +264,6 @@ function openChangelogDialog() {
@click="toggleIframe">
{{ t('core.navigation.documentation') }}
</v-btn>
<v-btn class="sidebar-footer-btn" size="small" variant="text" prepend-icon="mdi-frequently-asked-questions"
@click="openFaqLink">
{{ t('core.navigation.faq') }}
</v-btn>
<v-btn class="sidebar-footer-btn" size="small" variant="text" prepend-icon="mdi-github"
@click="openIframeLink('https://github.com/AstrBotDevs/AstrBot')">
{{ t('core.navigation.github') }}
+3 -74
View File
@@ -4,39 +4,17 @@
<div v-if="selectedConfigID || isSystemConfig" class="mt-4 config-panel"
style="display: flex; flex-direction: column; align-items: start;">
<div class="config-toolbar d-flex flex-row pr-4"
<div class="d-flex flex-row pr-4"
style="margin-bottom: 16px; align-items: center; gap: 12px; width: 100%; justify-content: space-between;">
<div class="config-toolbar-controls d-flex flex-row align-center" style="gap: 12px;">
<v-select class="config-select" style="min-width: 130px;" v-model="selectedConfigID" :items="configSelectItems" item-title="name" :disabled="initialConfigId !== null"
<div class="d-flex flex-row align-center" style="gap: 12px;">
<v-select style="min-width: 130px;" v-model="selectedConfigID" :items="configSelectItems" item-title="name" :disabled="initialConfigId !== null"
v-if="!isSystemConfig" item-value="id" :label="tm('configSelection.selectConfig')" hide-details density="compact" rounded="md"
variant="outlined" @update:model-value="onConfigSelect">
</v-select>
<v-text-field
class="config-search-input"
v-model="configSearchKeyword"
prepend-inner-icon="mdi-magnify"
:label="tm('search.placeholder')"
hide-details
density="compact"
rounded="md"
variant="outlined"
style="min-width: 280px;"
/>
<!-- <a style="color: inherit;" href="https://blog.astrbot.app/posts/what-is-changed-in-4.0.0/#%E5%A4%9A%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" target="_blank"><v-btn icon="mdi-help-circle" size="small" variant="plain"></v-btn></a> -->
</div>
</div>
<v-slide-y-transition>
<div v-if="fetched && hasUnsavedChanges" class="unsaved-changes-banner-wrap">
<v-banner
icon="$warning"
lines="one"
class="unsaved-changes-banner my-4"
>
{{ tm('messages.unsavedChangesNotice') }}
</v-banner>
</div>
</v-slide-y-transition>
<!-- <v-progress-linear v-if="!fetched" indeterminate color="primary"></v-progress-linear> -->
<v-slide-y-transition mode="out-in">
@@ -45,7 +23,6 @@
<AstrBotCoreConfigWrapper
:metadata="metadata"
:config_data="config_data"
:search-keyword="configSearchKeyword"
/>
<v-tooltip :text="tm('actions.save')" location="left">
@@ -258,12 +235,6 @@ export default {
});
return items;
},
hasUnsavedChanges() {
if (!this.fetched) {
return false;
}
return this.getConfigSnapshot(this.config_data) !== this.lastSavedConfigSnapshot;
}
},
watch: {
config_data_str(val) {
@@ -298,11 +269,9 @@ export default {
save_message: "",
save_message_success: "",
configContentKey: 0,
lastSavedConfigSnapshot: '',
// 配置类型切换
configType: 'normal', // 'normal' 或 'system'
configSearchKeyword: '',
// 系统配置开关
isSystemConfig: false,
@@ -414,7 +383,6 @@ export default {
params: params
}).then((res) => {
this.config_data = res.data.data.config;
this.lastSavedConfigSnapshot = this.getConfigSnapshot(this.config_data);
this.fetched = true
this.metadata = res.data.data.metadata;
this.configContentKey += 1;
@@ -439,7 +407,6 @@ export default {
axios.post('/api/config/astrbot/update', postData).then((res) => {
if (res.data.status === "ok") {
this.lastSavedConfigSnapshot = this.getConfigSnapshot(this.config_data);
this.save_message = res.data.message || this.messages.saveSuccess;
this.save_message_snack = true;
this.save_message_success = "success";
@@ -634,9 +601,6 @@ export default {
closeTestChat() {
this.testChatDrawer = false;
this.testConfigId = null;
},
getConfigSnapshot(config) {
return JSON.stringify(config ?? {});
}
},
}
@@ -648,26 +612,6 @@ export default {
text-transform: none !important;
}
.unsaved-changes-banner {
border-radius: 8px;
}
.v-theme--light .unsaved-changes-banner {
background-color: #f1f4f9 !important;
}
.v-theme--dark .unsaved-changes-banner {
background-color: #2d2d2d !important;
}
.unsaved-changes-banner-wrap {
position: sticky;
top: calc(var(--v-layout-top, 64px));
z-index: 20;
width: 100%;
margin-bottom: 6px;
}
/* 按钮切换样式优化 */
.v-btn-toggle .v-btn {
transition: all 0.3s ease !important;
@@ -715,21 +659,6 @@ export default {
.config-panel {
width: 100%;
}
.config-toolbar {
padding-right: 0 !important;
}
.config-toolbar-controls {
width: 100%;
flex-wrap: wrap;
}
.config-select,
.config-search-input {
width: 100%;
min-width: 0 !important;
}
}
/* 测试聊天抽屉样式 */
+4 -5
View File
@@ -55,12 +55,11 @@
<template #item.last_run_at="{ item }">{{ formatTime(item.last_run_at) }}</template>
<template #item.note="{ item }">{{ item.note || tm('table.notAvailable') }}</template>
<template #item.actions="{ item }">
<div class="d-flex align-center flex-nowrap" style="gap: 12px; min-width: 140px;">
<div class="d-flex" style="gap: 8px;">
<v-switch v-model="item.enabled" inset density="compact" hide-details color="primary"
class="mt-0" @change="toggleJob(item)" />
<v-btn size="small" variant="text" color="error" @click="deleteJob(item)">
{{ tm('actions.delete') }}
</v-btn>
@change="toggleJob(item)" />
<v-btn size="small" variant="text" color="primary" @click="deleteJob(item)">{{ tm('actions.delete')
}}</v-btn>
</div>
</template>
</v-data-table>
+1 -68
View File
@@ -116,21 +116,6 @@
</v-card>
</v-col>
</v-row>
<v-row v-if="showAnnouncement" class="px-4 mb-4">
<v-col cols="12">
<v-card class="welcome-card pa-6" elevation="0" border>
<div class="mb-4 text-h3 font-weight-bold">
{{ tm('announcement.title') }}
</div>
<MarkdownRender
:content="welcomeAnnouncement"
:typewriter="false"
class="welcome-announcement-markdown markdown-content"
/>
</v-card>
</v-col>
</v-row>
</v-container>
<AddNewPlatform v-model:show="showAddPlatformDialog" :metadata="platformMetadata" :config_data="platformConfigData"
@@ -144,16 +129,12 @@ import { computed, ref, watch, onMounted } from 'vue';
import axios from 'axios';
import AddNewPlatform from '@/components/platform/AddNewPlatform.vue';
import ProviderConfigDialog from '@/components/chat/ProviderConfigDialog.vue';
import { useI18n, useModuleI18n } from '@/i18n/composables';
import { useModuleI18n } from '@/i18n/composables';
import { useToast } from '@/utils/toast';
import { MarkdownRender } from 'markstream-vue';
import 'markstream-vue/index.css';
import 'highlight.js/styles/github.css';
type StepState = 'pending' | 'completed' | 'skipped';
const { tm } = useModuleI18n('features/welcome');
const { locale } = useI18n();
const { success: showSuccess, error: showError } = useToast();
const showAddPlatformDialog = ref(false);
@@ -167,38 +148,6 @@ const providerCountBeforeOpen = ref(0);
const platformStepState = ref<StepState>('pending');
const providerStepState = ref<StepState>('pending');
const welcomeAnnouncementRaw = ref<unknown>(null);
function resolveWelcomeAnnouncement(raw: unknown, currentLocale: string) {
if (typeof raw === 'string') {
return raw.trim();
}
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
return '';
}
const localeMap = raw as Record<string, unknown>;
const normalized = currentLocale.replace('-', '_');
const preferredKeys =
normalized.startsWith('zh')
? [normalized, 'zh_CN', 'zh-CN', 'zh', 'en_US', 'en-US', 'en']
: [normalized, 'en_US', 'en-US', 'en', 'zh_CN', 'zh-CN', 'zh'];
for (const key of preferredKeys) {
const value = localeMap[key];
if (typeof value === 'string' && value.trim().length > 0) {
return value.trim();
}
}
return '';
}
const welcomeAnnouncement = computed(() =>
resolveWelcomeAnnouncement(welcomeAnnouncementRaw.value, locale.value)
);
const showAnnouncement = computed(() => welcomeAnnouncement.value.length > 0);
const springFestivalDates: Record<number, string> = {
2025: '01-29',
@@ -336,19 +285,7 @@ async function syncDefaultConfigProviderIfNeeded() {
showSuccess(tm('onboard.providerDefaultUpdated', { id: targetProviderId }));
}
async function loadWelcomeAnnouncement() {
try {
const res = await axios.get('https://cloud.astrbot.app/api/v1/announcement');
welcomeAnnouncementRaw.value = res?.data?.data?.notice?.welcome_page ?? null;
} catch (e) {
welcomeAnnouncementRaw.value = null;
console.error(e);
}
}
onMounted(async () => {
await loadWelcomeAnnouncement();
try {
await loadPlatformConfigBase();
if ((platformConfigData.value.platform || []).length > 0) {
@@ -426,8 +363,4 @@ watch(showProviderDialog, async (visible, wasVisible) => {
.welcome-card {
border-radius: 16px;
}
.welcome-announcement-markdown {
line-height: 1.7;
}
</style>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "astrbot-desktop",
"version": "4.17.4",
"version": "4.17.3",
"description": "AstrBot desktop wrapper",
"private": true,
"main": "main.js",
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "AstrBot"
version = "4.17.4"
version = "4.17.3"
description = "Easy-to-use multi-platform LLM chatbot and development framework"
readme = "README.md"
requires-python = ">=3.12"