mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 05:16:00 +08:00
parent
9adbeadeec
commit
fb62017e50
@ -12,13 +12,12 @@ import AppUnavailable from '../../base/app-unavailable'
|
|||||||
import useConversation from './hooks/use-conversation'
|
import useConversation from './hooks/use-conversation'
|
||||||
import s from './style.module.css'
|
import s from './style.module.css'
|
||||||
import { ToastContext } from '@/app/components/base/toast'
|
import { ToastContext } from '@/app/components/base/toast'
|
||||||
import Sidebar from '@/app/components/share/chatbot/sidebar'
|
|
||||||
import ConfigScene from '@/app/components/share/chatbot/config-scence'
|
import ConfigScene from '@/app/components/share/chatbot/config-scence'
|
||||||
import Header from '@/app/components/share/header'
|
import Header from '@/app/components/share/header'
|
||||||
import { /* delConversation, */ fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, fetchSuggestedQuestions, pinConversation, sendChatMessage, stopChatMessageResponding, unpinConversation, updateFeedback } from '@/service/share'
|
import { fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, fetchSuggestedQuestions, sendChatMessage, stopChatMessageResponding, updateFeedback } from '@/service/share'
|
||||||
import type { ConversationItem, SiteInfo } from '@/models/share'
|
import type { ConversationItem, SiteInfo } from '@/models/share'
|
||||||
import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
|
import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
|
||||||
import type { Feedbacktype, IChatItem } from '@/app/components/app/chat'
|
import type { Feedbacktype, IChatItem } from '@/app/components/app/chat/type'
|
||||||
import Chat from '@/app/components/app/chat'
|
import Chat from '@/app/components/app/chat'
|
||||||
import { changeLanguage } from '@/i18n/i18next-config'
|
import { changeLanguage } from '@/i18n/i18next-config'
|
||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
@ -26,7 +25,7 @@ import Loading from '@/app/components/base/loading'
|
|||||||
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel'
|
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel'
|
||||||
import { userInputsFormToPromptVariables } from '@/utils/model-config'
|
import { userInputsFormToPromptVariables } from '@/utils/model-config'
|
||||||
import type { InstalledApp } from '@/models/explore'
|
import type { InstalledApp } from '@/models/explore'
|
||||||
// import Confirm from '@/app/components/base/confirm'
|
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
||||||
|
|
||||||
export type IMainProps = {
|
export type IMainProps = {
|
||||||
isInstalledApp?: boolean
|
isInstalledApp?: boolean
|
||||||
@ -52,8 +51,6 @@ const Main: FC<IMainProps> = ({
|
|||||||
const [promptConfig, setPromptConfig] = useState<PromptConfig | null>(null)
|
const [promptConfig, setPromptConfig] = useState<PromptConfig | null>(null)
|
||||||
const [inited, setInited] = useState<boolean>(false)
|
const [inited, setInited] = useState<boolean>(false)
|
||||||
const [plan, setPlan] = useState<string>('basic') // basic/plus/pro
|
const [plan, setPlan] = useState<string>('basic') // basic/plus/pro
|
||||||
// in mobile, show sidebar by click button
|
|
||||||
const [isShowSidebar, { setTrue: showSidebar, setFalse: hideSidebar }] = useBoolean(false)
|
|
||||||
// Can Use metadata(https://beta.nextjs.org/docs/api-reference/metadata) to set title. But it only works in server side client.
|
// Can Use metadata(https://beta.nextjs.org/docs/api-reference/metadata) to set title. But it only works in server side client.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (siteInfo?.title) {
|
if (siteInfo?.title) {
|
||||||
@ -124,37 +121,6 @@ const Main: FC<IMainProps> = ({
|
|||||||
|
|
||||||
setControlUpdateConversationList(Date.now())
|
setControlUpdateConversationList(Date.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePin = async (id: string) => {
|
|
||||||
await pinConversation(isInstalledApp, installedAppInfo?.id, id)
|
|
||||||
notify({ type: 'success', message: t('common.api.success') })
|
|
||||||
noticeUpdateList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUnpin = async (id: string) => {
|
|
||||||
await unpinConversation(isInstalledApp, installedAppInfo?.id, id)
|
|
||||||
notify({ type: 'success', message: t('common.api.success') })
|
|
||||||
noticeUpdateList()
|
|
||||||
}
|
|
||||||
const [isShowConfirm, { setTrue: showConfirm, setFalse: hideConfirm }] = useBoolean(false)
|
|
||||||
const [toDeleteConversationId, setToDeleteConversationId] = useState('')
|
|
||||||
|
|
||||||
const handleDelete = (id: string) => {
|
|
||||||
setToDeleteConversationId(id)
|
|
||||||
hideSidebar() // mobile
|
|
||||||
showConfirm()
|
|
||||||
}
|
|
||||||
|
|
||||||
// const didDelete = async () => {
|
|
||||||
// await delConversation(isInstalledApp, installedAppInfo?.id, toDeleteConversationId)
|
|
||||||
// notify({ type: 'success', message: t('common.api.success') })
|
|
||||||
// hideConfirm()
|
|
||||||
// if (currConversationId === toDeleteConversationId)
|
|
||||||
// handleConversationIdChange('-1')
|
|
||||||
|
|
||||||
// noticeUpdateList()
|
|
||||||
// }
|
|
||||||
|
|
||||||
const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<SuggestedQuestionsAfterAnswerConfig | null>(null)
|
const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<SuggestedQuestionsAfterAnswerConfig | null>(null)
|
||||||
const [speechToTextConfig, setSpeechToTextConfig] = useState<SuggestedQuestionsAfterAnswerConfig | null>(null)
|
const [speechToTextConfig, setSpeechToTextConfig] = useState<SuggestedQuestionsAfterAnswerConfig | null>(null)
|
||||||
|
|
||||||
@ -235,20 +201,6 @@ const Main: FC<IMainProps> = ({
|
|||||||
}
|
}
|
||||||
useEffect(handleConversationSwitch, [currConversationId, inited])
|
useEffect(handleConversationSwitch, [currConversationId, inited])
|
||||||
|
|
||||||
const handleConversationIdChange = (id: string) => {
|
|
||||||
if (id === '-1') {
|
|
||||||
createNewChat()
|
|
||||||
setConversationIdChangeBecauseOfNew(true)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setConversationIdChangeBecauseOfNew(false)
|
|
||||||
}
|
|
||||||
// trigger handleConversationSwitch
|
|
||||||
setCurrConversationId(id, appId)
|
|
||||||
setIsShowSuggestion(false)
|
|
||||||
hideSidebar()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* chat info. chat is under conversation.
|
* chat info. chat is under conversation.
|
||||||
*/
|
*/
|
||||||
@ -416,6 +368,7 @@ const Main: FC<IMainProps> = ({
|
|||||||
const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
|
const [suggestQuestions, setSuggestQuestions] = useState<string[]>([])
|
||||||
const [messageTaskId, setMessageTaskId] = useState('')
|
const [messageTaskId, setMessageTaskId] = useState('')
|
||||||
const [hasStopResponded, setHasStopResponded, getHasStopResponded] = useGetState(false)
|
const [hasStopResponded, setHasStopResponded, getHasStopResponded] = useGetState(false)
|
||||||
|
const [shouldReload, setShouldReload] = useState(false)
|
||||||
|
|
||||||
const handleSend = async (message: string) => {
|
const handleSend = async (message: string) => {
|
||||||
if (isResponsing) {
|
if (isResponsing) {
|
||||||
@ -500,7 +453,9 @@ const Main: FC<IMainProps> = ({
|
|||||||
setIsShowSuggestion(true)
|
setIsShowSuggestion(true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError() {
|
onError(errorMessage, errorCode) {
|
||||||
|
if (['provider_not_initialize', 'completion_request_error'].includes(errorCode as string))
|
||||||
|
setShouldReload(true)
|
||||||
setResponsingFalse()
|
setResponsingFalse()
|
||||||
// role back placeholder answer
|
// role back placeholder answer
|
||||||
setChatList(produce(getChatList(), (draft) => {
|
setChatList(produce(getChatList(), (draft) => {
|
||||||
@ -525,31 +480,11 @@ const Main: FC<IMainProps> = ({
|
|||||||
notify({ type: 'success', message: t('common.api.success') })
|
notify({ type: 'success', message: t('common.api.success') })
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderSidebar = () => {
|
const handleReload = () => {
|
||||||
if (!appId || !siteInfo || !promptConfig)
|
setCurrConversationId('-1', appId, false)
|
||||||
return null
|
setChatNotStarted()
|
||||||
return (
|
setShouldReload(false)
|
||||||
<Sidebar
|
createNewChat()
|
||||||
list={conversationList}
|
|
||||||
isClearConversationList={isClearConversationList}
|
|
||||||
pinnedList={pinnedConversationList}
|
|
||||||
isClearPinnedConversationList={isClearPinnedConversationList}
|
|
||||||
onMoreLoaded={onMoreLoaded}
|
|
||||||
onPinnedMoreLoaded={onPinnedMoreLoaded}
|
|
||||||
isNoMore={!hasMore}
|
|
||||||
isPinnedNoMore={!hasPinnedMore}
|
|
||||||
onCurrentIdChange={handleConversationIdChange}
|
|
||||||
currentId={currConversationId}
|
|
||||||
copyRight={siteInfo.copyright || siteInfo.title}
|
|
||||||
isInstalledApp={isInstalledApp}
|
|
||||||
installedAppId={installedAppInfo?.id}
|
|
||||||
siteInfo={siteInfo}
|
|
||||||
onPin={handlePin}
|
|
||||||
onUnpin={handleUnpin}
|
|
||||||
controlUpdateList={controlUpdateConversationList}
|
|
||||||
onDelete={handleDelete}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const difyIcon = (
|
const difyIcon = (
|
||||||
@ -571,24 +506,9 @@ const Main: FC<IMainProps> = ({
|
|||||||
icon_background={siteInfo.icon_background}
|
icon_background={siteInfo.icon_background}
|
||||||
isEmbedScene={true}
|
isEmbedScene={true}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
// onShowSideBar={showSidebar}
|
|
||||||
// onCreateNewChat={() => handleConversationIdChange('-1')}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={'flex bg-white overflow-hidden'}>
|
<div className={'flex bg-white overflow-hidden'}>
|
||||||
{/* sidebar */}
|
|
||||||
{/* {!isMobile && renderSidebar()} */}
|
|
||||||
{/* {isMobile && isShowSidebar && (
|
|
||||||
<div className='fixed inset-0 z-50'
|
|
||||||
style={{ backgroundColor: 'rgba(35, 56, 118, 0.2)' }}
|
|
||||||
onClick={hideSidebar}
|
|
||||||
>
|
|
||||||
<div className='inline-block' onClick={e => e.stopPropagation()}>
|
|
||||||
{renderSidebar()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
{/* main */}
|
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
isInstalledApp ? s.installedApp : 'h-[calc(100vh_-_3rem)]',
|
isInstalledApp ? s.installedApp : 'h-[calc(100vh_-_3rem)]',
|
||||||
'flex-grow flex flex-col overflow-y-auto',
|
'flex-grow flex flex-col overflow-y-auto',
|
||||||
@ -606,7 +526,22 @@ const Main: FC<IMainProps> = ({
|
|||||||
onInputsChange={setCurrInputs}
|
onInputsChange={setCurrInputs}
|
||||||
plan={plan}
|
plan={plan}
|
||||||
></ConfigScene>
|
></ConfigScene>
|
||||||
|
{
|
||||||
|
shouldReload && (
|
||||||
|
<div className='flex items-center justify-between mb-5 px-4 py-2 bg-[#FEF0C7]'>
|
||||||
|
<div className='flex items-center text-xs font-medium text-[#DC6803]'>
|
||||||
|
<AlertTriangle className='mr-2 w-4 h-4' />
|
||||||
|
{t('share.chat.temporarySystemIssue')}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='flex items-center px-3 h-7 bg-white shadow-xs rounded-md text-xs font-medium text-gray-700 cursor-pointer'
|
||||||
|
onClick={handleReload}
|
||||||
|
>
|
||||||
|
{t('share.chat.tryToSolve')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
{
|
{
|
||||||
hasSetInputs && (
|
hasSetInputs && (
|
||||||
<div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[76px]'), 'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden')}>
|
<div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[76px]'), 'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden')}>
|
||||||
|
@ -27,6 +27,8 @@ const translation = {
|
|||||||
title: 'Delete conversation',
|
title: 'Delete conversation',
|
||||||
content: 'Are you sure you want to delete this conversation?',
|
content: 'Are you sure you want to delete this conversation?',
|
||||||
},
|
},
|
||||||
|
tryToSolve: 'Try to solve',
|
||||||
|
temporarySystemIssue: 'Sorry, temporary system issue.',
|
||||||
},
|
},
|
||||||
generation: {
|
generation: {
|
||||||
tabs: {
|
tabs: {
|
||||||
|
@ -23,6 +23,8 @@ const translation = {
|
|||||||
title: '删除对话',
|
title: '删除对话',
|
||||||
content: '您确定要删除此对话吗?',
|
content: '您确定要删除此对话吗?',
|
||||||
},
|
},
|
||||||
|
tryToSolve: '尝试解决',
|
||||||
|
temporarySystemIssue: '抱歉,临时系统问题。',
|
||||||
},
|
},
|
||||||
generation: {
|
generation: {
|
||||||
tabs: {
|
tabs: {
|
||||||
|
@ -28,12 +28,13 @@ export type IOnDataMoreInfo = {
|
|||||||
taskId?: string
|
taskId?: string
|
||||||
messageId: string
|
messageId: string
|
||||||
errorMessage?: string
|
errorMessage?: string
|
||||||
|
errorCode?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IOnData = (message: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => void
|
export type IOnData = (message: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => void
|
||||||
export type IOnThought = (though: ThoughtItem) => void
|
export type IOnThought = (though: ThoughtItem) => void
|
||||||
export type IOnCompleted = (hasError?: boolean) => void
|
export type IOnCompleted = (hasError?: boolean) => void
|
||||||
export type IOnError = (msg: string) => void
|
export type IOnError = (msg: string, code?: string) => void
|
||||||
|
|
||||||
type IOtherOptions = {
|
type IOtherOptions = {
|
||||||
isPublicAPI?: boolean
|
isPublicAPI?: boolean
|
||||||
@ -102,6 +103,7 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted
|
|||||||
conversationId: undefined,
|
conversationId: undefined,
|
||||||
messageId: '',
|
messageId: '',
|
||||||
errorMessage: bufferObj.message,
|
errorMessage: bufferObj.message,
|
||||||
|
errorCode: bufferObj.code,
|
||||||
})
|
})
|
||||||
hasError = true
|
hasError = true
|
||||||
onCompleted && onCompleted(true)
|
onCompleted && onCompleted(true)
|
||||||
@ -345,7 +347,7 @@ export const ssePost = (url: string, fetchOptions: any, { isPublicAPI = false, o
|
|||||||
return handleStream(res, (str: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => {
|
return handleStream(res, (str: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => {
|
||||||
if (moreInfo.errorMessage) {
|
if (moreInfo.errorMessage) {
|
||||||
// debugger
|
// debugger
|
||||||
onError?.(moreInfo.errorMessage)
|
onError?.(moreInfo.errorMessage, moreInfo.errorCode)
|
||||||
if (moreInfo.errorMessage !== 'AbortError: The user aborted a request.')
|
if (moreInfo.errorMessage !== 'AbortError: The user aborted a request.')
|
||||||
Toast.notify({ type: 'error', message: moreInfo.errorMessage })
|
Toast.notify({ type: 'error', message: moreInfo.errorMessage })
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user