style: change import order

This commit is contained in:
kangfenmao 2024-08-02 09:42:12 +08:00
parent 18fa1c92a4
commit 5d90489a04
52 changed files with 325 additions and 250 deletions

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
plugins: ['unused-imports'], plugins: ['unused-imports', 'simple-import-sort'],
extends: [ extends: [
'eslint:recommended', 'eslint:recommended',
'plugin:react/recommended', 'plugin:react/recommended',
@ -14,12 +14,7 @@ module.exports = {
'unused-imports/no-unused-imports': 'error', 'unused-imports/no-unused-imports': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off', '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'react/prop-types': 'off', 'react/prop-types': 'off',
'sort-imports': [ 'simple-import-sort/imports': 'error',
'error', 'simple-import-sort/exports': 'error'
{
ignoreCase: true,
ignoreDeclarationSort: true
}
]
} }
} }

View File

@ -1,5 +1,5 @@
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import { resolve } from 'path' import { resolve } from 'path'
export default defineConfig({ export default defineConfig({

View File

@ -29,7 +29,8 @@
"electron-log": "^5.1.5", "electron-log": "^5.1.5",
"electron-store": "^8.2.0", "electron-store": "^8.2.0",
"electron-updater": "^6.1.7", "electron-updater": "^6.1.7",
"electron-window-state": "^5.0.3" "electron-window-state": "^5.0.3",
"eslint-plugin-simple-import-sort": "^12.1.1"
}, },
"devDependencies": { "devDependencies": {
"@anthropic-ai/sdk": "^0.24.3", "@anthropic-ai/sdk": "^0.24.3",

View File

@ -1,6 +1,6 @@
import { dialog, SaveDialogOptions, SaveDialogReturnValue } from 'electron' import { dialog, SaveDialogOptions, SaveDialogReturnValue } from 'electron'
import { writeFile } from 'fs'
import logger from 'electron-log' import logger from 'electron-log'
import { writeFile } from 'fs'
export async function saveFile(_: Electron.IpcMainInvokeEvent, fileName: string, content: string): Promise<void> { export async function saveFile(_: Electron.IpcMainInvokeEvent, fileName: string, content: string): Promise<void> {
try { try {

View File

@ -4,6 +4,7 @@ import { app, BrowserWindow, ipcMain, Menu, MenuItem, session, shell } from 'ele
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer' import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
import windowStateKeeper from 'electron-window-state' import windowStateKeeper from 'electron-window-state'
import { join } from 'path' import { join } from 'path'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config' import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config'
import { saveFile } from './event' import { saveFile } from './event'

View File

@ -1,6 +1,6 @@
import { AppUpdater as _AppUpdater, autoUpdater, UpdateInfo } from 'electron-updater'
import logger from 'electron-log'
import { BrowserWindow, dialog } from 'electron' import { BrowserWindow, dialog } from 'electron'
import logger from 'electron-log'
import { AppUpdater as _AppUpdater, autoUpdater, UpdateInfo } from 'electron-updater'
export default class AppUpdater { export default class AppUpdater {
autoUpdater: _AppUpdater = autoUpdater autoUpdater: _AppUpdater = autoUpdater

View File

@ -1,5 +1,5 @@
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload' import { electronAPI } from '@electron-toolkit/preload'
import { contextBridge, ipcRenderer } from 'electron'
// Custom APIs for renderer // Custom APIs for renderer
const api = { const api = {

View File

@ -2,6 +2,7 @@ import store, { persistor } from '@renderer/store'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import { HashRouter, Route, Routes } from 'react-router-dom' import { HashRouter, Route, Routes } from 'react-router-dom'
import { PersistGate } from 'redux-persist/integration/react' import { PersistGate } from 'redux-persist/integration/react'
import Sidebar from './components/app/Sidebar' import Sidebar from './components/app/Sidebar'
import TopViewContainer from './components/TopView' import TopViewContainer from './components/TopView'
import AppsPage from './pages/apps/AppsPage' import AppsPage from './pages/apps/AppsPage'

View File

@ -1,11 +1,12 @@
import { Input, Modal } from 'antd'
import { useState } from 'react'
import { TopView } from '../TopView'
import { Box } from '../Layout'
import { Assistant } from '@renderer/types' import { Assistant } from '@renderer/types'
import { Input, Modal } from 'antd'
import TextArea from 'antd/es/input/TextArea' import TextArea from 'antd/es/input/TextArea'
import { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Box } from '../Layout'
import { TopView } from '../TopView'
interface AssistantSettingPopupShowParams { interface AssistantSettingPopupShowParams {
assistant: Assistant assistant: Assistant
} }

View File

@ -1,7 +1,8 @@
import { Input, InputProps, Modal } from 'antd' import { Input, InputProps, Modal } from 'antd'
import { useState } from 'react' import { useState } from 'react'
import { TopView } from '../TopView'
import { Box } from '../Layout' import { Box } from '../Layout'
import { TopView } from '../TopView'
interface PromptPopupShowParams { interface PromptPopupShowParams {
title: string title: string

View File

@ -1,7 +1,8 @@
import { Modal } from 'antd' import { Modal } from 'antd'
import { useState } from 'react' import { useState } from 'react'
import { TopView } from '../TopView'
import { Box } from '../Layout' import { Box } from '../Layout'
import { TopView } from '../TopView'
interface ShowParams { interface ShowParams {
title: string title: string

View File

@ -1,10 +1,10 @@
import { FC } from 'react'
import Logo from '@renderer/assets/images/logo.png'
import styled from 'styled-components'
import { Link, useLocation } from 'react-router-dom'
import useAvatar from '@renderer/hooks/useAvatar'
import { isWindows } from '@renderer/config/constant'
import { TranslationOutlined } from '@ant-design/icons' import { TranslationOutlined } from '@ant-design/icons'
import Logo from '@renderer/assets/images/logo.png'
import { isWindows } from '@renderer/config/constant'
import useAvatar from '@renderer/hooks/useAvatar'
import { FC } from 'react'
import { Link, useLocation } from 'react-router-dom'
import styled from 'styled-components'
const Sidebar: FC = () => { const Sidebar: FC = () => {
const { pathname } = useLocation() const { pathname } = useLocation()

View File

@ -1,28 +1,28 @@
import OpenAiProviderLogo from '@renderer/assets/images/providers/openai.jpeg' import BaichuanModelLogo from '@renderer/assets/images/models/baichuan.png'
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 ZhipuProviderLogo from '@renderer/assets/images/providers/zhipu.png'
import OllamaProviderLogo from '@renderer/assets/images/providers/ollama.png'
import MoonshotProviderLogo from '@renderer/assets/images/providers/moonshot.jpeg'
import OpenRouterProviderLogo from '@renderer/assets/images/providers/openrouter.png'
import BaichuanProviderLogo from '@renderer/assets/images/providers/baichuan.png'
import DashScopeProviderLogo from '@renderer/assets/images/providers/dashscope.png'
import AnthropicProviderLogo from '@renderer/assets/images/providers/anthropic.jpeg'
import AiHubMixProviderLogo from '@renderer/assets/images/providers/aihubmix.jpg'
import ChatGPTModelLogo from '@renderer/assets/images/models/chatgpt.jpeg'
import ChatGLMModelLogo from '@renderer/assets/images/models/chatglm.jpeg' import ChatGLMModelLogo from '@renderer/assets/images/models/chatglm.jpeg'
import ChatGPTModelLogo from '@renderer/assets/images/models/chatgpt.jpeg'
import ClaudeModelLogo from '@renderer/assets/images/models/claude.png'
import DeepSeekModelLogo from '@renderer/assets/images/models/deepseek.png' import DeepSeekModelLogo from '@renderer/assets/images/models/deepseek.png'
import GemmaModelLogo from '@renderer/assets/images/models/gemma.jpeg' import GemmaModelLogo from '@renderer/assets/images/models/gemma.jpeg'
import LlamaModelLogo from '@renderer/assets/images/models/llama.jpeg'
import MicrosoftModelLogo from '@renderer/assets/images/models/microsoft.png'
import MixtralModelLogo from '@renderer/assets/images/models/mixtral.jpeg'
import QwenModelLogo from '@renderer/assets/images/models/qwen.png' import QwenModelLogo from '@renderer/assets/images/models/qwen.png'
import YiModelLogo from '@renderer/assets/images/models/yi.svg' import YiModelLogo from '@renderer/assets/images/models/yi.svg'
import LlamaModelLogo from '@renderer/assets/images/models/llama.jpeg' import AiHubMixProviderLogo from '@renderer/assets/images/providers/aihubmix.jpg'
import MixtralModelLogo from '@renderer/assets/images/models/mixtral.jpeg' import AnthropicProviderLogo from '@renderer/assets/images/providers/anthropic.jpeg'
import BaichuanProviderLogo from '@renderer/assets/images/providers/baichuan.png'
import DashScopeProviderLogo from '@renderer/assets/images/providers/dashscope.png'
import DeepSeekProviderLogo from '@renderer/assets/images/providers/deepseek.png'
import GroqProviderLogo from '@renderer/assets/images/providers/groq.png'
import MoonshotProviderLogo from '@renderer/assets/images/providers/moonshot.jpeg'
import MoonshotModelLogo from '@renderer/assets/images/providers/moonshot.jpeg' import MoonshotModelLogo from '@renderer/assets/images/providers/moonshot.jpeg'
import MicrosoftModelLogo from '@renderer/assets/images/models/microsoft.png' import OllamaProviderLogo from '@renderer/assets/images/providers/ollama.png'
import BaichuanModelLogo from '@renderer/assets/images/models/baichuan.png' import OpenAiProviderLogo from '@renderer/assets/images/providers/openai.jpeg'
import ClaudeModelLogo from '@renderer/assets/images/models/claude.png' import OpenRouterProviderLogo from '@renderer/assets/images/providers/openrouter.png'
import SiliconFlowProviderLogo from '@renderer/assets/images/providers/silicon.png'
import YiProviderLogo from '@renderer/assets/images/providers/yi.svg'
import ZhipuProviderLogo from '@renderer/assets/images/providers/zhipu.png'
export function getProviderLogo(providerId: string) { export function getProviderLogo(providerId: string) {
switch (providerId) { switch (providerId) {

View File

@ -1,8 +1,8 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
import type KeyvStorage from '@kangfenmao/keyv-storage'
import { MessageInstance } from 'antd/es/message/interface' import { MessageInstance } from 'antd/es/message/interface'
import { HookAPI } from 'antd/es/modal/useModal' import { HookAPI } from 'antd/es/modal/useModal'
import type KeyvStorage from '@kangfenmao/keyv-storage'
declare global { declare global {
interface Window { interface Window {

View File

@ -1,21 +1,22 @@
import { i18nInit } from '@renderer/i18n' import i18n from '@renderer/i18n'
import LocalStorage from '@renderer/services/storage' import LocalStorage from '@renderer/services/storage'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { setAvatar } from '@renderer/store/runtime' import { setAvatar } from '@renderer/store/runtime'
import { runAsyncFunction } from '@renderer/utils' import { runAsyncFunction } from '@renderer/utils'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useSettings } from './useSettings' import { useSettings } from './useSettings'
export function useAppInit() { export function useAppInit() {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { proxyUrl } = useSettings() const { proxyUrl } = useSettings()
const { language } = useSettings()
useEffect(() => { useEffect(() => {
runAsyncFunction(async () => { runAsyncFunction(async () => {
const storedImage = await LocalStorage.getImage('avatar') const storedImage = await LocalStorage.getImage('avatar')
storedImage && dispatch(setAvatar(storedImage)) storedImage && dispatch(setAvatar(storedImage))
}) })
i18nInit()
}, [dispatch]) }, [dispatch])
useEffect(() => { useEffect(() => {
@ -28,4 +29,8 @@ export function useAppInit() {
useEffect(() => { useEffect(() => {
proxyUrl && window.api.setProxy(proxyUrl) proxyUrl && window.api.setProxy(proxyUrl)
}, [proxyUrl]) }, [proxyUrl])
useEffect(() => {
i18n.changeLanguage(language || navigator.language || 'en-US')
}, [language])
} }

View File

@ -1,3 +1,4 @@
import { createSelector } from '@reduxjs/toolkit'
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppDispatch, useAppSelector } from '@renderer/store'
import { import {
addModel, addModel,
@ -8,8 +9,8 @@ import {
updateProviders updateProviders
} from '@renderer/store/llm' } from '@renderer/store/llm'
import { Assistant, Model, Provider } from '@renderer/types' import { Assistant, Model, Provider } from '@renderer/types'
import { useDefaultModel } from './useAssistant' import { useDefaultModel } from './useAssistant'
import { createSelector } from '@reduxjs/toolkit'
const selectEnabledProviders = createSelector( const selectEnabledProviders = createSelector(
(state) => state.llm.providers, (state) => state.llm.providers,

View File

@ -1,7 +1,7 @@
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppDispatch, useAppSelector } from '@renderer/store'
import { import {
setSendMessageShortcut as _setSendMessageShortcut,
SendMessageShortcut, SendMessageShortcut,
setSendMessageShortcut as _setSendMessageShortcut,
setTheme, setTheme,
ThemeMode ThemeMode
} from '@renderer/store/settings' } from '@renderer/store/settings'

View File

@ -1,4 +1,3 @@
import store from '@renderer/store'
import i18n from 'i18next' import i18n from 'i18next'
import { initReactI18next } from 'react-i18next' import { initReactI18next } from 'react-i18next'
@ -386,8 +385,4 @@ i18n.use(initReactI18next).init({
} }
}) })
export function i18nInit() {
i18n.changeLanguage(store.getState().settings.language || 'en-US')
}
export default i18n export default i18n

View File

@ -1,8 +1,9 @@
import localforage from 'localforage'
import KeyvStorage from '@kangfenmao/keyv-storage' import KeyvStorage from '@kangfenmao/keyv-storage'
import * as Sentry from '@sentry/electron/renderer' import * as Sentry from '@sentry/electron/renderer'
import { isProduction, loadScript } from './utils' import localforage from 'localforage'
import { ThemeMode } from './store/settings' import { ThemeMode } from './store/settings'
import { isProduction, loadScript } from './utils'
async function initSentry() { async function initSentry() {
if (await isProduction()) { if (await isProduction()) {

View File

@ -1,10 +1,12 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './assets/styles/index.scss' import './assets/styles/index.scss'
import './init' import './init'
import './i18n' import './i18n'
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode> <React.StrictMode>
<App /> <App />

View File

@ -1,13 +1,13 @@
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import SYSTEM_ASSISTANTS from '@renderer/config/assistants.json'
import { useAssistants } from '@renderer/hooks/useAssistant'
import { getDefaultAssistant } from '@renderer/services/assistant'
import { SystemAssistant } from '@renderer/types'
import { Col, Row, Typography } from 'antd' import { Col, Row, Typography } from 'antd'
import { find, groupBy } from 'lodash' import { find, groupBy } from 'lodash'
import { FC } from 'react' import { FC } from 'react'
import styled from 'styled-components'
import { SystemAssistant } from '@renderer/types'
import { getDefaultAssistant } from '@renderer/services/assistant'
import { useAssistants } from '@renderer/hooks/useAssistant'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import SYSTEM_ASSISTANTS from '@renderer/config/assistants.json' import styled from 'styled-components'
const { Title } = Typography const { Title } = Typography

View File

@ -1,16 +1,17 @@
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar' import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
import { isMac, isWindows } from '@renderer/config/constant'
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant' import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
import { useShowAssistants, useShowRightSidebar } from '@renderer/hooks/useStore'
import { useTheme } from '@renderer/providers/ThemeProvider'
import { Assistant } from '@renderer/types'
import { uuid } from '@renderer/utils'
import { Switch } from 'antd'
import { FC, useState } from 'react' import { FC, useState } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import Chat from './components/Chat'
import Assistants from './components/Assistants' import Assistants from './components/Assistants'
import { uuid } from '@renderer/utils' import Chat from './components/Chat'
import { useShowAssistants, useShowRightSidebar } from '@renderer/hooks/useStore'
import Navigation from './components/NavigationCenter' import Navigation from './components/NavigationCenter'
import { isMac, isWindows } from '@renderer/config/constant'
import { Assistant } from '@renderer/types'
import { useTheme } from '@renderer/providers/ThemeProvider'
import { Switch } from 'antd'
let _activeAssistant: Assistant let _activeAssistant: Assistant

View File

@ -10,7 +10,7 @@ import { droppableReorder, uuid } from '@renderer/utils'
import { Dropdown } from 'antd' import { Dropdown } from 'antd'
import { ItemType } from 'antd/es/menu/interface' import { ItemType } from 'antd/es/menu/interface'
import { last } from 'lodash' import { last } from 'lodash'
import { FC } from 'react' import { FC, useCallback } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -22,65 +22,78 @@ interface Props {
const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAssistant }) => { const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAssistant }) => {
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants() const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
const { updateAssistant } = useAssistant(activeAssistant.id)
const generating = useAppSelector((state) => state.runtime.generating) const generating = useAppSelector((state) => state.runtime.generating)
const { updateAssistant } = useAssistant(activeAssistant.id)
const { t } = useTranslation() const { t } = useTranslation()
const onDelete = (assistant: Assistant) => { const onDelete = useCallback(
const _assistant = last(assistants.filter((a) => a.id !== assistant.id)) (assistant: Assistant) => {
_assistant ? setActiveAssistant(_assistant) : onCreateAssistant() const _assistant = last(assistants.filter((a) => a.id !== assistant.id))
removeAssistant(assistant.id) _assistant ? setActiveAssistant(_assistant) : onCreateAssistant()
} removeAssistant(assistant.id)
},
[assistants, onCreateAssistant, removeAssistant, setActiveAssistant]
)
const getMenuItems = (assistant: Assistant) => const getMenuItems = useCallback(
[ (assistant: Assistant) =>
{ [
label: t('common.edit'), {
key: 'edit', label: t('common.edit'),
icon: <EditOutlined />, key: 'edit',
async onClick() { icon: <EditOutlined />,
const _assistant = await AssistantSettingPopup.show({ assistant }) async onClick() {
updateAssistant(_assistant) const _assistant = await AssistantSettingPopup.show({ assistant })
updateAssistant(_assistant)
}
},
{
label: t('common.duplicate'),
key: 'duplicate',
icon: <CopyOutlined />,
onClick: async () => {
const _assistant: Assistant = { ...assistant, id: uuid(), topics: [getDefaultTopic()] }
addAssistant(_assistant)
setActiveAssistant(_assistant)
}
},
{ type: 'divider' },
{
label: t('common.delete'),
key: 'delete',
icon: <DeleteOutlined />,
danger: true,
onClick: () => onDelete(assistant)
} }
}, ] as ItemType[],
{ [addAssistant, onDelete, setActiveAssistant, t, updateAssistant]
label: t('common.duplicate'), )
key: 'duplicate',
icon: <CopyOutlined />, const onDragEnd = useCallback(
onClick: async () => { (result: DropResult) => {
const _assistant: Assistant = { ...assistant, id: uuid(), topics: [getDefaultTopic()] } if (result.destination) {
addAssistant(_assistant) const sourceIndex = result.source.index
setActiveAssistant(_assistant) const destIndex = result.destination.index
} const reorderAssistants = droppableReorder<Assistant>(assistants, sourceIndex, destIndex)
}, updateAssistants(reorderAssistants)
{ type: 'divider' },
{
label: t('common.delete'),
key: 'delete',
icon: <DeleteOutlined />,
danger: true,
onClick: () => onDelete(assistant)
} }
] as ItemType[] },
[assistants, updateAssistants]
)
const onDragEnd = (result: DropResult) => { const onSwitchAssistant = useCallback(
if (result.destination) { (assistant: Assistant): any => {
const sourceIndex = result.source.index if (generating) {
const destIndex = result.destination.index return window.message.warning({
const reorderAssistants = droppableReorder<Assistant>(assistants, sourceIndex, destIndex) content: t('message.switch.disabled'),
updateAssistants(reorderAssistants) key: 'switch-assistant'
} })
} }
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
const onSwitchAssistant = (assistant: Assistant) => { setActiveAssistant(assistant)
if (generating) { },
window.message.warning({ content: t('message.switch.disabled'), key: 'switch-assistant' }) [generating, setActiveAssistant, t]
return )
}
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
setActiveAssistant(assistant)
}
return ( return (
<Container> <Container>
@ -91,7 +104,11 @@ const Assistants: FC<Props> = ({ activeAssistant, setActiveAssistant, onCreateAs
{assistants.map((assistant, index) => ( {assistants.map((assistant, index) => (
<Draggable key={`draggable_${assistant.id}_${index}`} draggableId={assistant.id} index={index}> <Draggable key={`draggable_${assistant.id}_${index}`} draggableId={assistant.id} index={index}>
{(provided) => ( {(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}> <div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{ ...provided.draggableProps.style, marginBottom: 5 }}>
<Dropdown key={assistant.id} menu={{ items: getMenuItems(assistant) }} trigger={['contextMenu']}> <Dropdown key={assistant.id} menu={{ items: getMenuItems(assistant) }} trigger={['contextMenu']}>
<AssistantItem <AssistantItem
onClick={() => onSwitchAssistant(assistant)} onClick={() => onSwitchAssistant(assistant)}
@ -130,7 +147,6 @@ const AssistantItem = styled.div`
padding: 7px 10px; padding: 7px 10px;
position: relative; position: relative;
border-radius: 3px; border-radius: 3px;
margin-bottom: 5px;
cursor: pointer; cursor: pointer;
font-family: Poppins; font-family: Poppins;
.anticon { .anticon {

View File

@ -1,12 +1,13 @@
import { Assistant } from '@renderer/types'
import { FC } from 'react'
import styled from 'styled-components'
import Inputbar from './Inputbar'
import Messages from './Messages'
import { Flex } from 'antd'
import RightSidebar from './RightSidebar'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useActiveTopic } from '@renderer/hooks/useTopic' import { useActiveTopic } from '@renderer/hooks/useTopic'
import { Assistant } from '@renderer/types'
import { Flex } from 'antd'
import { FC } from 'react'
import styled from 'styled-components'
import Inputbar from './input/Inputbar'
import Messages from './Messages'
import RightSidebar from './sidebar/RightSidebar'
interface Props { interface Props {
assistant: Assistant assistant: Assistant

View File

@ -21,6 +21,7 @@ import { upperFirst } from 'lodash'
import { FC, memo, useCallback, useMemo, useState } from 'react' import { FC, memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import Markdown from './markdown/Markdown' import Markdown from './markdown/Markdown'
interface Props { interface Props {

View File

@ -1,16 +1,17 @@
import { useAssistant } from '@renderer/hooks/useAssistant'
import { useProviderByAssistant } from '@renderer/hooks/useProvider'
import { fetchChatCompletion, fetchMessagesSummary } from '@renderer/services/api'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event' import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import LocalStorage from '@renderer/services/storage'
import { Assistant, Message, Topic } from '@renderer/types' import { Assistant, Message, Topic } from '@renderer/types'
import { estimateHistoryTokenCount, runAsyncFunction } from '@renderer/utils'
import { t } from 'i18next'
import localforage from 'localforage' import localforage from 'localforage'
import { debounce, reverse } from 'lodash'
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import MessageItem from './Message' import MessageItem from './Message'
import { debounce, reverse } from 'lodash'
import { fetchChatCompletion, fetchMessagesSummary } from '@renderer/services/api'
import { useAssistant } from '@renderer/hooks/useAssistant'
import { estimateHistoryTokenCount, runAsyncFunction } from '@renderer/utils'
import LocalStorage from '@renderer/services/storage'
import { useProviderByAssistant } from '@renderer/hooks/useProvider'
import { t } from 'i18next'
import Suggestions from './Suggestions' import Suggestions from './Suggestions'
interface Props { interface Props {

View File

@ -1,18 +1,19 @@
import { CodeSandboxOutlined } from '@ant-design/icons' import { CodeSandboxOutlined } from '@ant-design/icons'
import { NavbarCenter } from '@renderer/components/app/Navbar' import { NavbarCenter } from '@renderer/components/app/Navbar'
import { isMac } from '@renderer/config/constant' import { isMac } from '@renderer/config/constant'
import { getModelLogo } from '@renderer/config/provider'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useProviders } from '@renderer/hooks/useProvider' import { useProviders } from '@renderer/hooks/useProvider'
import { useShowAssistants } from '@renderer/hooks/useStore' import { useShowAssistants } from '@renderer/hooks/useStore'
import { Assistant } from '@renderer/types' import { Assistant } from '@renderer/types'
import { removeLeadingEmoji } from '@renderer/utils'
import { Avatar, Button, Dropdown, MenuProps } from 'antd' import { Avatar, Button, Dropdown, MenuProps } from 'antd'
import { first, upperFirst } from 'lodash' import { first, upperFirst } from 'lodash'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import { NewButton } from '../HomePage' import { NewButton } from '../HomePage'
import { getModelLogo } from '@renderer/config/provider'
import { removeLeadingEmoji } from '@renderer/utils'
interface Props { interface Props {
activeAssistant: Assistant activeAssistant: Assistant

View File

@ -1,11 +1,11 @@
import { fetchSuggestions } from '@renderer/services/api'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event' import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import { Assistant, Message, Suggestion } from '@renderer/types' import { Assistant, Message, Suggestion } from '@renderer/types'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import styled from 'styled-components'
import BeatLoader from 'react-spinners/BeatLoader' import BeatLoader from 'react-spinners/BeatLoader'
import { fetchSuggestions } from '@renderer/services/api' import styled from 'styled-components'
interface Props { interface Props {
assistant: Assistant assistant: Assistant

View File

@ -23,6 +23,7 @@ import { debounce, isEmpty } from 'lodash'
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import SendMessageButton from './SendMessageButton' import SendMessageButton from './SendMessageButton'
interface Props { interface Props {

View File

@ -1,9 +1,9 @@
import { ArrowUpOutlined, EnterOutlined } from '@ant-design/icons'
import { SendOutlined } from '@ant-design/icons'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
import { Dropdown, MenuProps } from 'antd' import { Dropdown, MenuProps } from 'antd'
import { FC } from 'react' import { FC } from 'react'
import { ArrowUpOutlined, EnterOutlined } from '@ant-design/icons'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { SendOutlined } from '@ant-design/icons'
interface Props { interface Props {
sendMessage: () => void sendMessage: () => void

View File

@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { atomDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism' import { atomDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism'
import styled from 'styled-components' import styled from 'styled-components'
import Mermaid from './Mermaid' import Mermaid from './Mermaid'
interface CodeBlockProps { interface CodeBlockProps {

View File

@ -1,14 +1,16 @@
import { FC, useCallback, useMemo } from 'react' import 'katex/dist/katex.min.css'
import ReactMarkdown from 'react-markdown'
import { Message } from '@renderer/types' import { Message } from '@renderer/types'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { FC, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import CodeBlock from './CodeBlock' import ReactMarkdown from 'react-markdown'
import Link from './Link' import rehypeKatex from 'rehype-katex'
import remarkGfm from 'remark-gfm' import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math' import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'
import 'katex/dist/katex.min.css' import CodeBlock from './CodeBlock'
import Link from './Link'
interface Props { interface Props {
message: Message message: Message

View File

@ -1,11 +1,12 @@
import { useShowRightSidebar } from '@renderer/hooks/useStore'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import { Assistant, Topic } from '@renderer/types' import { Assistant, Topic } from '@renderer/types'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import styled from 'styled-components'
import TopicsTab from './TopicsTab'
import SettingsTab from './SettingsTab'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event' import styled from 'styled-components'
import { useShowRightSidebar } from '@renderer/hooks/useStore'
import SettingsTab from './SettingsTab'
import TopicsTab from './TopicsTab'
interface Props { interface Props {
assistant: Assistant assistant: Assistant
@ -47,8 +48,12 @@ const RightSidebar: FC<Props> = (props) => {
return () => unsubscribes.forEach((unsub) => unsub()) return () => unsubscribes.forEach((unsub) => unsub())
}, [hideRightSidebar, isSettingsTab, isTopicTab, rightSidebarShown, showRightSidebar]) }, [hideRightSidebar, isSettingsTab, isTopicTab, rightSidebarShown, showRightSidebar])
if (!rightSidebarShown) {
return null
}
return ( return (
<Container style={{ display: rightSidebarShown ? 'block' : 'none' }}> <Container>
<Tabs> <Tabs>
<Tab className={tab === 'topic' ? 'active' : ''} onClick={() => setTab('topic')}> <Tab className={tab === 'topic' ? 'active' : ''} onClick={() => setTab('topic')}>
{t('common.topics')} {t('common.topics')}
@ -57,17 +62,20 @@ const RightSidebar: FC<Props> = (props) => {
{t('settings.title')} {t('settings.title')}
</Tab> </Tab>
</Tabs> </Tabs>
{tab === 'topic' && <TopicsTab {...props} />} <TabContent>
{tab === 'settings' && <SettingsTab assistant={props.assistant} />} {tab === 'topic' && <TopicsTab {...props} />}
{tab === 'settings' && <SettingsTab assistant={props.assistant} />}
</TabContent>
</Container> </Container>
) )
} }
const Container = styled.div` const Container = styled.div`
display: flex;
flex-direction: column;
width: var(--topic-list-width); width: var(--topic-list-width);
height: calc(100vh - var(--navbar-height)); height: calc(100vh - var(--navbar-height));
border-left: 0.5px solid var(--color-border); border-left: 0.5px solid var(--color-border);
overflow-y: auto;
.collapsed { .collapsed {
width: 0; width: 0;
border-left: none; border-left: none;
@ -97,4 +105,10 @@ const Tab = styled.div`
} }
` `
const TabContent = styled.div`
display: flex;
flex: 1;
overflow-y: auto;
`
export default RightSidebar export default RightSidebar

View File

@ -1,16 +1,16 @@
import { Assistant } from '@renderer/types' import { QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import styled from 'styled-components'
import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant' import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings'
import { SettingDivider, SettingRow, SettingRowTitle, SettingSubtitle } from '@renderer/pages/settings/components'
import { useAppDispatch } from '@renderer/store'
import { setMessageFont, setShowInputEstimatedTokens, setShowMessageDivider } from '@renderer/store/settings'
import { Assistant } from '@renderer/types'
import { Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd' import { Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import { FC, useCallback, useEffect, useState } from 'react' import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons' import styled from 'styled-components'
import { SettingDivider, SettingRow, SettingRowTitle, SettingSubtitle } from '@renderer/pages/settings/components'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setMessageFont, setShowInputEstimatedTokens, setShowMessageDivider } from '@renderer/store/settings'
interface Props { interface Props {
assistant: Assistant assistant: Assistant
@ -81,7 +81,7 @@ const SettingsTab: FC<Props> = (props) => {
<SettingSubtitle> <SettingSubtitle>
{t('settings.messages.model.title')}{' '} {t('settings.messages.model.title')}{' '}
<Tooltip title={t('assistant.settings.reset')}> <Tooltip title={t('assistant.settings.reset')}>
<ReloadOutlined onClick={onReset} style={{ cursor: 'pointer', fontSize: 13, padding: '0 3px' }} /> <ReloadOutlined onClick={onReset} style={{ cursor: 'pointer', fontSize: 12, padding: '0 3px' }} />
</Tooltip> </Tooltip>
</SettingSubtitle> </SettingSubtitle>
<SettingDivider /> <SettingDivider />
@ -177,6 +177,9 @@ const SettingsTab: FC<Props> = (props) => {
} }
const Container = styled.div` const Container = styled.div`
display: flex;
flex: 1;
flex-direction: column;
padding: 0 15px; padding: 0 15px;
` `

View File

@ -1,17 +1,16 @@
import { DeleteOutlined, EditOutlined, OpenAIOutlined } from '@ant-design/icons'
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd'
import PromptPopup from '@renderer/components/Popups/PromptPopup' import PromptPopup from '@renderer/components/Popups/PromptPopup'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useShowRightSidebar } from '@renderer/hooks/useStore'
import { fetchMessagesSummary } from '@renderer/services/api' import { fetchMessagesSummary } from '@renderer/services/api'
import LocalStorage from '@renderer/services/storage'
import { useAppSelector } from '@renderer/store'
import { Assistant, Topic } from '@renderer/types' import { Assistant, Topic } from '@renderer/types'
import { droppableReorder } from '@renderer/utils'
import { Dropdown, MenuProps } from 'antd' import { Dropdown, MenuProps } from 'antd'
import { FC, useCallback } from 'react' import { FC, useCallback } from 'react'
import styled from 'styled-components'
import { DeleteOutlined, EditOutlined, OpenAIOutlined } from '@ant-design/icons'
import LocalStorage from '@renderer/services/storage'
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd'
import { droppableReorder } from '@renderer/utils'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useAppSelector } from '@renderer/store' import styled from 'styled-components'
interface Props { interface Props {
assistant: Assistant assistant: Assistant
@ -20,7 +19,6 @@ interface Props {
} }
const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => { const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => {
const { rightSidebarShown } = useShowRightSidebar()
const { assistant, removeTopic, updateTopic, updateTopics } = useAssistant(_assistant.id) const { assistant, removeTopic, updateTopic, updateTopics } = useAssistant(_assistant.id)
const { t } = useTranslation() const { t } = useTranslation()
const generating = useAppSelector((state) => state.runtime.generating) const generating = useAppSelector((state) => state.runtime.generating)
@ -102,7 +100,7 @@ const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTop
) )
return ( return (
<Container style={{ display: rightSidebarShown ? 'block' : 'none' }}> <Container>
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable"> <Droppable droppableId="droppable">
{(provided) => ( {(provided) => (
@ -110,7 +108,11 @@ const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTop
{assistant.topics.map((topic, index) => ( {assistant.topics.map((topic, index) => (
<Draggable key={`draggable_${topic.id}_${index}`} draggableId={topic.id} index={index}> <Draggable key={`draggable_${topic.id}_${index}`} draggableId={topic.id} index={index}>
{(provided) => ( {(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}> <div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{ ...provided.draggableProps.style, marginBottom: 5 }}>
<Dropdown menu={{ items: getTopicMenuItems(topic) }} trigger={['contextMenu']} key={topic.id}> <Dropdown menu={{ items: getTopicMenuItems(topic) }} trigger={['contextMenu']} key={topic.id}>
<TopicListItem <TopicListItem
className={topic.id === activeTopic?.id ? 'active' : ''} className={topic.id === activeTopic?.id ? 'active' : ''}
@ -131,12 +133,14 @@ const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTop
} }
const Container = styled.div` const Container = styled.div`
display: flex;
flex: 1;
flex-direction: column;
padding: 15px 10px; padding: 15px 10px;
` `
const TopicListItem = styled.div` const TopicListItem = styled.div`
padding: 8px 10px; padding: 8px 10px;
margin-bottom: 5px;
cursor: pointer; cursor: pointer;
border-radius: 3px; border-radius: 3px;
font-size: 14px; font-size: 14px;

View File

@ -1,11 +1,12 @@
import { Avatar, Button, Progress, Row, Tag } from 'antd'
import { FC, useEffect, useState } from 'react'
import styled from 'styled-components'
import Logo from '@renderer/assets/images/logo.png' import Logo from '@renderer/assets/images/logo.png'
import { runAsyncFunction } from '@renderer/utils' import { runAsyncFunction } from '@renderer/utils'
import { useTranslation } from 'react-i18next' import { Avatar, Button, Progress, Row, Tag } from 'antd'
import { debounce } from 'lodash'
import { ProgressInfo } from 'electron-updater' import { ProgressInfo } from 'electron-updater'
import { debounce } from 'lodash'
import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components' import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components'
const AboutSettings: FC = () => { const AboutSettings: FC = () => {

View File

@ -3,11 +3,12 @@ import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/const
import { useDefaultAssistant } from '@renderer/hooks/useAssistant' import { useDefaultAssistant } from '@renderer/hooks/useAssistant'
import { Button, Col, Input, InputNumber, Row, Slider, Tooltip } from 'antd' import { Button, Col, Input, InputNumber, Row, Slider, Tooltip } from 'antd'
import TextArea from 'antd/es/input/TextArea' import TextArea from 'antd/es/input/TextArea'
import { debounce } from 'lodash'
import { FC, useCallback, useState } from 'react' import { FC, useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingSubtitle, SettingTitle } from './components' import { SettingContainer, SettingDivider, SettingSubtitle, SettingTitle } from './components'
import { debounce } from 'lodash'
const AssistantSettings: FC = () => { const AssistantSettings: FC = () => {
const { defaultAssistant, updateDefaultAssistant } = useDefaultAssistant() const { defaultAssistant, updateDefaultAssistant } = useDefaultAssistant()

View File

@ -1,17 +1,17 @@
import { FC, useState } from 'react'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components'
import { Avatar, Input, Select, Upload } from 'antd'
import styled from 'styled-components'
import LocalStorage from '@renderer/services/storage'
import { compressImage, isValidProxyUrl } from '@renderer/utils'
import useAvatar from '@renderer/hooks/useAvatar' import useAvatar from '@renderer/hooks/useAvatar'
import { useSettings } from '@renderer/hooks/useSettings'
import LocalStorage from '@renderer/services/storage'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { setAvatar } from '@renderer/store/runtime' import { setAvatar } from '@renderer/store/runtime'
import { useSettings } from '@renderer/hooks/useSettings'
import { setLanguage, setUserName, ThemeMode } from '@renderer/store/settings' import { setLanguage, setUserName, ThemeMode } from '@renderer/store/settings'
import { useTranslation } from 'react-i18next'
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings' import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
import i18n from '@renderer/i18n' import { compressImage, isValidProxyUrl } from '@renderer/utils'
import { Avatar, Input, Select, Upload } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components'
const GeneralSettings: FC = () => { const GeneralSettings: FC = () => {
const avatar = useAvatar() const avatar = useAvatar()
@ -22,7 +22,6 @@ const GeneralSettings: FC = () => {
const onSelectLanguage = (value: string) => { const onSelectLanguage = (value: string) => {
dispatch(setLanguage(value)) dispatch(setLanguage(value))
i18n.changeLanguage(value)
localStorage.setItem('language', value) localStorage.setItem('language', value)
} }

View File

@ -1,12 +1,13 @@
import { FC } from 'react'
import { SettingContainer, SettingDivider, SettingTitle } from './components'
import { Select } from 'antd'
import { useProviders } from '@renderer/hooks/useProvider'
import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { find } from 'lodash'
import { Model } from '@renderer/types'
import { useTranslation } from 'react-i18next'
import { EditOutlined, MessageOutlined, TranslationOutlined } from '@ant-design/icons' import { EditOutlined, MessageOutlined, TranslationOutlined } from '@ant-design/icons'
import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { useProviders } from '@renderer/hooks/useProvider'
import { Model } from '@renderer/types'
import { Select } from 'antd'
import { find } from 'lodash'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { SettingContainer, SettingDivider, SettingTitle } from './components'
const ModelSettings: FC = () => { const ModelSettings: FC = () => {
const { defaultModel, topicNamingModel, translateModel, setDefaultModel, setTopicNamingModel, setTranslateModel } = const { defaultModel, topicNamingModel, translateModel, setDefaultModel, setTopicNamingModel, setTranslateModel } =

View File

@ -1,16 +1,17 @@
import { PlusOutlined } from '@ant-design/icons'
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd' import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd'
import { useAllProviders, useProviders } from '@renderer/hooks/useProvider'
import { getProviderLogo } from '@renderer/config/provider' import { getProviderLogo } from '@renderer/config/provider'
import { useAllProviders, useProviders } from '@renderer/hooks/useProvider'
import { Provider } from '@renderer/types' import { Provider } from '@renderer/types'
import { droppableReorder, generateColorFromChar, getFirstCharacter, uuid } from '@renderer/utils' import { droppableReorder, generateColorFromChar, getFirstCharacter, uuid } from '@renderer/utils'
import { Avatar, Button, Dropdown, MenuProps, Tag } from 'antd' import { Avatar, Button, Dropdown, MenuProps, Tag } from 'antd'
import { FC, useState } from 'react' import { FC, useState } from 'react'
import styled from 'styled-components'
import ProviderSetting from './components/ProviderSetting'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { PlusOutlined } from '@ant-design/icons' import styled from 'styled-components'
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'
import AddProviderPopup from './components/AddProviderPopup' import AddProviderPopup from './components/AddProviderPopup'
import ProviderSetting from './components/ProviderSetting'
const ProviderSettings: FC = () => { const ProviderSettings: FC = () => {
const providers = useAllProviders() const providers = useAllProviders()
@ -92,7 +93,11 @@ const ProviderSettings: FC = () => {
{providers.map((provider, index) => ( {providers.map((provider, index) => (
<Draggable key={`draggable_${provider.id}_${index}`} draggableId={provider.id} index={index}> <Draggable key={`draggable_${provider.id}_${index}`} draggableId={provider.id} index={index}>
{(provided) => ( {(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}> <div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{ ...provided.draggableProps.style, marginBottom: 5 }}>
<Dropdown <Dropdown
menu={{ items: provider.isSystem ? [] : getDropdownMenus(provider) }} menu={{ items: provider.isSystem ? [] : getDropdownMenus(provider) }}
trigger={['contextMenu']}> trigger={['contextMenu']}>
@ -166,7 +171,6 @@ const ProviderListItem = styled.div`
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 5px 8px; padding: 5px 8px;
margin-bottom: 5px;
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
border-radius: 5px; border-radius: 5px;

View File

@ -1,13 +1,14 @@
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { Link, Route, Routes, useLocation } from 'react-router-dom' import { Link, Route, Routes, useLocation } from 'react-router-dom'
import styled from 'styled-components' import styled from 'styled-components'
import GeneralSettings from './GeneralSettings'
import AboutSettings from './AboutSettings' import AboutSettings from './AboutSettings'
import AssistantSettings from './AssistantSettings' import AssistantSettings from './AssistantSettings'
import GeneralSettings from './GeneralSettings'
import ModelSettings from './ModelSettings' import ModelSettings from './ModelSettings'
import ProviderSettings from './ProviderSettings' import ProviderSettings from './ProviderSettings'
import { useTranslation } from 'react-i18next'
const SettingsPage: FC = () => { const SettingsPage: FC = () => {
const { pathname } = useLocation() const { pathname } = useLocation()

View File

@ -1,17 +1,18 @@
import { LoadingOutlined, MinusOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons' import { LoadingOutlined, MinusOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import { SYSTEM_MODELS } from '@renderer/config/models' import { SYSTEM_MODELS } from '@renderer/config/models'
import { getModelLogo } from '@renderer/config/provider'
import { useProvider } from '@renderer/hooks/useProvider' import { useProvider } from '@renderer/hooks/useProvider'
import { fetchModels } from '@renderer/services/api' import { fetchModels } from '@renderer/services/api'
import { getModelLogo } from '@renderer/config/provider'
import { Model, Provider } from '@renderer/types' import { Model, Provider } from '@renderer/types'
import { getDefaultGroupName, isFreeModel, runAsyncFunction } from '@renderer/utils' import { getDefaultGroupName, isFreeModel, runAsyncFunction } from '@renderer/utils'
import { Avatar, Button, Empty, Flex, Modal, Tag } from 'antd' import { Avatar, Button, Empty, Flex, Modal, Tag } from 'antd'
import Search from 'antd/es/input/Search' import Search from 'antd/es/input/Search'
import { groupBy, isEmpty, uniqBy } from 'lodash' import { groupBy, isEmpty, uniqBy } from 'lodash'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import styled from 'styled-components'
import { TopView } from '../../../components/TopView'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { TopView } from '../../../components/TopView'
interface ShowParams { interface ShowParams {
provider: Provider provider: Provider

View File

@ -1,11 +1,3 @@
import { Provider } from '@renderer/types'
import { FC, useEffect, useState } from 'react'
import styled from 'styled-components'
import { Avatar, Button, Card, Divider, Flex, Input, Space, Switch } from 'antd'
import { useProvider } from '@renderer/hooks/useProvider'
import { groupBy } from 'lodash'
import { SettingContainer, SettingSubtitle, SettingTitle } from '.'
import { getModelLogo } from '@renderer/config/provider'
import { import {
CheckOutlined, CheckOutlined,
EditOutlined, EditOutlined,
@ -14,13 +6,22 @@ import {
MinusCircleOutlined, MinusCircleOutlined,
PlusOutlined PlusOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
import { getModelLogo } from '@renderer/config/provider'
import { PROVIDER_CONFIG } from '@renderer/config/provider'
import { useProvider } from '@renderer/hooks/useProvider'
import { useTheme } from '@renderer/providers/ThemeProvider'
import { checkApi } from '@renderer/services/api'
import { Provider } from '@renderer/types'
import { Avatar, Button, Card, Divider, Flex, Input, Space, Switch } from 'antd'
import Link from 'antd/es/typography/Link'
import { groupBy } from 'lodash'
import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { SettingContainer, SettingSubtitle, SettingTitle } from '.'
import AddModelPopup from './AddModelPopup' import AddModelPopup from './AddModelPopup'
import EditModelsPopup from './EditModelsPopup' import EditModelsPopup from './EditModelsPopup'
import Link from 'antd/es/typography/Link'
import { checkApi } from '@renderer/services/api'
import { useTranslation } from 'react-i18next'
import { PROVIDER_CONFIG } from '@renderer/config/provider'
import { useTheme } from '@renderer/providers/ThemeProvider'
interface Props { interface Props {
provider: Provider provider: Provider

View File

@ -26,7 +26,7 @@ export const SettingTitle = styled.div`
export const SettingSubtitle = styled.div` export const SettingSubtitle = styled.div`
font-size: 14px; font-size: 14px;
color: var(--color-text-2); color: var(--color-text-2);
margin: 15px 0 10px 0; margin: 15px 0 0 0;
user-select: none; user-select: none;
` `

View File

@ -2,6 +2,7 @@ import { useSettings } from '@renderer/hooks/useSettings'
import { ConfigProvider, theme } from 'antd' import { ConfigProvider, theme } from 'antd'
import zhCN from 'antd/locale/zh_CN' import zhCN from 'antd/locale/zh_CN'
import { FC, PropsWithChildren } from 'react' import { FC, PropsWithChildren } from 'react'
import { useTheme } from './ThemeProvider' import { useTheme } from './ThemeProvider'
const AntdProvider: FC<PropsWithChildren> = ({ children }) => { const AntdProvider: FC<PropsWithChildren> = ({ children }) => {

View File

@ -1,12 +1,13 @@
import { Assistant, Message, Provider, Suggestion } from '@renderer/types'
import OpenAI from 'openai'
import Anthropic from '@anthropic-ai/sdk' import Anthropic from '@anthropic-ai/sdk'
import { getDefaultModel, getTopNamingModel } from './assistant'
import { ChatCompletionCreateParamsNonStreaming, ChatCompletionMessageParam } from 'openai/resources'
import { sum, takeRight } from 'lodash'
import { MessageCreateParamsNonStreaming, MessageParam } from '@anthropic-ai/sdk/resources' import { MessageCreateParamsNonStreaming, MessageParam } from '@anthropic-ai/sdk/resources'
import { EVENT_NAMES } from './event' import { Assistant, Message, Provider, Suggestion } from '@renderer/types'
import { getAssistantSettings, removeQuotes } from '@renderer/utils' import { getAssistantSettings, removeQuotes } from '@renderer/utils'
import { sum, takeRight } from 'lodash'
import OpenAI from 'openai'
import { ChatCompletionCreateParamsNonStreaming, ChatCompletionMessageParam } from 'openai/resources'
import { getDefaultModel, getTopNamingModel } from './assistant'
import { EVENT_NAMES } from './event'
export default class ProviderSDK { export default class ProviderSDK {
provider: Provider provider: Provider

View File

@ -4,6 +4,8 @@ import { setGenerating } from '@renderer/store/runtime'
import { Assistant, Message, Provider, Suggestion, Topic } from '@renderer/types' import { Assistant, Message, Provider, Suggestion, Topic } from '@renderer/types'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { isEmpty } from 'lodash'
import { import {
getAssistantProvider, getAssistantProvider,
getDefaultModel, getDefaultModel,
@ -13,7 +15,6 @@ import {
} from './assistant' } from './assistant'
import { EVENT_NAMES, EventEmitter } from './event' import { EVENT_NAMES, EventEmitter } from './event'
import ProviderSDK from './ProviderSDK' import ProviderSDK from './ProviderSDK'
import { isEmpty } from 'lodash'
export async function fetchChatCompletion({ export async function fetchChatCompletion({
messages, messages,

View File

@ -1,7 +1,7 @@
import { Assistant, Model, Provider, Topic } from '@renderer/types'
import store from '@renderer/store'
import { uuid } from '@renderer/utils'
import i18n from '@renderer/i18n' import i18n from '@renderer/i18n'
import store from '@renderer/store'
import { Assistant, Model, Provider, Topic } from '@renderer/types'
import { uuid } from '@renderer/utils'
export function getDefaultAssistant(): Assistant { export function getDefaultAssistant(): Assistant {
return { return {

View File

@ -2,11 +2,12 @@ import { combineReducers, configureStore } from '@reduxjs/toolkit'
import { useDispatch, useSelector, useStore } from 'react-redux' import { useDispatch, useSelector, useStore } from 'react-redux'
import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist' import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist'
import storage from 'redux-persist/lib/storage' import storage from 'redux-persist/lib/storage'
import assistants from './assistants' import assistants from './assistants'
import settings from './settings'
import llm from './llm' import llm from './llm'
import runtime from './runtime'
import migrate from './migrate' import migrate from './migrate'
import runtime from './runtime'
import settings from './settings'
const rootReducer = combineReducers({ const rootReducer = combineReducers({
assistants, assistants,

View File

@ -1,9 +1,10 @@
import { createMigrate } from 'redux-persist'
import { RootState } from '.'
import { SYSTEM_MODELS } from '@renderer/config/models' import { SYSTEM_MODELS } from '@renderer/config/models'
import { isEmpty } from 'lodash'
import i18n from '@renderer/i18n' import i18n from '@renderer/i18n'
import { Assistant } from '@renderer/types' import { Assistant } from '@renderer/types'
import { isEmpty } from 'lodash'
import { createMigrate } from 'redux-persist'
import { RootState } from '.'
const migrateConfig = { const migrateConfig = {
'2': (state: RootState) => { '2': (state: RootState) => {

View File

@ -1,9 +1,9 @@
import { v4 as uuidv4 } from 'uuid'
import imageCompression from 'browser-image-compression'
import { Assistant, AssistantSettings, Message, Model } from '@renderer/types'
import { GPTTokens } from 'gpt-tokens'
import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant' import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { Assistant, AssistantSettings, Message, Model } from '@renderer/types'
import imageCompression from 'browser-image-compression'
import { GPTTokens } from 'gpt-tokens'
import { takeRight } from 'lodash' import { takeRight } from 'lodash'
import { v4 as uuidv4 } from 'uuid'
export const runAsyncFunction = async (fn: () => void) => { export const runAsyncFunction = async (fn: () => void) => {
await fn() await fn()

View File

@ -3472,6 +3472,7 @@ __metadata:
eslint: "npm:^8.56.0" eslint: "npm:^8.56.0"
eslint-plugin-react: "npm:^7.34.3" eslint-plugin-react: "npm:^7.34.3"
eslint-plugin-react-hooks: "npm:^4.6.2" eslint-plugin-react-hooks: "npm:^4.6.2"
eslint-plugin-simple-import-sort: "npm:^12.1.1"
eslint-plugin-unused-imports: "npm:^4.0.0" eslint-plugin-unused-imports: "npm:^4.0.0"
gpt-tokens: "npm:^1.3.6" gpt-tokens: "npm:^1.3.6"
i18next: "npm:^23.11.5" i18next: "npm:^23.11.5"
@ -4698,6 +4699,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eslint-plugin-simple-import-sort@npm:^12.1.1":
version: 12.1.1
resolution: "eslint-plugin-simple-import-sort@npm:12.1.1"
peerDependencies:
eslint: ">=5.0.0"
checksum: 10c0/0ad1907ad9ddbadd1db655db0a9d0b77076e274b793a77b982c8525d808d868e6ecfce24f3a411e8a1fa551077387f9ebb38c00956073970ebd7ee6a029ce2b3
languageName: node
linkType: hard
"eslint-plugin-unused-imports@npm:^4.0.0": "eslint-plugin-unused-imports@npm:^4.0.0":
version: 4.0.0 version: 4.0.0
resolution: "eslint-plugin-unused-imports@npm:4.0.0" resolution: "eslint-plugin-unused-imports@npm:4.0.0"