feat: more ai minapp
BIN
src/renderer/src/assets/images/apps/ai-search.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/renderer/src/assets/images/apps/devv.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
src/renderer/src/assets/images/apps/metaso.webp
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/renderer/src/assets/images/apps/sensetime.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
src/renderer/src/assets/images/apps/sparkdesk.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/renderer/src/assets/images/apps/tiangong.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/renderer/src/assets/images/apps/yuanbao.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
@ -227,6 +227,9 @@ const resources = {
|
|||||||
'keep_alive_time.placeholder': 'Minutes',
|
'keep_alive_time.placeholder': 'Minutes',
|
||||||
'keep_alive_time.description': 'The time in minutes to keep the connection alive, default is 5 minutes.'
|
'keep_alive_time.description': 'The time in minutes to keep the connection alive, default is 5 minutes.'
|
||||||
},
|
},
|
||||||
|
minapp: {
|
||||||
|
title: 'MinApp'
|
||||||
|
},
|
||||||
error: {
|
error: {
|
||||||
'chat.response': 'Something went wrong. Please check if you have set your API key in the Settings > Providers',
|
'chat.response': 'Something went wrong. Please check if you have set your API key in the Settings > Providers',
|
||||||
'backup.file_format': 'Backup file format error'
|
'backup.file_format': 'Backup file format error'
|
||||||
@ -462,6 +465,9 @@ const resources = {
|
|||||||
'keep_alive_time.placeholder': '分钟',
|
'keep_alive_time.placeholder': '分钟',
|
||||||
'keep_alive_time.description': '对话后模型在内存中保持的时间(默认:5分钟)'
|
'keep_alive_time.description': '对话后模型在内存中保持的时间(默认:5分钟)'
|
||||||
},
|
},
|
||||||
|
minapp: {
|
||||||
|
title: '小程序'
|
||||||
|
},
|
||||||
error: {
|
error: {
|
||||||
'chat.response': '出错了,如果没有配置 API 密钥,请前往设置 > 模型提供商中配置密钥',
|
'chat.response': '出错了,如果没有配置 API 密钥,请前往设置 > 模型提供商中配置密钥',
|
||||||
'backup.file_format': '备份文件格式错误'
|
'backup.file_format': '备份文件格式错误'
|
||||||
|
|||||||
@ -24,7 +24,7 @@ const App: FC<Props> = ({ app }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container onClick={onClick}>
|
<Container onClick={onClick}>
|
||||||
<AppIcon src={app.logo} style={{ border: theme === 'dark' ? 'none' : '1px solid var(--color-border' }} />
|
<AppIcon src={app.logo} style={{ border: theme === 'dark' ? 'none' : '0.5px solid var(--color-border' }} />
|
||||||
<AppTitle>{app.name}</AppTitle>
|
<AppTitle>{app.name}</AppTitle>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
@ -36,6 +36,7 @@ const Container = styled.div`
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
width: 65px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const AppIcon = styled.img`
|
const AppIcon = styled.img`
|
||||||
|
|||||||
@ -1,9 +1,20 @@
|
|||||||
|
import { SearchOutlined } from '@ant-design/icons'
|
||||||
import AiAssistantAppLogo from '@renderer/assets/images/apps/360-ai.png'
|
import AiAssistantAppLogo from '@renderer/assets/images/apps/360-ai.png'
|
||||||
|
import AiSearchAppLogo from '@renderer/assets/images/apps/ai-search.png'
|
||||||
import BaiduAiAppLogo from '@renderer/assets/images/apps/baidu-ai.png'
|
import BaiduAiAppLogo from '@renderer/assets/images/apps/baidu-ai.png'
|
||||||
|
import DevvAppLogo from '@renderer/assets/images/apps/devv.png'
|
||||||
|
import MetasoAppLogo from '@renderer/assets/images/apps/metaso.webp'
|
||||||
|
import SensetimeAppLogo from '@renderer/assets/images/apps/sensetime.png'
|
||||||
|
import SparkDeskAppLogo from '@renderer/assets/images/apps/sparkdesk.png'
|
||||||
|
import TiangongAiLogo from '@renderer/assets/images/apps/tiangong.png'
|
||||||
|
import TencentYuanbaoAppLogo from '@renderer/assets/images/apps/yuanbao.png'
|
||||||
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||||
|
import { Center } from '@renderer/components/Layout'
|
||||||
import { PROVIDER_CONFIG } from '@renderer/config/provider'
|
import { PROVIDER_CONFIG } from '@renderer/config/provider'
|
||||||
import { MinAppType } from '@renderer/types'
|
import { MinAppType } from '@renderer/types'
|
||||||
import { FC } from 'react'
|
import { Empty, Input } from 'antd'
|
||||||
|
import { isEmpty } from 'lodash'
|
||||||
|
import { FC, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -19,27 +30,87 @@ const _apps: MinAppType[] = [
|
|||||||
name: '文心一言',
|
name: '文心一言',
|
||||||
logo: BaiduAiAppLogo,
|
logo: BaiduAiAppLogo,
|
||||||
url: 'https://yiyan.baidu.com/'
|
url: 'https://yiyan.baidu.com/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'SparkDesk',
|
||||||
|
logo: SparkDeskAppLogo,
|
||||||
|
url: 'https://xinghuo.xfyun.cn/desk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '腾讯元宝',
|
||||||
|
logo: TencentYuanbaoAppLogo,
|
||||||
|
url: 'https://yuanbao.tencent.com/chat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '商量',
|
||||||
|
logo: SensetimeAppLogo,
|
||||||
|
url: 'https://chat.sensetime.com/wb/chat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '360AI搜索',
|
||||||
|
logo: AiSearchAppLogo,
|
||||||
|
url: 'https://so.360.com/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '秘塔AI搜索',
|
||||||
|
logo: MetasoAppLogo,
|
||||||
|
url: 'https://metaso.cn/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '天工AI',
|
||||||
|
logo: TiangongAiLogo,
|
||||||
|
url: 'https://www.tiangong.cn/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DEVV_',
|
||||||
|
logo: DevvAppLogo,
|
||||||
|
url: 'https://devv.ai/'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const AppsPage: FC = () => {
|
const AppsPage: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const [search, setSearch] = useState('')
|
||||||
|
|
||||||
const apps: MinAppType[] = (Object.entries(PROVIDER_CONFIG) as any[])
|
const list: MinAppType[] = (Object.entries(PROVIDER_CONFIG) as any[])
|
||||||
.filter(([, config]) => config.app)
|
.filter(([, config]) => config.app)
|
||||||
.map(([key, config]) => ({ id: key, ...config.app }))
|
.map(([key, config]) => ({ id: key, ...config.app }))
|
||||||
.concat(_apps)
|
.concat(_apps)
|
||||||
|
|
||||||
|
const apps = search
|
||||||
|
? list.filter(
|
||||||
|
(app) => app.name.toLowerCase().includes(search.toLowerCase()) || app.url.includes(search.toLowerCase())
|
||||||
|
)
|
||||||
|
: list
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Navbar>
|
<Navbar>
|
||||||
<NavbarCenter style={{ borderRight: 'none' }}>{t('agents.title')}</NavbarCenter>
|
<NavbarCenter style={{ borderRight: 'none', justifyContent: 'space-between' }}>
|
||||||
|
{t('minapp.title')}
|
||||||
|
<Input
|
||||||
|
placeholder={t('common.search')}
|
||||||
|
className="nodrag"
|
||||||
|
style={{ width: '30%', height: 28 }}
|
||||||
|
size="small"
|
||||||
|
variant="filled"
|
||||||
|
suffix={<SearchOutlined />}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
/>
|
||||||
|
<div style={{ width: 80 }} />
|
||||||
|
</NavbarCenter>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
<ContentContainer>
|
<ContentContainer>
|
||||||
<AppsContainer>
|
<AppsContainer>
|
||||||
{apps.map((app) => (
|
{apps.map((app) => (
|
||||||
<App key={app.name} app={app} />
|
<App key={app.name} app={app} />
|
||||||
))}
|
))}
|
||||||
|
{isEmpty(apps) && (
|
||||||
|
<Center style={{ flex: 1 }}>
|
||||||
|
<Empty />
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
</AppsContainer>
|
</AppsContainer>
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { GithubOutlined } from '@ant-design/icons'
|
|||||||
import { FileProtectOutlined, GlobalOutlined, MailOutlined, SoundOutlined } from '@ant-design/icons'
|
import { FileProtectOutlined, GlobalOutlined, MailOutlined, SoundOutlined } from '@ant-design/icons'
|
||||||
import Logo from '@renderer/assets/images/logo.png'
|
import Logo from '@renderer/assets/images/logo.png'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
import { HStack } from '@renderer/components/Layout'
|
||||||
|
import MinApp from '@renderer/components/MinApp'
|
||||||
import { runAsyncFunction } from '@renderer/utils'
|
import { runAsyncFunction } from '@renderer/utils'
|
||||||
import { Avatar, Button, Progress, Row, Tag } from 'antd'
|
import { Avatar, Button, Progress, Row, Tag } from 'antd'
|
||||||
import { ProgressInfo } from 'electron-updater'
|
import { ProgressInfo } from 'electron-updater'
|
||||||
@ -139,7 +140,14 @@ const AboutSettings: FC = () => {
|
|||||||
<SoundOutlined />
|
<SoundOutlined />
|
||||||
{t('settings.about.releases.title')}
|
{t('settings.about.releases.title')}
|
||||||
</SettingRowTitle>
|
</SettingRowTitle>
|
||||||
<Button onClick={() => onOpenWebsite('https://github.com/kangfenmao/cherry-studio/releases')}>
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
MinApp.start({
|
||||||
|
name: t('settings.about.releases.title'),
|
||||||
|
url: 'https://github.com/kangfenmao/cherry-studio/releases',
|
||||||
|
logo: ''
|
||||||
|
})
|
||||||
|
}>
|
||||||
{t('settings.about.releases.button')}
|
{t('settings.about.releases.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { FolderOpenOutlined, SaveOutlined } from '@ant-design/icons'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
import { HStack } from '@renderer/components/Layout'
|
||||||
import useAvatar from '@renderer/hooks/useAvatar'
|
import useAvatar from '@renderer/hooks/useAvatar'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
@ -117,8 +118,12 @@ const GeneralSettings: FC = () => {
|
|||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
|
<SettingRowTitle>{t('settings.general.backup.title')}</SettingRowTitle>
|
||||||
<HStack gap="5px">
|
<HStack gap="5px">
|
||||||
<Button onClick={backup}>备份</Button>
|
<Button onClick={backup} icon={<SaveOutlined />}>
|
||||||
<Button onClick={restore}>恢复</Button>
|
备份
|
||||||
|
</Button>
|
||||||
|
<Button onClick={restore} icon={<FolderOpenOutlined />}>
|
||||||
|
恢复
|
||||||
|
</Button>
|
||||||
</HStack>
|
</HStack>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
|||||||
@ -182,11 +182,10 @@ const ProviderListItem = styled.div`
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-primary-mute);
|
background: var(--color-background-soft);
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
background: var(--color-primary);
|
background: var(--color-background-mute);
|
||||||
color: var(--color-white);
|
|
||||||
font-weight: bold !important;
|
font-weight: bold !important;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -118,11 +118,10 @@ const MenuItem = styled.li`
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-primary-soft);
|
background: var(--color-background-soft);
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
background: var(--color-primary);
|
background: var(--color-background-mute);
|
||||||
color: var(--color-white);
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||