feat: add pause icon to pause chat completion
This commit is contained in:
parent
a97d6f024b
commit
e8bdf9d5fd
@ -39,7 +39,8 @@ const resources = {
|
||||
'error.enter.api.host': 'Please enter your API host first',
|
||||
'error.enter.model': 'Please select a model first',
|
||||
'api.connection.failed': 'Connection failed',
|
||||
'api.connection.success': 'Connection successful'
|
||||
'api.connection.success': 'Connection successful',
|
||||
'chat.completion.paused': 'Chat completion paused'
|
||||
},
|
||||
assistant: {
|
||||
'default.name': 'Default Assistant',
|
||||
@ -61,7 +62,8 @@ const resources = {
|
||||
'input.clear.title': 'Clear all messages?',
|
||||
'input.clear.content': 'Are you sure to clear all messages?',
|
||||
'input.placeholder': 'Type your message here...',
|
||||
'input.send': 'Send'
|
||||
'input.send': 'Send',
|
||||
'input.pause': 'Pause'
|
||||
},
|
||||
apps: {
|
||||
title: 'Agents'
|
||||
@ -146,7 +148,8 @@ const resources = {
|
||||
'error.enter.api.host': '请输入您的 API 地址',
|
||||
'error.enter.model': '请选择一个模型',
|
||||
'api.connection.failed': '连接失败',
|
||||
'api.connection.successful': '连接成功'
|
||||
'api.connection.successful': '连接成功',
|
||||
'chat.completion.paused': '会话已停止'
|
||||
},
|
||||
assistant: {
|
||||
'default.name': '默认助手',
|
||||
@ -168,7 +171,8 @@ const resources = {
|
||||
'input.clear.title': '清除所有消息?',
|
||||
'input.clear.content': '确定要清除所有消息吗?',
|
||||
'input.placeholder': '在这里输入消息...',
|
||||
'input.send': '发送'
|
||||
'input.send': '发送',
|
||||
'input.pause': '暂停'
|
||||
},
|
||||
apps: {
|
||||
title: '智能体'
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
FullscreenExitOutlined,
|
||||
FullscreenOutlined,
|
||||
HistoryOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlusCircleOutlined
|
||||
} from '@ant-design/icons'
|
||||
import TextArea, { TextAreaRef } from 'antd/es/input/TextArea'
|
||||
@ -19,9 +20,10 @@ import { isEmpty } from 'lodash'
|
||||
import SendMessageSetting from './SendMessageSetting'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import dayjs from 'dayjs'
|
||||
import { useAppSelector } from '@renderer/store'
|
||||
import store, { useAppSelector } from '@renderer/store'
|
||||
import { getDefaultTopic } from '@renderer/services/assistant'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { setGenerating } from '@renderer/store/runtime'
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
@ -86,6 +88,11 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
|
||||
const clearTopic = () => EventEmitter.emit(EVENT_NAMES.CLEAR_MESSAGES)
|
||||
|
||||
const onPause = () => {
|
||||
window.keyv.set(EVENT_NAMES.CHAT_COMPLETION_PAUSED, true)
|
||||
store.dispatch(setGenerating(false))
|
||||
}
|
||||
|
||||
// Command or Ctrl + N create new topic
|
||||
useEffect(() => {
|
||||
const onKeydown = (e) => {
|
||||
@ -148,6 +155,13 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
</Tooltip>
|
||||
</ToolbarMenu>
|
||||
<ToolbarMenu>
|
||||
{generating && (
|
||||
<Tooltip placement="top" title={t('assistant.input.pause')} arrow>
|
||||
<ToolbarButton type="text" onClick={onPause}>
|
||||
<PauseCircleOutlined />
|
||||
</ToolbarButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<SendMessageSetting>
|
||||
<ToolbarButton type="text" style={{ marginRight: 0 }}>
|
||||
<MoreOutlined />
|
||||
|
||||
@ -12,6 +12,7 @@ import Logo from '@renderer/assets/images/logo.png'
|
||||
import { SyncOutlined } from '@ant-design/icons'
|
||||
import { firstLetter } from '@renderer/utils'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { isEmpty } from 'lodash'
|
||||
|
||||
interface Props {
|
||||
message: Message
|
||||
@ -53,6 +54,13 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.REGENERATE_MESSAGE), 100)
|
||||
}
|
||||
|
||||
const getMessageContent = (message: Message) => {
|
||||
if (isEmpty(message.content) && message.status === 'paused') {
|
||||
return t('message.chat.completion.paused')
|
||||
}
|
||||
return message.content
|
||||
}
|
||||
|
||||
return (
|
||||
<MessageContainer key={message.id}>
|
||||
<AvatarWrapper>
|
||||
@ -72,7 +80,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
|
||||
)}
|
||||
{message.status !== 'sending' && (
|
||||
<Markdown className="markdown" components={{ code: CodeBlock as any }}>
|
||||
{message.content}
|
||||
{getMessageContent(message)}
|
||||
</Markdown>
|
||||
)}
|
||||
{showMenu && (
|
||||
|
||||
@ -27,6 +27,8 @@ const getOpenAiProvider = (provider: Provider) => {
|
||||
}
|
||||
|
||||
export async function fetchChatCompletion({ messages, topic, assistant, onResponse }: FetchChatCompletionParams) {
|
||||
window.keyv.set(EVENT_NAMES.CHAT_COMPLETION_PAUSED, false)
|
||||
|
||||
const provider = getAssistantProvider(assistant)
|
||||
const openaiProvider = getOpenAiProvider(provider)
|
||||
const defaultModel = getDefaultModel()
|
||||
@ -34,7 +36,7 @@ export async function fetchChatCompletion({ messages, topic, assistant, onRespon
|
||||
|
||||
store.dispatch(setGenerating(true))
|
||||
|
||||
const _message: Message = {
|
||||
const message: Message = {
|
||||
id: uuid(),
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
@ -45,7 +47,7 @@ export async function fetchChatCompletion({ messages, topic, assistant, onRespon
|
||||
status: 'sending'
|
||||
}
|
||||
|
||||
onResponse({ ..._message })
|
||||
onResponse({ ...message })
|
||||
|
||||
const systemMessage = assistant.prompt ? { role: 'system', content: assistant.prompt } : undefined
|
||||
|
||||
@ -54,12 +56,10 @@ export async function fetchChatCompletion({ messages, topic, assistant, onRespon
|
||||
content: message.content
|
||||
}))
|
||||
|
||||
const _messages = [systemMessage, ...userMessages].filter(Boolean) as ChatCompletionMessageParam[]
|
||||
|
||||
try {
|
||||
const stream = await openaiProvider.chat.completions.create({
|
||||
model: model.id,
|
||||
messages: _messages,
|
||||
messages: [systemMessage, ...userMessages].filter(Boolean) as ChatCompletionMessageParam[],
|
||||
stream: true
|
||||
})
|
||||
|
||||
@ -67,22 +67,27 @@ export async function fetchChatCompletion({ messages, topic, assistant, onRespon
|
||||
let usage: OpenAI.Completions.CompletionUsage | undefined = undefined
|
||||
|
||||
for await (const chunk of stream) {
|
||||
if (window.keyv.get(EVENT_NAMES.CHAT_COMPLETION_PAUSED)) {
|
||||
break
|
||||
}
|
||||
|
||||
content = content + (chunk.choices[0]?.delta?.content || '')
|
||||
chunk.usage && (usage = chunk.usage)
|
||||
onResponse({ ..._message, content, status: 'pending' })
|
||||
onResponse({ ...message, content, status: 'pending' })
|
||||
}
|
||||
|
||||
_message.content = content
|
||||
_message.usage = usage
|
||||
message.content = content
|
||||
message.usage = usage
|
||||
} catch (error: any) {
|
||||
_message.content = `Error: ${error.message}`
|
||||
message.content = `Error: ${error.message}`
|
||||
}
|
||||
|
||||
_message.status = 'success'
|
||||
EventEmitter.emit(EVENT_NAMES.AI_CHAT_COMPLETION, _message)
|
||||
const paused = window.keyv.get(EVENT_NAMES.CHAT_COMPLETION_PAUSED)
|
||||
message.status = paused ? 'paused' : 'success'
|
||||
EventEmitter.emit(EVENT_NAMES.AI_CHAT_COMPLETION, message)
|
||||
store.dispatch(setGenerating(false))
|
||||
|
||||
return _message
|
||||
return message
|
||||
}
|
||||
|
||||
interface FetchMessagesSummaryParams {
|
||||
|
||||
@ -9,5 +9,6 @@ export const EVENT_NAMES = {
|
||||
CLEAR_MESSAGES: 'CLEAR_MESSAGES',
|
||||
ADD_ASSISTANT: 'ADD_ASSISTANT',
|
||||
EDIT_MESSAGE: 'EDIT_MESSAGE',
|
||||
REGENERATE_MESSAGE: 'REGENERATE_MESSAGE'
|
||||
REGENERATE_MESSAGE: 'REGENERATE_MESSAGE',
|
||||
CHAT_COMPLETION_PAUSED: 'CHAT_COMPLETION_PAUSED'
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ export type Message = {
|
||||
topicId: string
|
||||
modelId?: string
|
||||
createdAt: string
|
||||
status: 'sending' | 'pending' | 'success' | 'error'
|
||||
status: 'sending' | 'pending' | 'success' | 'paused' | 'error'
|
||||
usage?: OpenAI.Completions.CompletionUsage
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user