feat: add provider and model image
BIN
src/renderer/src/assets/images/models/chatglm.jpeg
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
3
src/renderer/src/assets/images/models/chatgpt.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg viewBox='0 0 320 320' xmlns='http://www.w3.org/2000/svg'>
|
||||||
|
<path d='m297.06 130.97c7.26-21.79 4.76-45.66-6.85-65.48-17.46-30.4-52.56-46.04-86.84-38.68-15.25-17.18-37.16-26.95-60.13-26.81-35.04-.08-66.13 22.48-76.91 55.82-22.51 4.61-41.94 18.7-53.31 38.67-17.59 30.32-13.58 68.54 9.92 94.54-7.26 21.79-4.76 45.66 6.85 65.48 17.46 30.4 52.56 46.04 86.84 38.68 15.24 17.18 37.16 26.95 60.13 26.8 35.06.09 66.16-22.49 76.94-55.86 22.51-4.61 41.94-18.7 53.31-38.67 17.57-30.32 13.55-68.51-9.94-94.51zm-120.28 168.11c-14.03.02-27.62-4.89-38.39-13.88.49-.26 1.34-.73 1.89-1.07l63.72-36.8c3.26-1.85 5.26-5.32 5.24-9.07v-89.83l26.93 15.55c.29.14.48.42.52.74v74.39c-.04 33.08-26.83 59.9-59.91 59.97zm-128.84-55.03c-7.03-12.14-9.56-26.37-7.15-40.18.47.28 1.3.79 1.89 1.13l63.72 36.8c3.23 1.89 7.23 1.89 10.47 0l77.79-44.92v31.1c.02.32-.13.63-.38.83l-64.41 37.19c-28.69 16.52-65.33 6.7-81.92-21.95zm-16.77-139.09c7-12.16 18.05-21.46 31.21-26.29 0 .55-.03 1.52-.03 2.2v73.61c-.02 3.74 1.98 7.21 5.23 9.06l77.79 44.91-26.93 15.55c-.27.18-.61.21-.91.08l-64.42-37.22c-28.63-16.58-38.45-53.21-21.95-81.89zm221.26 51.49-77.79-44.92 26.93-15.54c.27-.18.61-.21.91-.08l64.42 37.19c28.68 16.57 38.51 53.26 21.94 81.94-7.01 12.14-18.05 21.44-31.2 26.28v-75.81c.03-3.74-1.96-7.2-5.2-9.06zm26.8-40.34c-.47-.29-1.3-.79-1.89-1.13l-63.72-36.8c-3.23-1.89-7.23-1.89-10.47 0l-77.79 44.92v-31.1c-.02-.32.13-.63.38-.83l64.41-37.16c28.69-16.55 65.37-6.7 81.91 22 6.99 12.12 9.52 26.31 7.15 40.1zm-168.51 55.43-26.94-15.55c-.29-.14-.48-.42-.52-.74v-74.39c.02-33.12 26.89-59.96 60.01-59.94 14.01 0 27.57 4.92 38.34 13.88-.49.26-1.33.73-1.89 1.07l-63.72 36.8c-3.26 1.85-5.26 5.31-5.24 9.06l-.04 89.79zm14.63-31.54 34.65-20.01 34.65 20v40.01l-34.65 20-34.65-20z'/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/renderer/src/assets/images/models/deepseek.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
src/renderer/src/assets/images/models/gemma.jpeg
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/renderer/src/assets/images/models/llama.jpeg
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
src/renderer/src/assets/images/models/mixtral.jpeg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src/renderer/src/assets/images/models/qwen.jpeg
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
7
src/renderer/src/assets/images/models/yi.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="300" cy="300" r="300" fill="white"/>
|
||||||
|
<rect x="409.733" y="340.032" width="42.3862" height="151.648" rx="21.1931" fill="#003425"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M422.005 133.354C413.089 125.771 399.714 126.851 392.131 135.768L273.699 275.021C270.643 278.614 268.994 282.932 268.698 287.302C268.532 288.371 268.446 289.466 268.446 290.581V468.603C268.446 480.308 277.934 489.796 289.639 489.796C301.344 489.796 310.832 480.308 310.832 468.603V296.784L424.419 163.228C432.002 154.312 430.921 140.937 422.005 133.354Z" fill="#003425"/>
|
||||||
|
<rect x="113.972" y="134.25" width="42.3862" height="174.745" rx="21.1931" transform="rotate(-39.3441 113.972 134.25)" fill="#003425"/>
|
||||||
|
<circle cx="460.126" cy="279.278" r="25.9027" fill="#00DD20"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 869 B |
BIN
src/renderer/src/assets/images/providers/deepseek.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
src/renderer/src/assets/images/providers/groq.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/renderer/src/assets/images/providers/openai.jpeg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/renderer/src/assets/images/providers/silicon.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
7
src/renderer/src/assets/images/providers/yi.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="300" cy="300" r="300" fill="#003425"/>
|
||||||
|
<rect x="409.733" y="340.031" width="42.3862" height="151.648" rx="21.1931" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M422.005 133.354C413.089 125.771 399.714 126.851 392.131 135.767L273.699 275.021C270.643 278.614 268.994 282.932 268.698 287.302C268.532 288.371 268.446 289.466 268.446 290.581V468.603C268.446 480.308 277.934 489.796 289.639 489.796C301.344 489.796 310.832 480.308 310.832 468.603V296.784L424.419 163.228C432.002 154.312 430.921 140.937 422.005 133.354Z" fill="white"/>
|
||||||
|
<rect x="113.972" y="134.25" width="42.3862" height="174.745" rx="21.1931" transform="rotate(-39.3441 113.972 134.25)" fill="white"/>
|
||||||
|
<circle cx="460.126" cy="279.278" r="25.9027" fill="#00FF25"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 865 B |
@ -94,3 +94,7 @@ body,
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#inputbar .ant-input {
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|||||||
@ -100,7 +100,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
}, [assistant])
|
}, [assistant])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container id="inputbar">
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarMenu>
|
<ToolbarMenu>
|
||||||
<Tooltip placement="top" title=" New Chat " arrow>
|
<Tooltip placement="top" title=" New Chat " arrow>
|
||||||
@ -144,7 +144,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
autoFocus
|
autoFocus
|
||||||
contextMenu="true"
|
contextMenu="true"
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
styles={{ textarea: { resize: 'none', paddingLeft: 0 } }}
|
styles={{ textarea: { paddingLeft: 0 } }}
|
||||||
allowClear
|
allowClear
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -2,12 +2,13 @@ import { Message } from '@renderer/types'
|
|||||||
import { Avatar, Tooltip } from 'antd'
|
import { Avatar, Tooltip } from 'antd'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import Logo from '@renderer/assets/images/logo.png'
|
|
||||||
import useAvatar from '@renderer/hooks/useAvatar'
|
import useAvatar from '@renderer/hooks/useAvatar'
|
||||||
import { CopyOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
import { CopyOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||||
import Markdown from 'react-markdown'
|
import Markdown from 'react-markdown'
|
||||||
import CodeBlock from './CodeBlock'
|
import CodeBlock from './CodeBlock'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||||
|
import { getModelLogo } from '@renderer/services/provider'
|
||||||
|
import Logo from '@renderer/assets/images/logo.png'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
message: Message
|
message: Message
|
||||||
@ -40,7 +41,13 @@ const MessageItem: FC<Props> = ({ message, showMenu, onDeleteMessage }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MessageContainer key={message.id}>
|
<MessageContainer key={message.id}>
|
||||||
<AvatarWrapper>{message.role === 'assistant' ? <Avatar src={Logo} /> : <Avatar src={avatar} />}</AvatarWrapper>
|
<AvatarWrapper>
|
||||||
|
{message.role === 'assistant' ? (
|
||||||
|
<Avatar src={message.modelId ? getModelLogo(message.modelId) : Logo} />
|
||||||
|
) : (
|
||||||
|
<Avatar src={avatar} />
|
||||||
|
)}
|
||||||
|
</AvatarWrapper>
|
||||||
<MessageContent>
|
<MessageContent>
|
||||||
<Markdown className="markdown" components={{ code: CodeBlock as any }}>
|
<Markdown className="markdown" components={{ code: CodeBlock as any }}>
|
||||||
{message.content}
|
{message.content}
|
||||||
|
|||||||
@ -16,7 +16,10 @@ const ModelSettings: FC = () => {
|
|||||||
.map((p) => ({
|
.map((p) => ({
|
||||||
label: p.name,
|
label: p.name,
|
||||||
title: p.name,
|
title: p.name,
|
||||||
options: p.models.map((m) => ({ label: m.name, value: m.id }))
|
options: p.models.map((m) => ({
|
||||||
|
label: m.name,
|
||||||
|
value: m.id
|
||||||
|
}))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { Provider } from '@renderer/types'
|
|||||||
import { FC, useState } from 'react'
|
import { FC, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import ModalProviderSetting from './components/ModalProviderSetting'
|
import ModalProviderSetting from './components/ModalProviderSetting'
|
||||||
|
import { Avatar } from 'antd'
|
||||||
|
import { getProviderLogo } from '@renderer/services/provider'
|
||||||
|
|
||||||
const ProviderSettings: FC = () => {
|
const ProviderSettings: FC = () => {
|
||||||
const providers = useSystemProviders()
|
const providers = useSystemProviders()
|
||||||
@ -16,7 +18,8 @@ const ProviderSettings: FC = () => {
|
|||||||
key={JSON.stringify(provider)}
|
key={JSON.stringify(provider)}
|
||||||
className={provider.id === selectedProvider?.id ? 'active' : ''}
|
className={provider.id === selectedProvider?.id ? 'active' : ''}
|
||||||
onClick={() => setSelectedProvider(provider)}>
|
onClick={() => setSelectedProvider(provider)}>
|
||||||
{provider.name}
|
<Avatar src={getProviderLogo(provider.id)} size={22} />
|
||||||
|
<ProviderItemName>{provider.name}</ProviderItemName>
|
||||||
</ProviderListItem>
|
</ProviderListItem>
|
||||||
))}
|
))}
|
||||||
</ProviderListContainer>
|
</ProviderListContainer>
|
||||||
@ -60,4 +63,9 @@ const ProviderListItem = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const ProviderItemName = styled.div`
|
||||||
|
margin-left: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
`
|
||||||
|
|
||||||
export default ProviderSettings
|
export default ProviderSettings
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { Provider } from '@renderer/types'
|
import { Provider } from '@renderer/types'
|
||||||
import { FC, useEffect, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Button, Card, Divider, Input } from 'antd'
|
import { Avatar, Button, Card, Divider, Input } from 'antd'
|
||||||
import { useProvider } from '@renderer/hooks/useProvider'
|
import { useProvider } from '@renderer/hooks/useProvider'
|
||||||
import ModalListPopup from '@renderer/components/Popups/ModalListPopup'
|
import ModalListPopup from '@renderer/components/Popups/ModalListPopup'
|
||||||
import { groupBy } from 'lodash'
|
import { groupBy } from 'lodash'
|
||||||
import { SettingContainer, SettingSubtitle, SettingTitle } from './SettingComponent'
|
import { SettingContainer, SettingSubtitle, SettingTitle } from './SettingComponent'
|
||||||
|
import { getModelLogo } from '@renderer/services/provider'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
provider: Provider
|
provider: Provider
|
||||||
@ -58,7 +59,10 @@ const ModalProviderSetting: FC<Props> = ({ provider }) => {
|
|||||||
{Object.keys(modelGroups).map((group) => (
|
{Object.keys(modelGroups).map((group) => (
|
||||||
<Card key={group} type="inner" title={group} style={{ marginBottom: '10px' }} size="small">
|
<Card key={group} type="inner" title={group} style={{ marginBottom: '10px' }} size="small">
|
||||||
{modelGroups[group].map((model) => (
|
{modelGroups[group].map((model) => (
|
||||||
<ModelListItem key={model.id}>{model.id}</ModelListItem>
|
<ModelListItem key={model.id}>
|
||||||
|
<Avatar src={getModelLogo(model.id)} size={22} style={{ marginRight: '8px' }} />
|
||||||
|
{model.id}
|
||||||
|
</ModelListItem>
|
||||||
))}
|
))}
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
@ -73,7 +77,7 @@ const ModelListItem = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: flex-start;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export const SettingTitle = styled.div`
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
font-weight: 900;
|
||||||
`
|
`
|
||||||
|
|
||||||
export const SettingSubtitle = styled.div`
|
export const SettingSubtitle = styled.div`
|
||||||
|
|||||||
@ -34,7 +34,14 @@ export function getAssistantProvider(assistant: Assistant) {
|
|||||||
return provider || getDefaultProvider()
|
return provider || getDefaultProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProviderByModel(model: Model) {
|
export function getProviderByModel(model?: Model) {
|
||||||
const providers = store.getState().llm.providers
|
const providers = store.getState().llm.providers
|
||||||
return providers.find((p) => p.id === model.provider) as Provider
|
const providerId = model ? model.provider : getDefaultProvider().id
|
||||||
|
return providers.find((p) => p.id === providerId) as Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProviderByModelId(modelId?: string) {
|
||||||
|
const providers = store.getState().llm.providers
|
||||||
|
const _modelId = modelId || getDefaultModel().id
|
||||||
|
return providers.find((p) => p.models.find((m) => m.id === _modelId)) as Provider
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/renderer/src/services/provider.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import OpenAiProviderLogo from '@renderer/assets/images/providers/openai.jpeg'
|
||||||
|
import SiliconFlowProviderLogo from '@renderer/assets/images/providers/silicon.png'
|
||||||
|
import DeepSeekProviderLogo from '@renderer/assets/images/providers/deepseek.png'
|
||||||
|
import YiProviderLogo from '@renderer/assets/images/providers/yi.svg'
|
||||||
|
import GroqProviderLogo from '@renderer/assets/images/providers/groq.png'
|
||||||
|
import ChatGPTModelLogo from '@renderer/assets/images/models/chatgpt.svg'
|
||||||
|
import ChatGLMModelLogo from '@renderer/assets/images/models/chatglm.jpeg'
|
||||||
|
import DeepSeekModelLogo from '@renderer/assets/images/models/deepseek.png'
|
||||||
|
import GemmaModelLogo from '@renderer/assets/images/models/gemma.jpeg'
|
||||||
|
import QwenModelLogo from '@renderer/assets/images/models/qwen.jpeg'
|
||||||
|
import YiModelLogo from '@renderer/assets/images/models/yi.svg'
|
||||||
|
import LlamaModelLogo from '@renderer/assets/images/models/llama.jpeg'
|
||||||
|
import MixtralModelLogo from '@renderer/assets/images/models/mixtral.jpeg'
|
||||||
|
|
||||||
|
export function getProviderLogo(providerId: string) {
|
||||||
|
if (providerId === 'openai') {
|
||||||
|
return OpenAiProviderLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerId === 'silicon') {
|
||||||
|
return SiliconFlowProviderLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerId === 'deepseek') {
|
||||||
|
return DeepSeekProviderLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerId === 'yi') {
|
||||||
|
return YiProviderLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerId === 'groq') {
|
||||||
|
return GroqProviderLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getModelLogo(modelId: string) {
|
||||||
|
const _modelId = modelId.toLowerCase()
|
||||||
|
|
||||||
|
if (_modelId.includes('gpt')) {
|
||||||
|
return ChatGPTModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('glm')) {
|
||||||
|
return ChatGLMModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('deepseek')) {
|
||||||
|
return DeepSeekModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('qwen')) {
|
||||||
|
return QwenModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('gemma')) {
|
||||||
|
return GemmaModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('yi-')) {
|
||||||
|
return YiModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('llama')) {
|
||||||
|
return LlamaModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelId.includes('mixtral')) {
|
||||||
|
return MixtralModelLogo
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||