Merge branch 'main' into develop

# Conflicts:
#	src/renderer/src/providers/AiProvider/OpenAIProvider.ts
#	src/renderer/src/providers/AiProvider/OpenAIResponseProvider.ts
This commit is contained in:
kangfenmao 2025-05-13 20:53:23 +08:00
commit 8bd38ccd86
3 changed files with 49 additions and 27 deletions

View File

@ -1,6 +1,6 @@
{
"name": "CherryStudio",
"version": "1.3.0",
"version": "1.3.1",
"private": true,
"description": "A powerful AI assistant for producer.",
"main": "./out/main/index.js",

View File

@ -1,6 +1,6 @@
import 'emoji-picker-element'
import { CheckOutlined, LoadingOutlined, ThunderboltOutlined } from '@ant-design/icons'
import { CheckOutlined, LoadingOutlined, ThunderboltOutlined, RollbackOutlined } from '@ant-design/icons'
import EmojiPicker from '@renderer/components/EmojiPicker'
import { TopView } from '@renderer/components/TopView'
import { AGENT_PROMPT } from '@renderer/config/prompts'
@ -38,6 +38,8 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
const formRef = useRef<FormInstance>(null)
const [emoji, setEmoji] = useState('')
const [loading, setLoading] = useState(false)
const [showUndoButton, setShowUndoButton] = useState(false)
const [originalPrompt, setOriginalPrompt] = useState('')
const [tokenCount, setTokenCount] = useState(0)
const knowledgeState = useAppSelector((state) => state.knowledge)
const showKnowledgeIcon = useSidebarIconShow('knowledge')
@ -98,7 +100,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
resolve(null)
}
const handleButtonClick = async () => {
const handleGenerateButtonClick = async () => {
const name = formRef.current?.getFieldValue('name')
const content = formRef.current?.getFieldValue('prompt')
const promptText = content || name
@ -112,6 +114,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
}
setLoading(true)
setShowUndoButton(false)
try {
const generatedText = await fetchGenerate({
@ -119,6 +122,8 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
content: promptText
})
form.setFieldsValue({ prompt: generatedText })
setShowUndoButton(true)
setOriginalPrompt(content)
} catch (error) {
console.error('Error fetching data:', error)
}
@ -126,6 +131,11 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
setLoading(false)
}
const handleUndoButtonClick = async () => {
form.setFieldsValue({ prompt: originalPrompt })
setShowUndoButton(false)
}
// Compute label width based on the longest label
const labelWidth = [t('agents.add.name'), t('agents.add.prompt'), t('agents.add.knowledge_base')]
.map((labelText) => stringWidth(labelText) * 8)
@ -155,6 +165,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
if (changedValues.prompt) {
const count = await estimateTextTokens(changedValues.prompt)
setTokenCount(count)
setShowUndoButton(false)
}
}}>
<Form.Item name="name" label="Emoji">
@ -176,10 +187,15 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
<TokenCount>Tokens: {tokenCount}</TokenCount>
<Button
icon={loading ? <LoadingOutlined /> : <ThunderboltOutlined />}
onClick={handleButtonClick}
onClick={handleGenerateButtonClick}
style={{ position: 'absolute', top: 8, right: 8 }}
disabled={loading}
/>
{showUndoButton && <Button
icon={<RollbackOutlined />}
onClick={handleUndoButtonClick}
style={{ position: 'absolute', top: 8, right: 48 }}
/>}
</div>
{showKnowledgeIcon && (
<Form.Item name="knowledge_base_ids" label={t('agents.add.knowledge_base')} rules={[{ required: false }]}>

View File

@ -50,29 +50,34 @@ const WebSearchButton: FC<Props> = ({ ref, assistant, ToolbarButton }) => {
const providerItems = useMemo<QuickPanelListItem[]>(() => {
const isWebSearchModelEnabled = assistant.model && isWebSearchModel(assistant.model)
const items: QuickPanelListItem[] = providers.map((p) => ({
label: p.name,
description: WebSearchService.isWebSearchEnabled(p.id)
? hasObjectKey(p, 'apiKey')
? t('settings.websearch.apikey')
: t('settings.websearch.free')
: t('chat.input.web_search.enable_content'),
icon: <Globe />,
isSelected: p.id === assistant?.webSearchProviderId,
disabled: !WebSearchService.isWebSearchEnabled(p.id),
action: () => updateSelectedWebSearchProvider(p.id)
}))
const items: QuickPanelListItem[] = providers
.map((p) => ({
label: p.name,
description: WebSearchService.isWebSearchEnabled(p.id)
? hasObjectKey(p, 'apiKey')
? t('settings.websearch.apikey')
: t('settings.websearch.free')
: t('chat.input.web_search.enable_content'),
icon: <Globe />,
isSelected: p.id === assistant?.webSearchProviderId,
disabled: !WebSearchService.isWebSearchEnabled(p.id),
action: () => updateSelectedWebSearchProvider(p.id)
}))
.filter((o) => !o.disabled)
if (isWebSearchModelEnabled) {
items.unshift({
label: t('chat.input.web_search.builtin'),
description: isWebSearchModelEnabled
? t('chat.input.web_search.builtin.enabled_content')
: t('chat.input.web_search.builtin.disabled_content'),
icon: <Globe />,
isSelected: assistant.enableWebSearch,
disabled: !isWebSearchModelEnabled,
action: () => updateSelectedWebSearchBuiltin()
})
}
items.unshift({
label: t('chat.input.web_search.builtin'),
description: isWebSearchModelEnabled
? t('chat.input.web_search.builtin.enabled_content')
: t('chat.input.web_search.builtin.disabled_content'),
icon: <Globe />,
isSelected: assistant.enableWebSearch,
disabled: !isWebSearchModelEnabled,
action: () => updateSelectedWebSearchBuiltin()
})
items.push({
label: '前往设置' + '...',
icon: <Settings />,
@ -105,7 +110,8 @@ const WebSearchButton: FC<Props> = ({ ref, assistant, ToolbarButton }) => {
quickPanel.open({
title: t('chat.input.web_search'),
list: providerItems,
symbol: '?'
symbol: '?',
pageSize: 9
})
}, [quickPanel, providerItems, t])