Skip to content

Conversation

@Sjshi763
Copy link

@Sjshi763 Sjshi763 commented Jan 17, 2026

添加了 人格设定支持导出/导入 功能 #4409

Modifications / 改动点

国际化的键值

dashboard/src/i18n/locales/en-US/features/persona.json
dashboard/src/i18n/locales/zh-CN/features/persona.json

导入导出的规则

dashboard/src/views/PersonaPage.vue

点击导出自动下载后端发来的人格json
点击导入,可以选择人格json 判断是否可以导入,最后导入

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

2026-01-17.132918.mp4

Checklist / 检查清单

  • [] 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

在仪表板的人物管理页面中添加人物的 JSON 导入和导出功能。

新功能:

  • 允许用户从人物操作菜单中,将单个人物导出为已清理的 JSON 文件。
  • 允许用户在人物页面从 JSON 文件导入人物定义,并在导入时进行校验和人物 ID 重复检查。

增强内容:

  • 更新人物页面的 UI,加入更加醒目的“导入”和“创建”按钮,并改进页面布局。
  • 扩展与人物相关的国际化字符串,涵盖新的导入、导出以及状态消息。
Original summary in English

Summary by Sourcery

Add JSON import and export capabilities for personas in the dashboard persona management page.

New Features:

  • Allow users to export an individual persona as a cleaned JSON file from the persona action menu.
  • Allow users to import persona definitions from a JSON file with validation and duplicate ID checks on the persona page.

Enhancements:

  • Update persona page UI to include prominent import and create buttons with improved layout.
  • Extend persona-related internationalization strings to cover new import, export, and status messages.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. feature:persona The bug / feature is about astrbot AI persona system (system prompt) labels Jan 17, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我这边发现了 3 个问题,并且补充了一些整体性的反馈:

  • 新增的导入/导出用户提示文案大多是硬编码的中文字符串;建议把这些文案移动到现有的 i18n persona 语言文件中,而不是在模板里混用 this.tm(...) 和字面量字符串。
  • 新增的 handleImport 逻辑直接调用了 axios.post('/api/persona/create', parsedData);如果该组件或项目中已经有现成的 API 封装层或 persona service,建议复用现有抽象,而不是在这里直接硬编码接口地址。
  • 导入逻辑中还保留了 console.logconsole.error 调用;这些应该删除,或改为使用现有的消息/通知机制,以避免在生产环境产生过多无用日志。
提供给 AI Agents 的提示
Please address the comments from this code review:

## Overall Comments
- The new import/export user-facing messages are mostly hardcoded Chinese strings; consider moving them into the existing i18n persona locale files instead of mixing `this.tm(...)` with literals.
- The new `handleImport` logic calls `axios.post('/api/persona/create', parsedData)` directly; if there is an existing API abstraction or persona service in this component or project, it would be cleaner to reuse that instead of hardcoding the endpoint here.
- There are `console.log` and `console.error` calls left in the import handler; these should be removed or replaced with the existing message/notification mechanism to avoid noisy logs in production.

## Individual Comments

### Comment 1
<location> `dashboard/src/views/PersonaPage.vue:48-51` </location>
<code_context>
                                             {{ tm('buttons.edit') }}
                                         </v-list-item-title>
                                     </v-list-item>
+                                    <v-list-item @click.stop="downloadPersonaJson(persona)">
+                                        <v-list-item-title>
+                                            <v-icon class="mr-2" size="small">mdi-content-copy</v-icon>
+                                            {{ tm('buttons.export') || '导出 JSON' }}
+                                        </v-list-item-title>
+                                    </v-list-item>
</code_context>

<issue_to_address>
**suggestion:** 导出操作目前使用了一个“复制”图标以及部分硬编码的标签,既可能让用户产生误解,也会绕过 i18n。

当前操作会触发导出/下载,因此使用 `mdi-content-copy`(剪贴板图标)可能会误导用户;建议改用 `mdi-download``mdi-export` 这类更符合“下载/导出”语义的图标。另外,硬编码的 `'导出 JSON'` 作为后备文案会绕过 i18n——请将这段文案移入翻译文件中,避免在模板中直接写入特定语言的字符串。

建议实现方式:

```
                                    <v-list-item @click.stop="downloadPersonaJson(persona)">
                                        <v-list-item-title>
                                            <v-icon class="mr-2" size="small">mdi-download</v-icon>
                                            {{ tm('buttons.exportJson') }}
                                        </v-list-item-title>
                                    </v-list-item>

```

1. 在 i18n 资源文件(例如 `en``zh` 等)中添加 `buttons.exportJson` 翻译键,为各语言配置合适的本地化文案,例如 `"Export JSON"` / `"导出 JSON"`2. 如果项目在按钮文案 key 的命名上有其他约定(例如 `buttons.export_json`),请相应调整模板中的 key 以及 i18n 文件中的定义。
</issue_to_address>

### Comment 2
<location> `dashboard/src/views/PersonaPage.vue:306` </location>
<code_context>
+                const url = URL.createObjectURL(blob);
+                const link = document.createElement('a');
+                link.href = url;
+                link.download = `${persona.persona_id}.json`;
+                
+                // 触发下载
</code_context>

<issue_to_address>
**issue:** 直接用 `persona_id` 作为文件名的一部分,可能会在 ID 包含特殊字符时导致下载失败。

如果 `persona_id` 可能包含空格、斜杠或其他非法文件名字符,在某些浏览器/操作系统上,保存文件时可能会失败或被自动修改文件名。建议对用于 `download` 的 ID 做一次“规范化”处理(例如用 `_` 替换掉所有不在 `[a-zA-Z0-9_-]` 范围内的字符),或者回退到一个安全的默认文件名,并可选择限制一个合理的最大长度。
</issue_to_address>

### Comment 3
<location> `dashboard/src/views/PersonaPage.vue:334-343` </location>
<code_context>
+                const parsedData = JSON.parse(text);
</code_context>

<issue_to_address>
**🚨 suggestion (security):** 在未进行字段白名单过滤的情况下,将解析后的原始 JSON 直接发送给 API,可能会引入服务端风险。

当前上传的 JSON 会原样转发到 `/api/persona/create`。即使后端有校验,从安全性角度看,前端最好还是只从 JSON 中按白名单字段构造请求体(例如 `persona_id``system_prompt``begin_dialogs``tools`),丢弃其他字段。这样可以减少恶意构造 JSON 携带意外属性的影响,并让前后端的契约更加清晰、严格。

建议实现方式:

```
                const text = await file.text();
                const parsedData = JSON.parse(text);

                // 只从上传 JSON 中提取允许的字段,避免将未预期的字段直接转发到后端
                const allowedFields = ['persona_id', 'system_prompt', 'begin_dialogs', 'tools'];
                const personaPayload = allowedFields.reduce((acc, key) => {
                    if (Object.prototype.hasOwnProperty.call(parsedData, key)) {
                        acc[key] = parsedData[key];
                    }
                    return acc;
                }, {});

                console.log("Parsed Data (whitelisted):", personaPayload);

                // 验证必需字段(基于白名单后的数据)
                if (!personaPayload.persona_id || !personaPayload.system_prompt) {

```

1. 在该方法后续将数据发送到 `/api/persona/create` 时,请确保使用 `personaPayload` 而不是 `parsedData` 作为请求体(例如 `axios.post('/api/persona/create', personaPayload)`)。
2. 如果有任何依赖 `parsedData` 其他字段的逻辑,需要显式地将这些字段加入 `allowedFields` 白名单,或在前端增加相应的转换逻辑以保持与后端约定一致。
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得这次代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,你的反馈将用于改进后续的代码审查。
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • The new import/export user-facing messages are mostly hardcoded Chinese strings; consider moving them into the existing i18n persona locale files instead of mixing this.tm(...) with literals.
  • The new handleImport logic calls axios.post('/api/persona/create', parsedData) directly; if there is an existing API abstraction or persona service in this component or project, it would be cleaner to reuse that instead of hardcoding the endpoint here.
  • There are console.log and console.error calls left in the import handler; these should be removed or replaced with the existing message/notification mechanism to avoid noisy logs in production.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new import/export user-facing messages are mostly hardcoded Chinese strings; consider moving them into the existing i18n persona locale files instead of mixing `this.tm(...)` with literals.
- The new `handleImport` logic calls `axios.post('/api/persona/create', parsedData)` directly; if there is an existing API abstraction or persona service in this component or project, it would be cleaner to reuse that instead of hardcoding the endpoint here.
- There are `console.log` and `console.error` calls left in the import handler; these should be removed or replaced with the existing message/notification mechanism to avoid noisy logs in production.

## Individual Comments

### Comment 1
<location> `dashboard/src/views/PersonaPage.vue:48-51` </location>
<code_context>
                                             {{ tm('buttons.edit') }}
                                         </v-list-item-title>
                                     </v-list-item>
+                                    <v-list-item @click.stop="downloadPersonaJson(persona)">
+                                        <v-list-item-title>
+                                            <v-icon class="mr-2" size="small">mdi-content-copy</v-icon>
+                                            {{ tm('buttons.export') || '导出 JSON' }}
+                                        </v-list-item-title>
+                                    </v-list-item>
</code_context>

<issue_to_address>
**suggestion:** The export action uses a copy icon and a partially hard-coded label, which may confuse users and bypass i18n.

This action triggers an export/download, so `mdi-content-copy` (clipboard) may mislead users; consider a more appropriate icon such as `mdi-download` or `mdi-export`. Also, the hard-coded `'导出 JSON'` fallback bypasses i18n—please move this into the translation files and avoid language-specific strings directly in the template.

Suggested implementation:

```
                                    <v-list-item @click.stop="downloadPersonaJson(persona)">
                                        <v-list-item-title>
                                            <v-icon class="mr-2" size="small">mdi-download</v-icon>
                                            {{ tm('buttons.exportJson') }}
                                        </v-list-item-title>
                                    </v-list-item>

```

1. Add a `buttons.exportJson` translation key to your i18n resources (e.g., `en`, `zh`, etc.), with appropriate localized strings such as `"Export JSON"` / `"导出 JSON"`.
2. If your project follows a different naming convention for button keys (e.g., `buttons.export_json`), adjust the key in both the template and the i18n files accordingly.
</issue_to_address>

### Comment 2
<location> `dashboard/src/views/PersonaPage.vue:306` </location>
<code_context>
+                const url = URL.createObjectURL(blob);
+                const link = document.createElement('a');
+                link.href = url;
+                link.download = `${persona.persona_id}.json`;
+                
+                // 触发下载
</code_context>

<issue_to_address>
**issue:** Using `persona_id` directly in the filename may break downloads for IDs with special characters.

If `persona_id` can include spaces, slashes, or other disallowed filename characters, some browsers/OSes may fail to save the file or alter the name. Consider normalizing the ID for `download` (e.g., replace anything outside `[a-zA-Z0-9_-]` with `_`) or falling back to a safe default name, and optionally enforcing a reasonable max length.
</issue_to_address>

### Comment 3
<location> `dashboard/src/views/PersonaPage.vue:334-343` </location>
<code_context>
+                const parsedData = JSON.parse(text);
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Posting the raw parsed JSON to the API without whitelisting fields may introduce server-side risks.

The uploaded JSON is currently forwarded as-is to `/api/persona/create`. Even with backend validation, it’s safer to explicitly build the payload from the allowed fields (e.g. `persona_id`, `system_prompt`, `begin_dialogs`, `tools`) and drop everything else. This limits the impact of crafted JSON with unexpected properties and keeps the client–server contract strict.

Suggested implementation:

```
                const text = await file.text();
                const parsedData = JSON.parse(text);

                // 只从上传 JSON 中提取允许的字段,避免将未预期的字段直接转发到后端
                const allowedFields = ['persona_id', 'system_prompt', 'begin_dialogs', 'tools'];
                const personaPayload = allowedFields.reduce((acc, key) => {
                    if (Object.prototype.hasOwnProperty.call(parsedData, key)) {
                        acc[key] = parsedData[key];
                    }
                    return acc;
                }, {});

                console.log("Parsed Data (whitelisted):", personaPayload);

                // 验证必需字段(基于白名单后的数据)
                if (!personaPayload.persona_id || !personaPayload.system_prompt) {

```

1. 在该方法后续将数据发送到 `/api/persona/create` 时,请确保使用 `personaPayload` 而不是 `parsedData` 作为请求体(例如 `axios.post('/api/persona/create', personaPayload)`)。
2. 如果有任何依赖 `parsedData` 其他字段的逻辑,需要显式地将这些字段加入 `allowedFields` 白名单,或在前端增加相应的转换逻辑以保持与后端约定一致。
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Sjshi763 Sjshi763 changed the title Sjshi763/issue4409 Sjshi763/issue4409 feature:人格设定支持导出/导入 Jan 17, 2026
@nexusai97-gif

This comment was marked as spam.

@Sjshi763
Copy link
Author

Okay, 我拥有一个 API,有多个模型和高性能,价格便宜。欢迎在 Telegram @Nexusai97 上联系我。

傻逼吧,广告在pr打

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature:persona The bug / feature is about astrbot AI persona system (system prompt) size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants