feat: add export to Yuque
This commit is contained in:
parent
69513cc76e
commit
0a5401174b
@ -141,6 +141,7 @@
|
|||||||
"topics.export.image": "Export as image",
|
"topics.export.image": "Export as image",
|
||||||
"topics.export.md": "Export as markdown",
|
"topics.export.md": "Export as markdown",
|
||||||
"topics.export.notion": "Export to Notion",
|
"topics.export.notion": "Export to Notion",
|
||||||
|
"topics.export.yuque": "Export to Yuque",
|
||||||
"topics.export.title": "Export",
|
"topics.export.title": "Export",
|
||||||
"topics.export.word": "Export as Word",
|
"topics.export.word": "Export as Word",
|
||||||
"topics.list": "Topic List",
|
"topics.list": "Topic List",
|
||||||
@ -380,7 +381,9 @@
|
|||||||
"error.invalid.proxy.url": "Invalid proxy URL",
|
"error.invalid.proxy.url": "Invalid proxy URL",
|
||||||
"error.invalid.webdav": "Invalid WebDAV settings",
|
"error.invalid.webdav": "Invalid WebDAV settings",
|
||||||
"error.notion.export": "Failed to export to Notion. Please check connection status and configuration according to documentation",
|
"error.notion.export": "Failed to export to Notion. Please check connection status and configuration according to documentation",
|
||||||
|
"error.yuque.export": "Failed to export to Yuque. Please check connection status and configuration according to documentation",
|
||||||
"error.notion.no_api_key": "Notion ApiKey or Notion DatabaseID is not configured",
|
"error.notion.no_api_key": "Notion ApiKey or Notion DatabaseID is not configured",
|
||||||
|
"error.yuque.no_config": "Yuque Token or Yuque Url is not configured",
|
||||||
"group.delete.content": "Deleting a group message will delete the user's question and all assistant's answers",
|
"group.delete.content": "Deleting a group message will delete the user's question and all assistant's answers",
|
||||||
"group.delete.title": "Delete Group Message",
|
"group.delete.title": "Delete Group Message",
|
||||||
"mention.title": "Switch model answer",
|
"mention.title": "Switch model answer",
|
||||||
@ -402,6 +405,7 @@
|
|||||||
"restore.success": "Restored successfully",
|
"restore.success": "Restored successfully",
|
||||||
"save.success.title": "Saved successfully",
|
"save.success.title": "Saved successfully",
|
||||||
"success.notion.export": "Successfully exported to Notion",
|
"success.notion.export": "Successfully exported to Notion",
|
||||||
|
"success.yuque.export": "Successfully exported to Yuque",
|
||||||
"switch.disabled": "Please wait for the current reply to complete",
|
"switch.disabled": "Please wait for the current reply to complete",
|
||||||
"topic.added": "New topic added",
|
"topic.added": "New topic added",
|
||||||
"upgrade.success.button": "Restart",
|
"upgrade.success.button": "Restart",
|
||||||
@ -641,8 +645,24 @@
|
|||||||
"syncStatus": "Backup Status",
|
"syncStatus": "Backup Status",
|
||||||
"title": "WebDAV",
|
"title": "WebDAV",
|
||||||
"user": "WebDAV User"
|
"user": "WebDAV User"
|
||||||
|
},
|
||||||
|
"yuque": {
|
||||||
|
"title": "Yuque Configuration",
|
||||||
|
"repo_url": "Yuque URL",
|
||||||
|
"repo_url_placeholder": "https://www.yuque.com/username/xxx",
|
||||||
|
"token": "Yuque Token",
|
||||||
|
"token_placeholder": "Please enter the Yuque Token",
|
||||||
|
"help": "Get Yuque Token",
|
||||||
|
"check": {
|
||||||
|
"button": "Verify Connection",
|
||||||
|
"success": "Yuque connection verified successfully",
|
||||||
|
"fail": "Yuque connection verification failed",
|
||||||
|
"empty_token": "Please enter the Yuque Token first",
|
||||||
|
"empty_repo_url": "Please enter the knowledge base URL first"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"display.custom.css": "Custom CSS",
|
"display.custom.css": "Custom CSS",
|
||||||
"display.custom.css.placeholder": "/* Put custom CSS here */",
|
"display.custom.css.placeholder": "/* Put custom CSS here */",
|
||||||
"display.minApp.disabled": "Hidden MinApp",
|
"display.minApp.disabled": "Hidden MinApp",
|
||||||
|
|||||||
@ -141,6 +141,7 @@
|
|||||||
"topics.export.image": "画像としてエクスポート",
|
"topics.export.image": "画像としてエクスポート",
|
||||||
"topics.export.md": "Markdownとしてエクスポート",
|
"topics.export.md": "Markdownとしてエクスポート",
|
||||||
"topics.export.notion": "Notion にエクスポート",
|
"topics.export.notion": "Notion にエクスポート",
|
||||||
|
"topics.export.yuque": "語雀にエクスポート",
|
||||||
"topics.export.title": "エクスポート",
|
"topics.export.title": "エクスポート",
|
||||||
"topics.export.word": "Wordとしてエクスポート",
|
"topics.export.word": "Wordとしてエクスポート",
|
||||||
"topics.list": "トピックリスト",
|
"topics.list": "トピックリスト",
|
||||||
@ -380,7 +381,9 @@
|
|||||||
"error.invalid.proxy.url": "無効なプロキシURL",
|
"error.invalid.proxy.url": "無効なプロキシURL",
|
||||||
"error.invalid.webdav": "無効なWebDAV設定",
|
"error.invalid.webdav": "無効なWebDAV設定",
|
||||||
"error.notion.export": "Notionへのエクスポートに失敗しました。接続状態と設定を確認してください",
|
"error.notion.export": "Notionへのエクスポートに失敗しました。接続状態と設定を確認してください",
|
||||||
|
"error.yuque.export": "語雀へのエクスポートに失敗しました。接続状態と設定を確認してください",
|
||||||
"error.notion.no_api_key": "Notion ApiKey または Notion DatabaseID が設定されていません",
|
"error.notion.no_api_key": "Notion ApiKey または Notion DatabaseID が設定されていません",
|
||||||
|
"error.yuque.no_config": "語雀Token または 知識ベースID が設定されていません",
|
||||||
"group.delete.content": "分組メッセージを削除するとユーザーの質問と助け手の回答がすべて削除されます",
|
"group.delete.content": "分組メッセージを削除するとユーザーの質問と助け手の回答がすべて削除されます",
|
||||||
"group.delete.title": "分組メッセージを削除",
|
"group.delete.title": "分組メッセージを削除",
|
||||||
"mention.title": "モデルを切り替える",
|
"mention.title": "モデルを切り替える",
|
||||||
@ -402,6 +405,7 @@
|
|||||||
"restore.success": "復元に成功しました",
|
"restore.success": "復元に成功しました",
|
||||||
"save.success.title": "保存に成功しました",
|
"save.success.title": "保存に成功しました",
|
||||||
"success.notion.export": "Notionへのエクスポートに成功しました",
|
"success.notion.export": "Notionへのエクスポートに成功しました",
|
||||||
|
"success.yuque.export": "語雀へのエクスポートに成功しました",
|
||||||
"switch.disabled": "現在の応答が完了するまで切り替えを無効にします",
|
"switch.disabled": "現在の応答が完了するまで切り替えを無効にします",
|
||||||
"topic.added": "新しいトピックが追加されました",
|
"topic.added": "新しいトピックが追加されました",
|
||||||
"upgrade.success.button": "再起動",
|
"upgrade.success.button": "再起動",
|
||||||
@ -641,6 +645,21 @@
|
|||||||
"syncStatus": "バックアップ状態",
|
"syncStatus": "バックアップ状態",
|
||||||
"title": "WebDAV",
|
"title": "WebDAV",
|
||||||
"user": "WebDAVユーザー"
|
"user": "WebDAVユーザー"
|
||||||
|
},
|
||||||
|
"yuque": {
|
||||||
|
"title": "Yuque設定",
|
||||||
|
"repo_url": "ナレッジベースURL",
|
||||||
|
"repo_url_placeholder": "https://www.yuque.com/username/xxx",
|
||||||
|
"token": "Yuqueトークン",
|
||||||
|
"token_placeholder": "Yuqueトークンを入力してください",
|
||||||
|
"help": "Yuqueトークンを取得",
|
||||||
|
"check": {
|
||||||
|
"button": "接続確認",
|
||||||
|
"success": "Yuque接続確認に成功しました",
|
||||||
|
"fail": "Yuque接続確認に失敗しました",
|
||||||
|
"empty_token": "先にYuqueトークンを入力してください",
|
||||||
|
"empty_repo_url": "先にナレッジベースURLを入力してください"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"display.custom.css": "カスタムCSS",
|
"display.custom.css": "カスタムCSS",
|
||||||
|
|||||||
@ -141,6 +141,7 @@
|
|||||||
"topics.export.image": "Экспорт как изображение",
|
"topics.export.image": "Экспорт как изображение",
|
||||||
"topics.export.md": "Экспорт как markdown",
|
"topics.export.md": "Экспорт как markdown",
|
||||||
"topics.export.notion": "Экспорт в Notion",
|
"topics.export.notion": "Экспорт в Notion",
|
||||||
|
"topics.export.yuque": "Экспорт в Yuque",
|
||||||
"topics.export.title": "Экспорт",
|
"topics.export.title": "Экспорт",
|
||||||
"topics.export.word": "Экспорт как Word",
|
"topics.export.word": "Экспорт как Word",
|
||||||
"topics.list": "Список топиков",
|
"topics.list": "Список топиков",
|
||||||
@ -380,7 +381,9 @@
|
|||||||
"error.invalid.proxy.url": "Неверный URL прокси",
|
"error.invalid.proxy.url": "Неверный URL прокси",
|
||||||
"error.invalid.webdav": "Неверные настройки WebDAV",
|
"error.invalid.webdav": "Неверные настройки WebDAV",
|
||||||
"error.notion.export": "Ошибка экспорта в Notion, пожалуйста, проверьте состояние подключения и настройки в документации",
|
"error.notion.export": "Ошибка экспорта в Notion, пожалуйста, проверьте состояние подключения и настройки в документации",
|
||||||
|
"error.yuque.export": "Ошибка экспорта в Yuque, пожалуйста, проверьте состояние подключения и настройки в документации",
|
||||||
"error.notion.no_api_key": "Notion ApiKey или Notion DatabaseID не настроен",
|
"error.notion.no_api_key": "Notion ApiKey или Notion DatabaseID не настроен",
|
||||||
|
"error.yuque.no_config": "Yuque Token или Yuque Url не настроен",
|
||||||
"group.delete.content": "Удаление группы сообщений удалит пользовательский вопрос и все ответы помощника",
|
"group.delete.content": "Удаление группы сообщений удалит пользовательский вопрос и все ответы помощника",
|
||||||
"group.delete.title": "Удалить группу сообщений",
|
"group.delete.title": "Удалить группу сообщений",
|
||||||
"mention.title": "Переключить модель ответа",
|
"mention.title": "Переключить модель ответа",
|
||||||
@ -402,6 +405,7 @@
|
|||||||
"restore.success": "Успешно восстановлено",
|
"restore.success": "Успешно восстановлено",
|
||||||
"save.success.title": "Успешно сохранено",
|
"save.success.title": "Успешно сохранено",
|
||||||
"success.notion.export": "Успешный экспорт в Notion",
|
"success.notion.export": "Успешный экспорт в Notion",
|
||||||
|
"success.yuque.export": "Успешный экспорт в Yuque",
|
||||||
"switch.disabled": "Пожалуйста, дождитесь завершения текущего ответа",
|
"switch.disabled": "Пожалуйста, дождитесь завершения текущего ответа",
|
||||||
"topic.added": "Новый топик добавлен",
|
"topic.added": "Новый топик добавлен",
|
||||||
"upgrade.success.button": "Перезапустить",
|
"upgrade.success.button": "Перезапустить",
|
||||||
@ -637,6 +641,21 @@
|
|||||||
"title": "WebDAV",
|
"title": "WebDAV",
|
||||||
"user": "Пользователь WebDAV"
|
"user": "Пользователь WebDAV"
|
||||||
},
|
},
|
||||||
|
"yuque": {
|
||||||
|
"title": "Настройка Yuque",
|
||||||
|
"repo_url": "URL базы знаний",
|
||||||
|
"repo_url_placeholder": "https://www.yuque.com/username/xxx",
|
||||||
|
"token": "Токен Yuque",
|
||||||
|
"token_placeholder": "Введите токен Yuque",
|
||||||
|
"help": "Получить токен Yuque",
|
||||||
|
"check": {
|
||||||
|
"button": "Проверить подключение",
|
||||||
|
"success": "Подключение к Yuque успешно проверено",
|
||||||
|
"fail": "Не удалось проверить подключение к Yuque",
|
||||||
|
"empty_token": "Сначала введите токен Yuque",
|
||||||
|
"empty_repo_url": "Сначала введите URL базы знаний"
|
||||||
|
}
|
||||||
|
},
|
||||||
"notion.auto_split_tip": "Автоматическое разбиение на страницы при экспорте в Notion, если тема слишком длинная",
|
"notion.auto_split_tip": "Автоматическое разбиение на страницы при экспорте в Notion, если тема слишком длинная",
|
||||||
"notion.auto_split": "Автоматическое разбиение на страницы при экспорте диалога",
|
"notion.auto_split": "Автоматическое разбиение на страницы при экспорте диалога",
|
||||||
"notion.split_size": "Размер автоматического разбиения",
|
"notion.split_size": "Размер автоматического разбиения",
|
||||||
|
|||||||
@ -141,6 +141,7 @@
|
|||||||
"topics.export.image": "导出为图片",
|
"topics.export.image": "导出为图片",
|
||||||
"topics.export.md": "导出为 Markdown",
|
"topics.export.md": "导出为 Markdown",
|
||||||
"topics.export.notion": "导出到 Notion",
|
"topics.export.notion": "导出到 Notion",
|
||||||
|
"topics.export.yuque": "导出到语雀",
|
||||||
"topics.export.title": "导出",
|
"topics.export.title": "导出",
|
||||||
"topics.export.word": "导出为 Word",
|
"topics.export.word": "导出为 Word",
|
||||||
"topics.list": "话题列表",
|
"topics.list": "话题列表",
|
||||||
@ -380,7 +381,9 @@
|
|||||||
"error.invalid.proxy.url": "无效的代理地址",
|
"error.invalid.proxy.url": "无效的代理地址",
|
||||||
"error.invalid.webdav": "无效的 WebDAV 设置",
|
"error.invalid.webdav": "无效的 WebDAV 设置",
|
||||||
"error.notion.export": "导出Notion错误,请检查连接状态并对照文档检查配置",
|
"error.notion.export": "导出Notion错误,请检查连接状态并对照文档检查配置",
|
||||||
|
"error.yuque.export": "导出语雀错误,请检查连接状态并对照文档检查配置",
|
||||||
"error.notion.no_api_key": "未配置Notion ApiKey或Notion DatabaseID",
|
"error.notion.no_api_key": "未配置Notion ApiKey或Notion DatabaseID",
|
||||||
|
"error.yuque.no_config": "未配置语雀Token 或 知识库Url",
|
||||||
"group.delete.content": "删除分组消息会删除用户提问和所有助手的回答",
|
"group.delete.content": "删除分组消息会删除用户提问和所有助手的回答",
|
||||||
"group.delete.title": "删除分组消息",
|
"group.delete.title": "删除分组消息",
|
||||||
"mention.title": "切换模型回答",
|
"mention.title": "切换模型回答",
|
||||||
@ -402,6 +405,7 @@
|
|||||||
"restore.success": "恢复成功",
|
"restore.success": "恢复成功",
|
||||||
"save.success.title": "保存成功",
|
"save.success.title": "保存成功",
|
||||||
"success.notion.export": "成功导出到Notion",
|
"success.notion.export": "成功导出到Notion",
|
||||||
|
"success.yuque.export": "成功导出到语雀",
|
||||||
"switch.disabled": "请等待当前回复完成后操作",
|
"switch.disabled": "请等待当前回复完成后操作",
|
||||||
"topic.added": "话题添加成功",
|
"topic.added": "话题添加成功",
|
||||||
"upgrade.success.button": "重启",
|
"upgrade.success.button": "重启",
|
||||||
@ -641,6 +645,21 @@
|
|||||||
"syncStatus": "备份状态",
|
"syncStatus": "备份状态",
|
||||||
"title": "WebDAV",
|
"title": "WebDAV",
|
||||||
"user": "WebDAV 用户名"
|
"user": "WebDAV 用户名"
|
||||||
|
},
|
||||||
|
"yuque": {
|
||||||
|
"title": "语雀配置",
|
||||||
|
"repo_url": "知识库 URL",
|
||||||
|
"repo_url_placeholder": "https://www.yuque.com/username/xxx",
|
||||||
|
"token": "语雀 Token",
|
||||||
|
"token_placeholder": "请输入语雀Token",
|
||||||
|
"help": "获取语雀 Token",
|
||||||
|
"check": {
|
||||||
|
"button": "验证连接",
|
||||||
|
"success": "语雀连接验证成功",
|
||||||
|
"fail": "语雀连接验证失败",
|
||||||
|
"empty_token": "请先输入语雀Token",
|
||||||
|
"empty_repo_url": "请先输入知识库URL"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"display.custom.css": "自定义 CSS",
|
"display.custom.css": "自定义 CSS",
|
||||||
|
|||||||
@ -141,6 +141,7 @@
|
|||||||
"topics.export.image": "匯出為圖片",
|
"topics.export.image": "匯出為圖片",
|
||||||
"topics.export.md": "匯出為 Markdown",
|
"topics.export.md": "匯出為 Markdown",
|
||||||
"topics.export.notion": "匯出到 Notion",
|
"topics.export.notion": "匯出到 Notion",
|
||||||
|
"topics.export.yuque": "匯出到語雀",
|
||||||
"topics.export.title": "匯出",
|
"topics.export.title": "匯出",
|
||||||
"topics.export.word": "導出為 Word",
|
"topics.export.word": "導出為 Word",
|
||||||
"topics.list": "話題列表",
|
"topics.list": "話題列表",
|
||||||
@ -380,7 +381,9 @@
|
|||||||
"error.invalid.proxy.url": "無效的代理 URL",
|
"error.invalid.proxy.url": "無效的代理 URL",
|
||||||
"error.invalid.webdav": "無效的 WebDAV 設定",
|
"error.invalid.webdav": "無效的 WebDAV 設定",
|
||||||
"error.notion.export": "導出Notion錯誤,請檢查連接狀態並對照文檔檢查配置",
|
"error.notion.export": "導出Notion錯誤,請檢查連接狀態並對照文檔檢查配置",
|
||||||
|
"error.yuque.export": "導出語雀錯誤,請檢查連接狀態並對照文檔檢查配置",
|
||||||
"error.notion.no_api_key": "未配置 Notion ApiKey 或 Notion DatabaseID",
|
"error.notion.no_api_key": "未配置 Notion ApiKey 或 Notion DatabaseID",
|
||||||
|
"error.yuque.no_config": "未配置語雀Token 或 知識庫Url",
|
||||||
"group.delete.content": "刪除分組消息會刪除用戶提問和所有助手的回答",
|
"group.delete.content": "刪除分組消息會刪除用戶提問和所有助手的回答",
|
||||||
"group.delete.title": "刪除分組消息",
|
"group.delete.title": "刪除分組消息",
|
||||||
"mention.title": "切換模型回答",
|
"mention.title": "切換模型回答",
|
||||||
@ -402,6 +405,7 @@
|
|||||||
"restore.success": "恢復成功",
|
"restore.success": "恢復成功",
|
||||||
"save.success.title": "保存成功",
|
"save.success.title": "保存成功",
|
||||||
"success.notion.export": "成功導出到Notion",
|
"success.notion.export": "成功導出到Notion",
|
||||||
|
"success.yuque.export": "成功導出到語雀",
|
||||||
"switch.disabled": "請等待當前回覆完成",
|
"switch.disabled": "請等待當前回覆完成",
|
||||||
"topic.added": "新話題已添加",
|
"topic.added": "新話題已添加",
|
||||||
"upgrade.success.button": "重新啟動",
|
"upgrade.success.button": "重新啟動",
|
||||||
@ -641,6 +645,21 @@
|
|||||||
"syncStatus": "備份狀態",
|
"syncStatus": "備份狀態",
|
||||||
"title": "WebDAV",
|
"title": "WebDAV",
|
||||||
"user": "WebDAV 使用者名稱"
|
"user": "WebDAV 使用者名稱"
|
||||||
|
},
|
||||||
|
"yuque": {
|
||||||
|
"title": "語雀配置",
|
||||||
|
"repo_url": "知識庫 URL",
|
||||||
|
"repo_url_placeholder": "https://www.yuque.com/username/xxx",
|
||||||
|
"token": "語雀 Token",
|
||||||
|
"token_placeholder": "請輸入語雀Token",
|
||||||
|
"help": "獲取語雀 Token",
|
||||||
|
"check": {
|
||||||
|
"button": "驗證連接",
|
||||||
|
"success": "語雀連接驗證成功",
|
||||||
|
"fail": "語雀連接驗證失敗",
|
||||||
|
"empty_token": "請先輸入語雀Token",
|
||||||
|
"empty_repo_url": "請先輸入知識庫URL"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"display.custom.css": "自定義 CSS",
|
"display.custom.css": "自定義 CSS",
|
||||||
|
|||||||
@ -26,7 +26,12 @@ import {
|
|||||||
removeTrailingDoubleSpaces,
|
removeTrailingDoubleSpaces,
|
||||||
uuid
|
uuid
|
||||||
} from '@renderer/utils'
|
} from '@renderer/utils'
|
||||||
import { exportMarkdownToNotion, exportMessageAsMarkdown, messageToMarkdown } from '@renderer/utils/export'
|
import {
|
||||||
|
exportMarkdownToNotion,
|
||||||
|
exportMessageAsMarkdown,
|
||||||
|
messageToMarkdown,
|
||||||
|
exportMarkdownToYuque
|
||||||
|
} from '@renderer/utils/export'
|
||||||
import { Button, Dropdown, Popconfirm, Tooltip } from 'antd'
|
import { Button, Dropdown, Popconfirm, Tooltip } from 'antd'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
@ -258,6 +263,15 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
const markdown = messageToMarkdown(message)
|
const markdown = messageToMarkdown(message)
|
||||||
exportMarkdownToNotion(title, markdown)
|
exportMarkdownToNotion(title, markdown)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('chat.topics.export.yuque'),
|
||||||
|
key: 'yuque',
|
||||||
|
onClick: async () => {
|
||||||
|
const title = getMessageTitle(message)
|
||||||
|
const markdown = messageToMarkdown(message)
|
||||||
|
exportMarkdownToYuque(title, markdown)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,12 @@ import store from '@renderer/store'
|
|||||||
import { setGenerating } from '@renderer/store/runtime'
|
import { setGenerating } from '@renderer/store/runtime'
|
||||||
import { Assistant, Topic } from '@renderer/types'
|
import { Assistant, Topic } from '@renderer/types'
|
||||||
import { copyTopicAsMarkdown } from '@renderer/utils/copy'
|
import { copyTopicAsMarkdown } from '@renderer/utils/copy'
|
||||||
import { exportMarkdownToNotion, exportTopicAsMarkdown, topicToMarkdown } from '@renderer/utils/export'
|
import {
|
||||||
|
exportMarkdownToNotion,
|
||||||
|
exportMarkdownToYuque,
|
||||||
|
exportTopicAsMarkdown,
|
||||||
|
topicToMarkdown
|
||||||
|
} from '@renderer/utils/export'
|
||||||
import { Dropdown, MenuProps, Tooltip } from 'antd'
|
import { Dropdown, MenuProps, Tooltip } from 'antd'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { findIndex } from 'lodash'
|
import { findIndex } from 'lodash'
|
||||||
@ -239,6 +244,14 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
|||||||
const markdown = await topicToMarkdown(topic)
|
const markdown = await topicToMarkdown(topic)
|
||||||
exportMarkdownToNotion(topic.name, markdown)
|
exportMarkdownToNotion(topic.name, markdown)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('chat.topics.export.yuque'),
|
||||||
|
key: 'yuque',
|
||||||
|
onClick: async () => {
|
||||||
|
const markdown = await topicToMarkdown(topic)
|
||||||
|
exportMarkdownToYuque(topic.name, markdown)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,10 @@ import {
|
|||||||
setNotionAutoSplit,
|
setNotionAutoSplit,
|
||||||
setNotionDatabaseID,
|
setNotionDatabaseID,
|
||||||
setNotionPageNameKey,
|
setNotionPageNameKey,
|
||||||
setNotionSplitSize
|
setNotionSplitSize,
|
||||||
|
setYuqueRepoId,
|
||||||
|
setYuqueToken,
|
||||||
|
setYuqueUrl
|
||||||
} from '@renderer/store/settings'
|
} from '@renderer/store/settings'
|
||||||
import { AppInfo } from '@renderer/types'
|
import { AppInfo } from '@renderer/types'
|
||||||
import { Button, InputNumber, Modal, Switch, Tooltip, Typography } from 'antd'
|
import { Button, InputNumber, Modal, Switch, Tooltip, Typography } from 'antd'
|
||||||
@ -189,6 +192,107 @@ const NotionSettings: FC = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const YuqueSettings: FC = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { theme } = useTheme()
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
const yuqueToken = useSelector((state: RootState) => state.settings.yuqueToken)
|
||||||
|
const yuqueUrl = useSelector((state: RootState) => state.settings.yuqueUrl)
|
||||||
|
|
||||||
|
const handleYuqueTokenChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
dispatch(setYuqueToken(e.target.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleYuqueRepoUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
dispatch(setYuqueUrl(e.target.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleYuqueConnectionCheck = async () => {
|
||||||
|
if (!yuqueToken) {
|
||||||
|
window.message.error(t('settings.data.yuque.check.empty_token'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!yuqueUrl) {
|
||||||
|
window.message.error(t('settings.data.yuque.check.empty_url'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch('https://www.yuque.com/api/v2/hello', {
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token': yuqueToken
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
window.message.error(t('settings.data.yuque.check.fail'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const yuqueSlug = yuqueUrl.replace('https://www.yuque.com/', '')
|
||||||
|
const repoIDResponse = await fetch(`https://www.yuque.com/api/v2/repos/${yuqueSlug}`, {
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token': yuqueToken
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!repoIDResponse.ok) {
|
||||||
|
window.message.error(t('settings.data.yuque.check.fail'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const data = await repoIDResponse.json()
|
||||||
|
dispatch(setYuqueRepoId(data.data.id))
|
||||||
|
window.message.success(t('settings.data.yuque.check.success'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleYuqueHelpClick = () => {
|
||||||
|
MinApp.start({
|
||||||
|
id: 'yuque-help',
|
||||||
|
name: 'Yuque Help',
|
||||||
|
url: 'https://www.yuque.com/settings/tokens'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingGroup theme={theme}>
|
||||||
|
<SettingTitle>{t('settings.data.yuque.title')}</SettingTitle>
|
||||||
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitle>{t('settings.data.yuque.repo_url')}</SettingRowTitle>
|
||||||
|
<HStack alignItems="center" gap="5px" style={{ width: 315 }}>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
value={yuqueUrl || ''}
|
||||||
|
onChange={handleYuqueRepoUrlChange}
|
||||||
|
style={{ width: 315 }}
|
||||||
|
placeholder={t('settings.data.yuque.repo_url_placeholder')}
|
||||||
|
/>
|
||||||
|
</HStack>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitle>
|
||||||
|
{t('settings.data.yuque.token')}
|
||||||
|
<Tooltip title={t('settings.data.yuque.help')} placement="left">
|
||||||
|
<InfoCircleOutlined
|
||||||
|
style={{ color: 'var(--color-text-2)', cursor: 'pointer', marginLeft: 4 }}
|
||||||
|
onClick={handleYuqueHelpClick}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</SettingRowTitle>
|
||||||
|
<HStack alignItems="center" gap="5px" style={{ width: 315 }}>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
value={yuqueToken || ''}
|
||||||
|
onChange={handleYuqueTokenChange}
|
||||||
|
style={{ width: 250 }}
|
||||||
|
placeholder={t('settings.data.yuque.token_placeholder')}
|
||||||
|
/>
|
||||||
|
<Button onClick={handleYuqueConnectionCheck}>{t('settings.data.yuque.check.button')}</Button>
|
||||||
|
</HStack>
|
||||||
|
</SettingRow>
|
||||||
|
</SettingGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const DataSettings: FC = () => {
|
const DataSettings: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [appInfo, setAppInfo] = useState<AppInfo>()
|
const [appInfo, setAppInfo] = useState<AppInfo>()
|
||||||
@ -258,6 +362,7 @@ const DataSettings: FC = () => {
|
|||||||
<WebDavSettings />
|
<WebDavSettings />
|
||||||
</SettingGroup>
|
</SettingGroup>
|
||||||
<NotionSettings />
|
<NotionSettings />
|
||||||
|
<YuqueSettings />
|
||||||
<SettingGroup theme={theme}>
|
<SettingGroup theme={theme}>
|
||||||
<SettingTitle>{t('settings.data.data.title')}</SettingTitle>
|
<SettingTitle>{t('settings.data.data.title')}</SettingTitle>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
|||||||
@ -73,6 +73,9 @@ export interface SettingsState {
|
|||||||
thoughtAutoCollapse: boolean
|
thoughtAutoCollapse: boolean
|
||||||
notionAutoSplit: boolean
|
notionAutoSplit: boolean
|
||||||
notionSplitSize: number
|
notionSplitSize: number
|
||||||
|
yuqueToken: string | null
|
||||||
|
yuqueUrl: string | null
|
||||||
|
yuqueRepoId: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MultiModelMessageStyle = 'horizontal' | 'vertical' | 'fold' | 'grid'
|
export type MultiModelMessageStyle = 'horizontal' | 'vertical' | 'fold' | 'grid'
|
||||||
@ -131,7 +134,10 @@ const initialState: SettingsState = {
|
|||||||
notionPageNameKey: 'Name',
|
notionPageNameKey: 'Name',
|
||||||
thoughtAutoCollapse: true,
|
thoughtAutoCollapse: true,
|
||||||
notionAutoSplit: false,
|
notionAutoSplit: false,
|
||||||
notionSplitSize: 90
|
notionSplitSize: 90,
|
||||||
|
yuqueToken: '',
|
||||||
|
yuqueUrl: '',
|
||||||
|
yuqueRepoId: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsSlice = createSlice({
|
const settingsSlice = createSlice({
|
||||||
@ -302,6 +308,15 @@ const settingsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
setNotionSplitSize: (state, action: PayloadAction<number>) => {
|
setNotionSplitSize: (state, action: PayloadAction<number>) => {
|
||||||
state.notionSplitSize = action.payload
|
state.notionSplitSize = action.payload
|
||||||
|
},
|
||||||
|
setYuqueToken: (state, action: PayloadAction<string>) => {
|
||||||
|
state.yuqueToken = action.payload
|
||||||
|
},
|
||||||
|
setYuqueRepoId: (state, action: PayloadAction<string>) => {
|
||||||
|
state.yuqueRepoId = action.payload
|
||||||
|
},
|
||||||
|
setYuqueUrl: (state, action: PayloadAction<string>) => {
|
||||||
|
state.yuqueUrl = action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -359,7 +374,10 @@ export const {
|
|||||||
setNotionPageNameKey,
|
setNotionPageNameKey,
|
||||||
setThoughtAutoCollapse,
|
setThoughtAutoCollapse,
|
||||||
setNotionAutoSplit,
|
setNotionAutoSplit,
|
||||||
setNotionSplitSize
|
setNotionSplitSize,
|
||||||
|
setYuqueToken,
|
||||||
|
setYuqueRepoId,
|
||||||
|
setYuqueUrl
|
||||||
} = settingsSlice.actions
|
} = settingsSlice.actions
|
||||||
|
|
||||||
export default settingsSlice.reducer
|
export default settingsSlice.reducer
|
||||||
|
|||||||
@ -215,3 +215,76 @@ export const exportMarkdownToNotion = async (title: string, content: string) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exportMarkdownToYuque = async (title: string, content: string) => {
|
||||||
|
const { isExporting } = store.getState().runtime.export
|
||||||
|
const { yuqueToken, yuqueRepoId } = store.getState().settings
|
||||||
|
|
||||||
|
if (isExporting) {
|
||||||
|
window.message.warning({ content: i18n.t('message.warn.yuque.exporting'), key: 'yuque-exporting' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!yuqueToken || !yuqueRepoId) {
|
||||||
|
window.message.error({ content: i18n.t('message.error.yuque.no_config'), key: 'yuque-no-config-error' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setExportState({ isExporting: true })
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`https://www.yuque.com/api/v2/repos/${yuqueRepoId}/docs`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Auth-Token': yuqueToken,
|
||||||
|
'User-Agent': 'CherryAI'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
title: title,
|
||||||
|
slug: Date.now().toString(), // 使用时间戳作为唯一slug
|
||||||
|
format: 'markdown',
|
||||||
|
body: content
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json()
|
||||||
|
const doc_id = data.data.id
|
||||||
|
|
||||||
|
const tocResponse = await fetch(`https://www.yuque.com/api/v2/repos/${yuqueRepoId}/toc`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Auth-Token': yuqueToken,
|
||||||
|
'User-Agent': 'CherryAI'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
action: 'appendNode',
|
||||||
|
action_mode: 'sibling',
|
||||||
|
doc_ids: [doc_id]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!tocResponse.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${tocResponse.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.message.success({
|
||||||
|
content: i18n.t('message.success.yuque.export'),
|
||||||
|
key: 'yuque-success'
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
} catch (error: any) {
|
||||||
|
window.message.error({
|
||||||
|
content: i18n.t('message.error.yuque.export'),
|
||||||
|
key: 'yuque-error'
|
||||||
|
})
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
setExportState({ isExporting: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user