Commit 3f2bc97b authored by Joel's avatar Joel

Merge branch 'feat/universal-chat-fe' into deploy/dev

parents ff4f6569 b30706ff
......@@ -161,7 +161,7 @@ const Chat: FC<IChatProps> = ({
if (item.isAnswer) {
const isLast = item.id === chatList[chatList.length - 1].id
const thoughts = item.agent_thoughts?.filter(item => item.thought !== '[DONE]')
const isThinking = item.agent_thoughts && item.agent_thoughts?.length > 0 && !item.agent_thoughts.find(item => item.thought !== '[DONE]')
const isThinking = item.agent_thoughts && item.agent_thoughts?.length > 0 && !item.agent_thoughts.some(item => item.thought === '[DONE]')
return <Answer
key={item.id}
item={item}
......
......@@ -70,7 +70,7 @@ const Thought: FC<IThoughtProps> = ({
<div className='flex items-center h-6 space-x-1 cursor-pointer' onClick={() => setIsShowDetail(!isShowDetail)} >
{!isThinking ? <ThoughtList /> : <div className='animate-spin'><LodingIcon /></div>}
<div dangerouslySetInnerHTML= {{
__html: isThinking ? getThoughtText(list[0]) : (t(`explore.universalChat.thought.${isShowDetail ? 'hide' : 'show'}`) + t('explore.universalChat.thought.processOfThought')),
__html: isThinking ? getThoughtText(list[list.length - 1]) : (t(`explore.universalChat.thought.${isShowDetail ? 'hide' : 'show'}`) + t('explore.universalChat.thought.processOfThought')),
}}
></div>
<ChevronDown className={isShowDetail ? 'rotate-180' : '' } />
......
......@@ -3,7 +3,6 @@ import type { FC } from 'react'
import React from 'react'
import cn from 'classnames'
import { useTranslation } from 'react-i18next'
import { useBoolean, useClickAway } from 'ahooks'
import s from './style.module.css'
import Config from '@/app/components/explore/universal-chat/config'
......@@ -18,29 +17,17 @@ const ConfigViewPanel: FC<Props> = ({
dataSets,
}) => {
const { t } = useTranslation()
const [isShowConfig, { setFalse: hideConfig, toggle: toggleShowConfig }] = useBoolean(false)
const configContentRef = React.useRef(null)
useClickAway(() => {
hideConfig()
}, configContentRef)
return (
<div ref={configContentRef} className='relative'>
<div onClick={toggleShowConfig} className={cn(s.btn, 'flex h-8 w-8 rounded-lg border border-gray-200 bg-white cursor-pointer')}></div>
{isShowConfig && (
<div className={cn('absolute top-9 right-0 z-20 p-4 bg-white rounded-2xl shadow-md', s.panelBorder)}>
<div className='w-[368px]'>
<Config
readonly
modelId={modelId}
plugins={plugins}
dataSets={dataSets}
/>
<div className='mt-3 text-xs leading-[18px] text-500 font-normal'>{t('explore.universalChat.viewConfigDetailTip')}</div>
</div>
</div>
)}
<div className={cn('absolute top-9 right-0 z-20 p-4 bg-white rounded-2xl shadow-md', s.panelBorder)}>
<div className='w-[368px]'>
<Config
readonly
modelId={modelId}
plugins={plugins}
dataSets={dataSets}
/>
<div className='mt-3 text-xs leading-[18px] text-500 font-normal'>{t('explore.universalChat.viewConfigDetailTip')}</div>
</div>
</div>
)
}
......
......@@ -2,22 +2,26 @@
import type { FC } from 'react'
import React from 'react'
import cn from 'classnames'
import { useBoolean, useClickAway } from 'ahooks'
import s from './style.module.css'
import ModelIcon from '@/app/components/app/configuration/config-model/model-icon'
import { Google, WebReader, Wikipedia } from '@/app/components/base/icons/src/public/plugins'
import ConfigDetail from '@/app/components/explore/universal-chat/config-view/detail'
export type ISummaryProps = {
modelId: string
pluginIds: string[]
plugins: Record<string, boolean>
dataSets: any[]
}
const getColorInfo = (modelId: string) => {
if (modelId === 'gpt-4')
return 'bg-[#EBE9FE] border-[#F4F3FF]'
return s.gpt4
if (modelId === 'claude-2')
return 'bg-[#F9EBDF] border-[#FCF3EB]'
return s.claude
return 'bg-[#D3F8DF] border-[#EDFCF2]'
return s.gpt3
}
const getPlugIcon = (pluginId: string) => {
......@@ -36,29 +40,45 @@ const getPlugIcon = (pluginId: string) => {
const Summary: FC<ISummaryProps> = ({
modelId,
pluginIds,
plugins,
dataSets,
}) => {
const pluginIds = Object.keys(plugins).filter(key => plugins[key])
const [isShowConfig, { setFalse: hideConfig, toggle: toggleShowConfig }] = useBoolean(false)
const configContentRef = React.useRef(null)
useClickAway(() => {
hideConfig()
}, configContentRef)
return (
<div className={cn(getColorInfo(modelId), 'flex items-center px-1 h-8 rounded-lg border')}>
<ModelIcon modelId={modelId} className='!w-6 !h-6' />
<div className='ml-2 text-[13px] font-medium text-gray-900'>{modelId}</div>
{
pluginIds.length > 0 && (
<div className='ml-1.5 flex items-center'>
<div className='mr-1 h-3 w-[1px] bg-[#000] opacity-[0.05]'></div>
<div className='flex space-x-1'>
{pluginIds.map(pluginId => (
<div
key={pluginId}
className={`flex items-center justify-center w-6 h-6 rounded-md ${s.border} bg-white`}
>
{getPlugIcon(pluginId)}</div>
))}
<div ref={configContentRef} className='relative'>
<div onClick={toggleShowConfig} className={cn(getColorInfo(modelId), 'flex items-center px-1 h-8 rounded-lg border cursor-pointer')}>
<ModelIcon modelId={modelId} className='!w-6 !h-6' />
<div className='ml-2 text-[13px] font-medium text-gray-900'>{modelId}</div>
{
pluginIds.length > 0 && (
<div className='ml-1.5 flex items-center'>
<div className='mr-1 h-3 w-[1px] bg-[#000] opacity-[0.05]'></div>
<div className='flex space-x-1'>
{pluginIds.map(pluginId => (
<div
key={pluginId}
className={`flex items-center justify-center w-6 h-6 rounded-md ${s.border} bg-white`}
>
{getPlugIcon(pluginId)}</div>
))}
</div>
</div>
</div>
)
}
)
}
</div>
{isShowConfig && (
<ConfigDetail
modelId={modelId} plugins={plugins} dataSets={dataSets}
/>
)}
</div>
)
}
export default React.memo(Summary)
.border {
border: 1px solid rgba(0, 0, 0, 0.05);
}
.gpt3 {
background: linear-gradient(0deg, #D3F8DF, #D3F8DF),
linear-gradient(0deg, #EDFCF2, #EDFCF2);
border: 1px solid rgba(211, 248, 223, 1)
}
.gpt4 {
background: linear-gradient(0deg, #EBE9FE, #EBE9FE),
linear-gradient(0deg, #F4F3FF, #F4F3FF);
border: 1px solid rgba(235, 233, 254, 1)
}
.claude {
background: linear-gradient(0deg, #F9EBDF, #F9EBDF),
linear-gradient(0deg, #FCF3EB, #FCF3EB);
border: 1px solid rgba(249, 235, 223, 1)
}
\ No newline at end of file
......@@ -37,8 +37,9 @@ import { userInputsFormToPromptVariables } from '@/utils/model-config'
import Confirm from '@/app/components/base/confirm'
import type { DataSet } from '@/models/datasets'
import ConfigSummary from '@/app/components/explore/universal-chat/config-view/summary'
import ConfigDetail from '@/app/components/explore/universal-chat/config-view/detail'
import { fetchDatasets } from '@/service/datasets'
import ItemOperation from '@/app/components/explore/item-operation'
const APP_ID = 'universal-chat'
const DEFAULT_MODEL_ID = 'gpt-3.5-turbo' // gpt-4, claude-2
const DEFAULT_PLUGIN = {
......@@ -131,12 +132,14 @@ const Main: FC<IMainProps> = () => {
}
const handlePin = async (id: string) => {
await pinConversation(id)
setControlItemOpHide(Date.now())
notify({ type: 'success', message: t('common.api.success') })
noticeUpdateList()
}
const handleUnpin = async (id: string) => {
await unpinConversation(id)
setControlItemOpHide(Date.now())
notify({ type: 'success', message: t('common.api.success') })
noticeUpdateList()
}
......@@ -150,6 +153,7 @@ const Main: FC<IMainProps> = () => {
const didDelete = async () => {
await delConversation(toDeleteConversationId)
setControlItemOpHide(Date.now())
notify({ type: 'success', message: t('common.api.success') })
hideConfirm()
if (currConversationId === toDeleteConversationId)
......@@ -510,10 +514,8 @@ const Main: FC<IMainProps> = () => {
}
},
onThought(thought) {
if (thought.thought === '[DONE]')
return
responseItem.id = thought.message_id;
// thought finished then start to return message. Warning: use push agent_thoughts.push would caused problem when the thought is more then 2
responseItem.id = thought.message_id;
(responseItem as any).agent_thoughts = [...(responseItem as any).agent_thoughts, thought] // .push(thought)
const newListWithAnswer = produce(
getChatList().filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
......@@ -595,7 +597,8 @@ const Main: FC<IMainProps> = () => {
setPlugins(DEFAULT_PLUGIN)
setDateSets([])
}
const isCurrConversationPinned = !!pinnedConversationList.find(item => item.id === currConversationId)
const [controlItemOpHide, setControlItemOpHide] = useState(0)
if (appUnavailable)
return <AppUnavailable isUnknwonReason={isUnknwonReason} />
......@@ -635,9 +638,21 @@ const Main: FC<IMainProps> = () => {
<div className='absolute z-10 top-0 left-0 right-0 flex items-center justify-between border-b border-gray-100 mobile:h-12 tablet:h-16 px-8 bg-white'>
<div className='text-gray-900'>{conversationName}</div>
<div className='flex items-center shrink-0 ml-2 space-x-2'>
<ConfigSummary modelId={modelId} pluginIds={Object.keys(plugins).filter(key => plugins[key])}
<ConfigSummary
modelId={modelId}
plugins={plugins}
dataSets={dataSets}
/>
<ConfigDetail modelId={modelId} plugins={plugins} dataSets={dataSets}/>
<div className={cn('flex w-8 h-8 justify-center items-center shrink-0 rounded-lg border border-gray-200')} onClick={e => e.stopPropagation()}>
<ItemOperation
key={controlItemOpHide}
className='!w-8 !h-8'
isPinned={isCurrConversationPinned}
togglePin={() => isCurrConversationPinned ? handleUnpin(currConversationId) : handlePin(currConversationId)}
isShowDelete
onDelete={() => handleDelete(currConversationId)}
/>
</div>
</div>
</div>
)}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment