diff --git a/lingtropy-client/src/main/IPCs.ts b/lingtropy-client/src/main/IPCs.ts index 0e72347..d9f5df6 100644 --- a/lingtropy-client/src/main/IPCs.ts +++ b/lingtropy-client/src/main/IPCs.ts @@ -114,6 +114,58 @@ export default class IPCs { } }) + ipcMain.handle( + 'call-openai-title', + async (event, baseUrl: string, apiKey: string, model: string, count: number, text: string) => { + try { + const client = new OpenAI({ + baseURL: baseUrl, + apiKey: apiKey, + maxRetries: 2, + timeout: 30000 + }) + + // 创建 count 个请求 + const requests = Array.from({ length: count }, (_, index) => { + return client.chat.completions + .create({ + model: model, + messages: [ + { + role: 'system', + content: '你是一个小红书标题写手,能够熟练地根据用户的输入,改写成内容相近,但表达方式不同的新标题。你的标题中需要具备吸人眼球的钩子,能够牢牢抓住用户的注意力。请直接输出新的标题,不要输出其他任何提示性词语, 以纯文本的形式输出' + }, + { role: 'user', content: text } + ], + max_tokens: 100, + temperature: 0.8, + stream: true + }) + .then(async (stream) => { + let fullResponse = '' + for await (const chunk of stream) { + const content = chunk.choices[0].delta.content || '' + fullResponse += content + // 实时发送每个请求的部分结果 + event.sender.send('openai-partial-response', { index, content }) + } + // 返回最终结果 + return { index, response: fullResponse.trim() } + }) + }) + + // 并发执行所有请求 + const results = await Promise.all(requests) + + // 返回所有请求的最终结果 + return results + } catch (error) { + console.error('生成标题失败:', error) + throw error + } + } + ) + ipcMain.handle('get-api-key', () => { return store.get('api-key') || null }) @@ -145,5 +197,7 @@ export default class IPCs { }) return dialogResult }) + + } } diff --git a/lingtropy-client/src/preload/index.ts b/lingtropy-client/src/preload/index.ts index df31b33..d9b6b13 100644 --- a/lingtropy-client/src/preload/index.ts +++ b/lingtropy-client/src/preload/index.ts @@ -12,7 +12,8 @@ const mainAvailChannels: string[] = [ 'call-openai', 'openai-partial-response', 'get-api-key', - 'set-api-key' + 'set-api-key', + 'call-openai-title' ] const rendererAvailChannels: string[] = ['openai-partial-response', 'get-api-key', 'set-api-key'] diff --git a/lingtropy-client/src/renderer/components/InputSection.vue b/lingtropy-client/src/renderer/components/InputSection.vue index 75e6df2..9267b42 100644 --- a/lingtropy-client/src/renderer/components/InputSection.vue +++ b/lingtropy-client/src/renderer/components/InputSection.vue @@ -66,10 +66,24 @@ > - +
+ + +
@@ -79,11 +93,14 @@ import { ARTICLE_MAX_COUNT } from '../constants/constants' import HeaderComponent from './HeaderComponent.vue' import SelectModel from './SelectModelComponent.vue' -// 使用解构直接获取 isGenerating -const { isGenerating } = defineProps({ +const { isGenerating, isGeneratingTitle } = defineProps({ isGenerating: { type: Boolean, default: false + }, + isGeneratingTitle: { + type: Boolean, + default: false } }) @@ -108,11 +125,16 @@ watch(currentModel, (newValue) => { }) const validateInput = () => { + if (!originalText.value.trim()) { + return false + } + if (generationCount.value < 1) { setGenerationCount(1) } else if (generationCount.value > ARTICLE_MAX_COUNT) { setGenerationCount(ARTICLE_MAX_COUNT) } + return true } const setGenerationCount = async (value) => { @@ -138,20 +160,38 @@ const decrementCount = () => { } } -const handleRewrite = () => { - if (!originalText.value.trim()) { - // 可以通过 emit 发送错误消息给父组件显示 +const handleRewrite = async (type) => { + if (!validateInput()) { + showToast('请输入需要改写的文本') return } - + emit('rewrite', { mode: mode.value, text: originalText.value, count: mode.value === 'single' ? 1 : generationCount.value, model: currentModel.value, - key: currentKey.value + key: currentKey.value, + type }) } + +const showToast = (message) => { + const toast = document.createElement('div') + toast.className = 'toast-message' + toast.textContent = message + document.body.appendChild(toast) + + setTimeout(() => { + toast.classList.add('show') + setTimeout(() => { + toast.classList.remove('show') + setTimeout(() => { + document.body.removeChild(toast) + }, 300) + }, 2000) + }, 10) +}