feat: add support for title generation when exporting single message

#3992
This commit is contained in:
shiquda 2025-03-31 23:44:35 +08:00 committed by 亢奋猫
parent 750247aef8
commit 8fbedb2bd0
10 changed files with 87 additions and 19 deletions

View File

@ -229,7 +229,10 @@
"topics.title": "Topics",
"topics.unpinned": "Unpinned Topics",
"translate": "Translate",
"topics.export.siyuan": "Export to Siyuan Note"
"topics.export.siyuan": "Export to Siyuan Note",
"topics.export.wait_for_title_naming": "Generating title...",
"topics.export.title_naming_success": "Title generated successfully",
"topics.export.title_naming_failed": "Failed to generate title, using default title"
},
"code_block": {
"collapse": "Collapse",
@ -919,7 +922,9 @@
"new_folder.button.confirm": "Confirm",
"new_folder.button.cancel": "Cancel",
"new_folder.button": "New Folder"
}
},
"message_title.use_topic_naming.title": "Use topic naming model to create titles for exported messages",
"message_title.use_topic_naming.help": "When enabled, use topic naming model to create titles for exported messages. This will also affect all Markdown export methods."
},
"display.assistant.title": "Assistant Settings",
"display.custom.css": "Custom CSS",

View File

@ -229,7 +229,10 @@
"topics.title": "トピック",
"topics.unpinned": "固定解除",
"translate": "翻訳",
"topics.export.siyuan": "思源笔记にエクスポート"
"topics.export.siyuan": "思源笔记にエクスポート",
"topics.export.wait_for_title_naming": "タイトルを生成中...",
"topics.export.title_naming_success": "タイトルの生成に成功しました",
"topics.export.title_naming_failed": "タイトルの生成に失敗しました。デフォルトのタイトルを使用します"
},
"code_block": {
"collapse": "折りたたむ",
@ -1246,7 +1249,9 @@
},
"title": "ウェブ検索"
},
"general.auto_check_update.title": "自動更新チェックを有効にする"
"general.auto_check_update.title": "自動更新チェックを有効にする",
"message_title.use_topic_naming.title": "エクスポートされたメッセージのタイトル作成にトピック命名モデルを使用",
"message_title.use_topic_naming.help": "有効にすると、エクスポートされたメッセージのタイトル作成にトピック命名モデルを使用します。これはすべてのMarkdownエクスポート方式にも影響します。"
},
"translate": {
"any.language": "任意の言語",

View File

@ -229,7 +229,10 @@
"topics.title": "Топики",
"topics.unpinned": "Открепленные темы",
"translate": "Перевести",
"topics.export.siyuan": "Экспорт в Siyuan Note"
"topics.export.siyuan": "Экспорт в Siyuan Note",
"topics.export.wait_for_title_naming": "Создание заголовка...",
"topics.export.title_naming_success": "Заголовок успешно создан",
"topics.export.title_naming_failed": "Не удалось создать заголовок, используется заголовок по умолчанию"
},
"code_block": {
"collapse": "Свернуть",
@ -1246,7 +1249,9 @@
},
"title": "Поиск в Интернете"
},
"general.auto_check_update.title": "Включить автоматическую проверку обновлений"
"general.auto_check_update.title": "Включить автоматическую проверку обновлений",
"message_title.use_topic_naming.title": "Использовать модель именования тем для создания заголовков экспортируемых сообщений",
"message_title.use_topic_naming.help": "При включении использует модель именования тем для создания заголовков экспортируемых сообщений. Это также повлияет на все методы экспорта Markdown."
},
"translate": {
"any.language": "Любой язык",

View File

@ -229,7 +229,10 @@
"topics.title": "话题",
"topics.unpinned": "取消固定",
"translate": "翻译",
"topics.export.siyuan": "导出到思源笔记"
"topics.export.siyuan": "导出到思源笔记",
"topics.export.wait_for_title_naming": "正在生成标题...",
"topics.export.title_naming_success": "标题生成成功",
"topics.export.title_naming_failed": "标题生成失败,使用默认标题"
},
"code_block": {
"collapse": "收起",
@ -800,6 +803,8 @@
"markdown_export.path_placeholder": "导出路径",
"markdown_export.select": "选择",
"markdown_export.title": "Markdown 导出",
"message_title.use_topic_naming.title": "使用话题命名模型为导出的消息创建标题",
"message_title.use_topic_naming.help": "开启后使用话题命名模型为导出的消息创建标题。该项也会影响所有通过Markdown导出的方式。",
"minute_interval_one": "{{count}} 分钟",
"minute_interval_other": "{{count}} 分钟",
"notion.api_key": "Notion 密钥",

View File

@ -229,7 +229,10 @@
"topics.title": "話題",
"topics.unpinned": "取消固定",
"translate": "翻譯",
"topics.export.siyuan": "匯出到思源筆記"
"topics.export.siyuan": "匯出到思源筆記",
"topics.export.wait_for_title_naming": "正在生成標題...",
"topics.export.title_naming_success": "標題生成成功",
"topics.export.title_naming_failed": "標題生成失敗,使用預設標題"
},
"code_block": {
"collapse": "折疊",
@ -1246,7 +1249,9 @@
},
"title": "網路搜尋"
},
"general.auto_check_update.title": "啟用自動更新檢查"
"general.auto_check_update.title": "啟用自動更新檢查",
"message_title.use_topic_naming.title": "使用話題命名模型為匯出的訊息建立標題",
"message_title.use_topic_naming.help": "開啟後使用話題命名模型為匯出的訊息建立標題。該項也會影響所有透過Markdown匯出的方式。"
},
"translate": {
"any.language": "任意語言",

View File

@ -198,7 +198,7 @@ const MessageMenubar: FC<Props> = (props) => {
key: 'image',
onClick: async () => {
const imageData = await captureScrollableDivAsDataURL(messageContainerRef)
const title = getMessageTitle(message)
const title = await getMessageTitle(message)
if (title && imageData) {
window.api.file.saveImage(title, imageData)
}
@ -211,14 +211,15 @@ const MessageMenubar: FC<Props> = (props) => {
key: 'word',
onClick: async () => {
const markdown = messageToMarkdown(message)
window.api.export.toWord(markdown, getMessageTitle(message))
const title = await getMessageTitle(message)
window.api.export.toWord(markdown, title)
}
},
{
label: t('chat.topics.export.notion'),
key: 'notion',
onClick: async () => {
const title = getMessageTitle(message)
const title = await getMessageTitle(message)
const markdown = messageToMarkdown(message)
exportMarkdownToNotion(title, markdown)
}
@ -227,7 +228,7 @@ const MessageMenubar: FC<Props> = (props) => {
label: t('chat.topics.export.yuque'),
key: 'yuque',
onClick: async () => {
const title = getMessageTitle(message)
const title = await getMessageTitle(message)
const markdown = messageToMarkdown(message)
exportMarkdownToYuque(title, markdown)
}
@ -245,7 +246,7 @@ const MessageMenubar: FC<Props> = (props) => {
label: t('chat.topics.export.joplin'),
key: 'joplin',
onClick: async () => {
const title = getMessageTitle(message)
const title = await getMessageTitle(message)
const markdown = messageToMarkdown(message)
exportMarkdownToJoplin(title, markdown)
}
@ -254,7 +255,7 @@ const MessageMenubar: FC<Props> = (props) => {
label: t('chat.topics.export.siyuan'),
key: 'siyuan',
onClick: async () => {
const title = getMessageTitle(message)
const title = await getMessageTitle(message)
const markdown = messageToMarkdown(message)
exportMarkdownToSiyuan(title, markdown)
}

View File

@ -2,7 +2,11 @@ import { DeleteOutlined, FolderOpenOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import { useTheme } from '@renderer/context/ThemeProvider'
import { RootState, useAppDispatch } from '@renderer/store'
import { setForceDollarMathInMarkdown, setmarkdownExportPath } from '@renderer/store/settings'
import {
setForceDollarMathInMarkdown,
setmarkdownExportPath,
setUseTopicNamingForMessageTitle
} from '@renderer/store/settings'
import { Button, Switch } from 'antd'
import Input from 'antd/es/input/Input'
import { FC } from 'react'
@ -18,6 +22,7 @@ const MarkdownExportSettings: FC = () => {
const markdownExportPath = useSelector((state: RootState) => state.settings.markdownExportPath)
const forceDollarMathInMarkdown = useSelector((state: RootState) => state.settings.forceDollarMathInMarkdown)
const useTopicNamingForMessageTitle = useSelector((state: RootState) => state.settings.useTopicNamingForMessageTitle)
const handleSelectFolder = async () => {
const path = await window.api.file.selectFolder()
@ -34,6 +39,10 @@ const MarkdownExportSettings: FC = () => {
dispatch(setForceDollarMathInMarkdown(checked))
}
const handleToggleTopicNaming = (checked: boolean) => {
dispatch(setUseTopicNamingForMessageTitle(checked))
}
return (
<SettingGroup theme={theme}>
<SettingTitle>{t('settings.data.markdown_export.title')}</SettingTitle>
@ -69,6 +78,14 @@ const MarkdownExportSettings: FC = () => {
<SettingRow>
<SettingHelpText>{t('settings.data.markdown_export.force_dollar_math.help')}</SettingHelpText>
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.data.message_title.use_topic_naming.title')}</SettingRowTitle>
<Switch checked={useTopicNamingForMessageTitle} onChange={handleToggleTopicNaming} />
</SettingRow>
<SettingRow>
<SettingHelpText>{t('settings.data.message_title.use_topic_naming.help')}</SettingHelpText>
</SettingRow>
</SettingGroup>
)
}

View File

@ -2,6 +2,7 @@ import SearchPopup from '@renderer/components/Popups/SearchPopup'
import { DEFAULT_CONTEXTCOUNT } from '@renderer/config/constant'
import { getTopicById } from '@renderer/hooks/useTopic'
import i18n from '@renderer/i18n'
import { fetchMessagesSummary } from '@renderer/services/ApiService'
import store from '@renderer/store'
import { Assistant, Message, Model, Topic } from '@renderer/types'
import { getTitleFromString, uuid } from '@renderer/utils'
@ -214,7 +215,22 @@ export function resetAssistantMessage(message: Message, model?: Model): Message
}
}
export function getMessageTitle(message: Message, length = 30) {
export async function getMessageTitle(message: Message, length = 30): Promise<string> {
// 检查 Redux 设置,若开启话题命名则调用 summaries 方法
if ((store.getState().settings as any).useTopicNamingForMessageTitle) {
try {
window.message.loading({ content: t('chat.topics.export.wait_for_title_naming'), key: 'message-title-naming' })
const title = await fetchMessagesSummary({ messages: [message], assistant: {} as Assistant })
if (title) {
window.message.success({ content: t('chat.topics.export.title_naming_success'), key: 'message-title-naming' })
return title
}
} catch (e) {
window.message.error({ content: t('chat.topics.export.title_naming_failed'), key: 'message-title-naming' })
console.error('Failed to generate title using topic naming, downgraded to default logic', e)
}
}
let title = getTitleFromString(message.content, length)
if (!title) {
@ -223,6 +239,7 @@ export function getMessageTitle(message: Message, length = 30) {
return title
}
export function checkRateLimit(assistant: Assistant): boolean {
const provider = getAssistantProvider(assistant)

View File

@ -85,6 +85,7 @@ export interface SettingsState {
notionPageNameKey: string | null
markdownExportPath: string | null
forceDollarMathInMarkdown: boolean
useTopicNamingForMessageTitle: boolean
thoughtAutoCollapse: boolean
notionAutoSplit: boolean
notionSplitSize: number
@ -167,6 +168,7 @@ const initialState: SettingsState = {
notionPageNameKey: 'Name',
markdownExportPath: null,
forceDollarMathInMarkdown: false,
useTopicNamingForMessageTitle: false,
thoughtAutoCollapse: true,
notionAutoSplit: false,
notionSplitSize: 90,
@ -372,6 +374,9 @@ const settingsSlice = createSlice({
setForceDollarMathInMarkdown: (state, action: PayloadAction<boolean>) => {
state.forceDollarMathInMarkdown = action.payload
},
setUseTopicNamingForMessageTitle: (state, action: PayloadAction<boolean>) => {
state.useTopicNamingForMessageTitle = action.payload
},
setThoughtAutoCollapse: (state, action: PayloadAction<boolean>) => {
state.thoughtAutoCollapse = action.payload
},
@ -483,6 +488,7 @@ export const {
setNotionPageNameKey,
setmarkdownExportPath,
setForceDollarMathInMarkdown,
setUseTopicNamingForMessageTitle,
setThoughtAutoCollapse,
setNotionAutoSplit,
setNotionSplitSize,

View File

@ -66,7 +66,8 @@ export const exportMessageAsMarkdown = async (message: Message) => {
const { markdownExportPath } = store.getState().settings
if (!markdownExportPath) {
try {
const fileName = removeSpecialCharactersForFileName(getMessageTitle(message)) + '.md'
const title = await getMessageTitle(message)
const fileName = removeSpecialCharactersForFileName(title) + '.md'
const markdown = messageToMarkdown(message)
const result = await window.api.file.save(fileName, markdown)
if (result) {
@ -81,7 +82,8 @@ export const exportMessageAsMarkdown = async (message: Message) => {
} else {
try {
const timestamp = dayjs().format('YYYY-MM-DD-HH-mm-ss')
const fileName = removeSpecialCharactersForFileName(getMessageTitle(message)) + ` ${timestamp}.md`
const title = await getMessageTitle(message)
const fileName = removeSpecialCharactersForFileName(title) + ` ${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' })