feat: more ai minapp

This commit is contained in:
kangfenmao 2024-08-22 18:45:06 +08:00
parent b88f4a869e
commit b131d320ea
14 changed files with 102 additions and 13 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -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': '备份文件格式错误'

View File

@ -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`

View File

@ -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>

View File

@ -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>

View File

@ -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 />

View File

@ -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;
} }
` `

View File

@ -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);
} }
` `