diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json
index e6b1b731..f8679a07 100644
--- a/src/renderer/src/i18n/locales/en-us.json
+++ b/src/renderer/src/i18n/locales/en-us.json
@@ -411,6 +411,8 @@
"error.invalid.enter.model": "Please select a model",
"error.invalid.proxy.url": "Invalid proxy URL",
"error.invalid.webdav": "Invalid WebDAV settings",
+ "error.markdown.export.preconf": "Failed to export the Markdown file to the preconfigured path",
+ "error.markdown.export.specified": "Failed to export the Markdown file",
"error.notion.export": "Failed to export to Notion. Please check connection status and configuration according to documentation",
"error.notion.no_api_key": "Notion ApiKey or Notion DatabaseID is not configured",
"error.yuque.export": "Failed to export to Yuque. Please check connection status and configuration according to documentation",
@@ -441,6 +443,8 @@
"restore.success": "Restored successfully",
"save.success.title": "Saved successfully",
"searching": "Searching the internet...",
+ "success.markdown.export.preconf": "Successfully exported the Markdown file to the preconfigured path",
+ "success.markdown.export.specified": "Successfully exported the Markdown file",
"success.notion.export": "Successfully exported to Notion",
"success.yuque.export": "Successfully exported to Yuque",
"switch.disabled": "Please wait for the current reply to complete",
@@ -666,6 +670,11 @@
"hour_interval_other": "{{count}} hours",
"minute_interval_one": "{{count}} minute",
"minute_interval_other": "{{count}} minutes",
+ "markdown_export.title": "Markdown Export",
+ "markdown_export.path": "Default Export Path",
+ "markdown_export.path_placeholder": "Export Path",
+ "markdown_export.select": "Select",
+ "markdown_export.help": "If provided, exports will be automatically saved to this path; otherwise, a save dialog will appear.",
"notion.api_key": "Notion API Key",
"notion.api_key_placeholder": "Enter Notion API Key",
"notion.auto_split": "Auto split when exporting",
diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json
index 4054ddfa..c08d6fc9 100644
--- a/src/renderer/src/i18n/locales/ja-jp.json
+++ b/src/renderer/src/i18n/locales/ja-jp.json
@@ -411,6 +411,8 @@
"error.invalid.enter.model": "モデルを選択してください",
"error.invalid.proxy.url": "無効なプロキシURL",
"error.invalid.webdav": "無効なWebDAV設定",
+ "error.markdown.export.preconf": "Markdown ファイルを事前設定されたパスにエクスポートできませんでした",
+ "error.markdown.export.specified": "Markdown ファイルのエクスポートに失敗しました",
"error.notion.export": "Notionへのエクスポートに失敗しました。接続状態と設定を確認してください",
"error.notion.no_api_key": "Notion ApiKey または Notion DatabaseID が設定されていません",
"error.yuque.export": "語雀へのエクスポートに失敗しました。接続状態と設定を確認してください",
@@ -441,6 +443,8 @@
"restore.success": "復元に成功しました",
"save.success.title": "保存に成功しました",
"searching": "インターネットで検索中...",
+ "success.markdown.export.preconf": "Markdown ファイルを事前設定されたパスに正常にエクスポートしました",
+ "success.markdown.export.specified": "Markdown ファイルを正常にエクスポートしました",
"success.notion.export": "Notionへのエクスポートに成功しました",
"success.yuque.export": "語雀へのエクスポートに成功しました",
"switch.disabled": "現在の応答が完了するまで切り替えを無効にします",
@@ -666,6 +670,11 @@
"hour_interval_other": "{{count}} 時間",
"minute_interval_one": "{{count}} 分",
"minute_interval_other": "{{count}} 分",
+ "markdown_export.title": "Markdown エクスポート",
+ "markdown_export.path": "デフォルトのエクスポートパス",
+ "markdown_export.path_placeholder": "エクスポートパス",
+ "markdown_export.select": "選択",
+ "markdown_export.help": "入力された場合、エクスポート時に自動的にこのパスに保存されます。未入力の場合、保存ダイアログが表示されます。",
"notion.api_key": "Notion APIキー",
"notion.api_key_placeholder": "Notion APIキーを入力してください",
"notion.auto_split": "내보내기 시 자동 분할",
diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json
index 1b46e911..ed145321 100644
--- a/src/renderer/src/i18n/locales/ru-ru.json
+++ b/src/renderer/src/i18n/locales/ru-ru.json
@@ -411,6 +411,8 @@
"error.invalid.enter.model": "Пожалуйста, выберите модель",
"error.invalid.proxy.url": "Неверный URL прокси",
"error.invalid.webdav": "Неверные настройки WebDAV",
+ "error.markdown.export.preconf": "Не удалось экспортировать файл Markdown в предуказанный путь",
+ "error.markdown.export.specified": "Не удалось экспортировать файл Markdown",
"error.notion.export": "Ошибка экспорта в Notion, пожалуйста, проверьте состояние подключения и настройки в документации",
"error.notion.no_api_key": "Notion ApiKey или Notion DatabaseID не настроен",
"error.yuque.export": "Ошибка экспорта в Yuque, пожалуйста, проверьте состояние подключения и настройки в документации",
@@ -441,6 +443,8 @@
"restore.success": "Успешно восстановлено",
"save.success.title": "Успешно сохранено",
"searching": "Поиск в Интернете...",
+ "success.markdown.export.preconf": "Файл Markdown успешно экспортирован в предуказанный путь",
+ "success.markdown.export.specified": "Файл Markdown успешно экспортирован",
"success.notion.export": "Успешный экспорт в Notion",
"success.yuque.export": "Успешный экспорт в Yuque",
"switch.disabled": "Пожалуйста, дождитесь завершения текущего ответа",
@@ -666,6 +670,11 @@
"hour_interval_other": "{{count}} часов",
"minute_interval_one": "{{count}} минута",
"minute_interval_other": "{{count}} минут",
+ "markdown_export.title": "Экспорт в Markdown",
+ "markdown_export.path": "Путь экспорта по умолчанию",
+ "markdown_export.path_placeholder": "Путь экспорта",
+ "markdown_export.select": "Выбрать",
+ "markdown_export.help": "Если указано, файлы будут автоматически сохраняться в этот путь; в противном случае появится диалоговое окно сохранения.",
"notion.api_key": "Ключ API Notion",
"notion.api_key_placeholder": "Введите ключ API Notion",
"notion.auto_split": "Автоматическое разбиение на страницы при экспорте диалога",
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index e088b396..4f9cb34f 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -411,6 +411,8 @@
"error.invalid.enter.model": "请选择一个模型",
"error.invalid.proxy.url": "无效的代理地址",
"error.invalid.webdav": "无效的 WebDAV 设置",
+ "error.markdown.export.preconf": "导出Markdown文件到预先设定的路径失败",
+ "error.markdown.export.specified": "导出Markdown文件失败",
"error.notion.export": "导出 Notion 错误,请检查连接状态并对照文档检查配置",
"error.notion.no_api_key": "未配置 Notion API Key 或 Notion Database ID",
"error.yuque.export": "导出语雀错误,请检查连接状态并对照文档检查配置",
@@ -441,6 +443,8 @@
"restore.success": "恢复成功",
"save.success.title": "保存成功",
"searching": "正在联网搜索...",
+ "success.markdown.export.preconf": "成功导出Markdown文件到预先设定的路径",
+ "success.markdown.export.specified": "成功导出Markdown文件",
"success.notion.export": "成功导出到Notion",
"success.yuque.export": "成功导出到语雀",
"switch.disabled": "请等待当前回复完成后操作",
@@ -666,6 +670,11 @@
"hour_interval_other": "{{count}} 小时",
"minute_interval_one": "{{count}} 分钟",
"minute_interval_other": "{{count}} 分钟",
+ "markdown_export.title": "Markdown 导出",
+ "markdown_export.path": "默认导出路径",
+ "markdown_export.path_placeholder": "导出路径",
+ "markdown_export.select": "选择",
+ "markdown_export.help": "若填入,则每次导出时将自动保存到该路径;否则,将弹出保存对话框",
"notion.api_key": "Notion 密钥",
"notion.api_key_placeholder": "请输入Notion 密钥",
"notion.auto_split": "导出对话时自动分页",
diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json
index 66ce6a74..21910d6f 100644
--- a/src/renderer/src/i18n/locales/zh-tw.json
+++ b/src/renderer/src/i18n/locales/zh-tw.json
@@ -411,6 +411,8 @@
"error.invalid.enter.model": "請選擇一個模型",
"error.invalid.proxy.url": "無效的代理伺服器 URL",
"error.invalid.webdav": "無效的 WebDAV 設定",
+ "error.markdown.export.preconf": "導出 Markdown 文件到預先設定的路徑失敗",
+ "error.markdown.export.specified": "導出 Markdown 文件失敗",
"error.notion.export": "匯出 Notion 錯誤,請檢查連接狀態並對照文件檢查設定",
"error.notion.no_api_key": "未設定 Notion API Key 或 Notion Database ID",
"error.yuque.export": "匯出語雀錯誤,請檢查連接狀態並對照文件檢查設定",
@@ -441,6 +443,8 @@
"restore.success": "恢復成功",
"save.success.title": "儲存成功",
"searching": "正在網路上搜尋...",
+ "success.markdown.export.preconf": "成功導出 Markdown 文件到預先設定的路徑",
+ "success.markdown.export.specified": "成功導出 Markdown 文件",
"success.notion.export": "成功匯出到 Notion",
"success.yuque.export": "成功匯出到語雀",
"switch.disabled": "請等待當前回覆完成",
@@ -666,6 +670,11 @@
"hour_interval_other": "{{count}} 小時",
"minute_interval_one": "{{count}} 分鐘",
"minute_interval_other": "{{count}} 分鐘",
+ "markdown_export.title": "Markdown 匯出",
+ "markdown_export.path": "預設匯出路徑",
+ "markdown_export.path_placeholder": "匯出路徑",
+ "markdown_export.select": "選擇",
+ "markdown_export.help": "若填入,每次匯出時將自動儲存至該路徑;否則,將彈出儲存對話框。",
"notion.api_key": "Notion 金鑰",
"notion.api_key_placeholder": "請輸入 Notion 金鑰",
"notion.auto_split": "匯出對話時自動分頁",
diff --git a/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx b/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx
index c20a47cd..3f0358fa 100644
--- a/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx
+++ b/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx
@@ -1,4 +1,10 @@
-import { FileSearchOutlined, FolderOpenOutlined, InfoCircleOutlined, SaveOutlined } from '@ant-design/icons'
+import {
+ DeleteOutlined,
+ FileSearchOutlined,
+ FolderOpenOutlined,
+ InfoCircleOutlined,
+ SaveOutlined
+} from '@ant-design/icons'
import { Client } from '@notionhq/client'
import { HStack } from '@renderer/components/Layout'
import MinApp from '@renderer/components/MinApp'
@@ -9,6 +15,7 @@ import { useKnowledgeFiles } from '@renderer/hooks/useKnowledgeFiles'
import { reset } from '@renderer/services/BackupService'
import { RootState, useAppDispatch } from '@renderer/store'
import {
+ setmarkdownExportPath,
setNotionApiKey,
setNotionAutoSplit,
setNotionDatabaseID,
@@ -38,6 +45,56 @@ import {
} from '..'
import WebDavSettings from './WebDavSettings'
+// 新增的 MarkdownExportSettings 组件
+const MarkdownExportSettings: FC = () => {
+ const { t } = useTranslation()
+ const { theme } = useTheme()
+ const dispatch = useAppDispatch()
+
+ const markdownExportPath = useSelector((state: RootState) => state.settings.markdownExportPath)
+
+ const handleSelectFolder = async () => {
+ const path = await window.api.file.selectFolder()
+ if (path) {
+ dispatch(setmarkdownExportPath(path))
+ }
+ }
+
+ const handleClearPath = () => {
+ dispatch(setmarkdownExportPath(null))
+ }
+
+ return (
+
+ {t('settings.data.markdown_export.title')}
+
+
+ {t('settings.data.markdown_export.path')}
+
+
+ ) : null
+ }
+ />
+ }>
+ {t('settings.data.markdown_export.select')}
+
+
+
+
+ {t('settings.data.markdown_export.help')}
+
+
+ )
+}
+
// 新增的 NotionSettings 组件
const NotionSettings: FC = () => {
const { t } = useTranslation()
@@ -382,6 +439,7 @@ const DataSettings: FC = () => {
+
diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts
index d269144a..35be6eac 100644
--- a/src/renderer/src/store/settings.ts
+++ b/src/renderer/src/store/settings.ts
@@ -72,6 +72,7 @@ export interface SettingsState {
notionDatabaseID: string | null
notionApiKey: string | null
notionPageNameKey: string | null
+ markdownExportPath: string | null
thoughtAutoCollapse: boolean
notionAutoSplit: boolean
notionSplitSize: number
@@ -136,6 +137,7 @@ const initialState: SettingsState = {
notionDatabaseID: '',
notionApiKey: '',
notionPageNameKey: 'Name',
+ markdownExportPath: null,
thoughtAutoCollapse: true,
notionAutoSplit: false,
notionSplitSize: 90,
@@ -310,6 +312,9 @@ const settingsSlice = createSlice({
setNotionPageNameKey: (state, action: PayloadAction) => {
state.notionPageNameKey = action.payload
},
+ setmarkdownExportPath: (state, action: PayloadAction) => {
+ state.markdownExportPath = action.payload
+ },
setThoughtAutoCollapse: (state, action: PayloadAction) => {
state.thoughtAutoCollapse = action.payload
},
@@ -384,6 +389,7 @@ export const {
setNotionDatabaseID,
setNotionApiKey,
setNotionPageNameKey,
+ setmarkdownExportPath,
setThoughtAutoCollapse,
setNotionAutoSplit,
setNotionSplitSize,
diff --git a/src/renderer/src/utils/export.ts b/src/renderer/src/utils/export.ts
index 32c0f0f5..35a5a475 100644
--- a/src/renderer/src/utils/export.ts
+++ b/src/renderer/src/utils/export.ts
@@ -6,6 +6,7 @@ import store from '@renderer/store'
import { setExportState } from '@renderer/store/runtime'
import { Message, Topic } from '@renderer/types'
import { removeSpecialCharactersForFileName } from '@renderer/utils/index'
+import dayjs from 'dayjs'
export const messageToMarkdown = (message: Message) => {
const roleText = message.role === 'user' ? '🧑💻 User' : '🤖 Assistant'
@@ -31,15 +32,51 @@ export const topicToMarkdown = async (topic: Topic) => {
}
export const exportTopicAsMarkdown = async (topic: Topic) => {
- const fileName = removeSpecialCharactersForFileName(topic.name) + '.md'
- const markdown = await topicToMarkdown(topic)
- window.api.file.save(fileName, markdown)
+ const { markdownExportPath } = store.getState().settings
+ if (!markdownExportPath) {
+ try {
+ const fileName = removeSpecialCharactersForFileName(topic.name) + '.md'
+ const markdown = await topicToMarkdown(topic)
+ await window.api.file.save(fileName, markdown)
+ window.message.success({ content: i18n.t('message.success.markdown.export.specified'), key: 'markdown-success' })
+ } catch (error: any) {
+ window.message.error({ content: i18n.t('message.error.markdown.export.specified'), key: 'markdown-error' })
+ }
+ } else {
+ try {
+ const timestamp = dayjs().format('YYYY-MM-DD-HH-mm-ss')
+ const fileName = removeSpecialCharactersForFileName(topic.name) + ` ${timestamp}.md`
+ const markdown = await topicToMarkdown(topic)
+ await window.api.file.write(markdownExportPath + '/' + fileName, markdown)
+ window.message.success({ content: i18n.t('message.success.markdown.export.preconf'), key: 'markdown-success' })
+ } catch (error: any) {
+ window.message.error({ content: i18n.t('message.error.markdown.export.preconf'), key: 'markdown error' })
+ }
+ }
}
export const exportMessageAsMarkdown = async (message: Message) => {
- const fileName = getMessageTitle(message) + '.md'
- const markdown = messageToMarkdown(message)
- window.api.file.save(fileName, markdown)
+ const { markdownExportPath } = store.getState().settings
+ if (!markdownExportPath) {
+ try {
+ const fileName = removeSpecialCharactersForFileName(getMessageTitle(message)) + '.md'
+ const markdown = messageToMarkdown(message)
+ await window.api.file.save(fileName, markdown)
+ window.message.success({ content: i18n.t('message.success.markdown.export.specified'), key: 'markdown-success' })
+ } catch (error: any) {
+ window.message.error({ content: i18n.t('message.error.markdown.export.specified'), key: 'markdown error' })
+ }
+ } else {
+ try {
+ const timestamp = dayjs().format('YYYY-MM-DD-HH-mm-ss')
+ const fileName = removeSpecialCharactersForFileName(getMessageTitle(message)) + ` ${timestamp}.md`
+ const markdown = messageToMarkdown(message)
+ await window.api.file.write(markdownExportPath + '/' + fileName, markdown)
+ window.message.success({ content: i18n.t('message.success.markdown.export.preconf'), key: 'markdown-success' })
+ } catch (error: any) {
+ window.message.error({ content: i18n.t('message.error.markdown.export.preconf'), key: 'markdown-error' })
+ }
+ }
}
// 修改 splitNotionBlocks 函数