mirror of https://github.com/langgenius/dify.git
fix prompt log
This commit is contained in:
parent
cd01c890e1
commit
9638885a67
|
|
@ -1,6 +1,6 @@
|
|||
'use client'
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { UserCircleIcon } from '@heroicons/react/24/solid'
|
||||
import cn from 'classnames'
|
||||
|
|
@ -27,7 +27,6 @@ import type { Emoji } from '@/app/components/tools/types'
|
|||
import type { VisionFile } from '@/types/app'
|
||||
import ImageGallery from '@/app/components/base/image-gallery'
|
||||
import Log from '@/app/components/app/chat/log'
|
||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||
|
||||
const IconWrapper: FC<{ children: React.ReactNode | string }> = ({ children }) => {
|
||||
return <div className={'rounded-lg h-6 w-6 flex items-center justify-center hover:bg-gray-100'}>
|
||||
|
|
@ -234,23 +233,9 @@ const Answer: FC<IAnswerProps> = ({
|
|||
</div>
|
||||
)
|
||||
|
||||
const [showPromptLogModal, setShowPromptLogModal] = useState(false)
|
||||
const [width, setWidth] = useState(0)
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
const adjustModalWidth = () => {
|
||||
if (ref.current)
|
||||
setWidth(document.body.clientWidth - (ref.current?.clientWidth + 56 + 16))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
adjustModalWidth()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
// data-id for debug the item message is right
|
||||
<div key={id} data-id={id} ref={ref}>
|
||||
<div key={id} data-id={id}>
|
||||
<div className='flex items-start'>
|
||||
{
|
||||
answerIcon || (
|
||||
|
|
@ -336,7 +321,7 @@ const Answer: FC<IAnswerProps> = ({
|
|||
{((isShowPromptLog && !isResponding) || (!item.isOpeningStatement && isShowTextToSpeech)) && (
|
||||
<div className='hidden group-hover:flex items-center h-[28px] p-0.5 rounded-lg bg-white border-[0.5px] border-gray-100 shadow-md'>
|
||||
{isShowPromptLog && !isResponding && (
|
||||
<Log runID={item.workflow_run_id} setShowModal={setShowPromptLogModal} />
|
||||
<Log logItem={item} />
|
||||
)}
|
||||
{!item.isOpeningStatement && isShowTextToSpeech && (
|
||||
<>
|
||||
|
|
@ -386,13 +371,6 @@ const Answer: FC<IAnswerProps> = ({
|
|||
{!feedbackDisabled && renderFeedbackRating(feedback?.rating, !isHideFeedbackEdit, displayScene !== 'console')}
|
||||
</div>
|
||||
</div>
|
||||
{showPromptLogModal && (
|
||||
<PromptLogModal
|
||||
width={width}
|
||||
log={item.log || []}
|
||||
onCancel={() => setShowPromptLogModal(false)}
|
||||
/>
|
||||
)}
|
||||
{more && <MoreInfo className='invisible group-hover:visible' more={more} isQuestion={false} />}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,43 +1,32 @@
|
|||
import type { Dispatch, FC, ReactNode, SetStateAction } from 'react'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { File02 } from '@/app/components/base/icons/src/vender/line/files'
|
||||
|
||||
export type LogData = {
|
||||
role: string
|
||||
text: string
|
||||
}
|
||||
import type { IChatItem } from '@/app/components/app/chat/type'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
|
||||
type LogProps = {
|
||||
runID?: string
|
||||
setShowModal: Dispatch<SetStateAction<boolean>>
|
||||
children?: (v: Dispatch<SetStateAction<boolean>>) => ReactNode
|
||||
logItem: IChatItem
|
||||
}
|
||||
const Log: FC<LogProps> = ({
|
||||
children,
|
||||
runID,
|
||||
setShowModal,
|
||||
logItem,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { setCurrentLogItem, setShowPromptLogModal } = useAppStore()
|
||||
const { workflow_run_id: runID } = logItem
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
children
|
||||
? children(setShowModal)
|
||||
: (
|
||||
<div
|
||||
className='p-1 flex items-center justify-center rounded-[6px] hover:bg-gray-50 cursor-pointer'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setShowModal(true)
|
||||
}}
|
||||
>
|
||||
<File02 className='mr-1 w-4 h-4 text-gray-500' />
|
||||
<div className='text-xs leading-4 text-gray-500'>{runID ? t('appLog.viewLog') : t('appLog.promptLog')}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</>
|
||||
<div
|
||||
className='p-1 flex items-center justify-center rounded-[6px] hover:bg-gray-50 cursor-pointer'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
setCurrentLogItem(logItem)
|
||||
setShowPromptLogModal(true)
|
||||
}}
|
||||
>
|
||||
<File02 className='mr-1 w-4 h-4 text-gray-500' />
|
||||
<div className='text-xs leading-4 text-gray-500'>{runID ? t('appLog.viewLog') : t('appLog.promptLog')}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import {
|
||||
HandThumbDownIcon,
|
||||
|
|
@ -35,6 +35,8 @@ import ModelName from '@/app/components/header/account-setting/model-provider-pa
|
|||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import TextGeneration from '@/app/components/app/text-generate/item'
|
||||
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
|
||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
|
||||
type IConversationList = {
|
||||
logs?: ChatConversationsResponse | CompletionConversationsResponse
|
||||
|
|
@ -141,6 +143,7 @@ type IDetailPanel<T> = {
|
|||
|
||||
function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionConversationFullDetailResponse>({ detail, onFeedback }: IDetailPanel<T>) {
|
||||
const { onClose, appDetail } = useContext(DrawerContext)
|
||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore()
|
||||
const { t } = useTranslation()
|
||||
const [items, setItems] = React.useState<IChatItem[]>([])
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
|
|
@ -228,144 +231,168 @@ function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionCo
|
|||
return value
|
||||
}
|
||||
|
||||
return (<div className='rounded-xl border-[0.5px] border-gray-200 h-full flex flex-col overflow-auto'>
|
||||
{/* Panel Header */}
|
||||
<div className='border-b border-gray-100 py-4 px-6 flex items-center justify-between'>
|
||||
<div>
|
||||
<div className='text-gray-500 text-[10px] leading-[14px]'>{isChatMode ? t('appLog.detail.conversationId') : t('appLog.detail.time')}</div>
|
||||
<div className='text-gray-700 text-[13px] leading-[18px]'>{isChatMode ? detail.id?.split('-').slice(-1)[0] : dayjs.unix(detail.created_at).format(t('appLog.dateTimeFormat') as string)}</div>
|
||||
</div>
|
||||
<div className='flex items-center flex-wrap gap-y-1 justify-end'>
|
||||
<div
|
||||
className={cn('mr-2 flex items-center border h-8 px-2 space-x-2 rounded-lg bg-indigo-25 border-[#2A87F5]')}
|
||||
>
|
||||
<ModelIcon
|
||||
className='!w-5 !h-5'
|
||||
provider={currentProvider}
|
||||
modelName={currentModel?.model}
|
||||
/>
|
||||
<ModelName
|
||||
modelItem={currentModel!}
|
||||
showMode
|
||||
/>
|
||||
const [width, setWidth] = useState(0)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
const adjustModalWidth = () => {
|
||||
if (ref.current)
|
||||
setWidth(document.body.clientWidth - (ref.current?.clientWidth + 16) - 8)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
adjustModalWidth()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div ref={ref} className='rounded-xl border-[0.5px] border-gray-200 h-full flex flex-col overflow-auto'>
|
||||
{/* Panel Header */}
|
||||
<div className='border-b border-gray-100 py-4 px-6 flex items-center justify-between'>
|
||||
<div>
|
||||
<div className='text-gray-500 text-[10px] leading-[14px]'>{isChatMode ? t('appLog.detail.conversationId') : t('appLog.detail.time')}</div>
|
||||
<div className='text-gray-700 text-[13px] leading-[18px]'>{isChatMode ? detail.id?.split('-').slice(-1)[0] : dayjs.unix(detail.created_at).format(t('appLog.dateTimeFormat') as string)}</div>
|
||||
</div>
|
||||
<Popover
|
||||
position='br'
|
||||
className='!w-[280px]'
|
||||
btnClassName='mr-4 !bg-gray-50 !py-1.5 !px-2.5 border-none font-normal'
|
||||
btnElement={<>
|
||||
<span className='text-[13px]'>{targetTone}</span>
|
||||
<InformationCircleIcon className='h-4 w-4 text-gray-800 ml-1.5' />
|
||||
</>}
|
||||
htmlContent={<div className='w-[280px]'>
|
||||
<div className='flex justify-between py-2 px-4 font-medium text-sm text-gray-700'>
|
||||
<span>Tone of responses</span>
|
||||
<div>{targetTone}</div>
|
||||
</div>
|
||||
{['temperature', 'top_p', 'presence_penalty', 'max_tokens', 'stop'].map((param: string, index: number) => {
|
||||
return <div className='flex justify-between py-2 px-4 bg-gray-50' key={index}>
|
||||
<span className='text-xs text-gray-700'>{PARAM_MAP[param as keyof typeof PARAM_MAP]}</span>
|
||||
<span className='text-gray-800 font-medium text-xs'>{getParamValue(param)}</span>
|
||||
<div className='flex items-center flex-wrap gap-y-1 justify-end'>
|
||||
<div
|
||||
className={cn('mr-2 flex items-center border h-8 px-2 space-x-2 rounded-lg bg-indigo-25 border-[#2A87F5]')}
|
||||
>
|
||||
<ModelIcon
|
||||
className='!w-5 !h-5'
|
||||
provider={currentProvider}
|
||||
modelName={currentModel?.model}
|
||||
/>
|
||||
<ModelName
|
||||
modelItem={currentModel!}
|
||||
showMode
|
||||
/>
|
||||
</div>
|
||||
<Popover
|
||||
position='br'
|
||||
className='!w-[280px]'
|
||||
btnClassName='mr-4 !bg-gray-50 !py-1.5 !px-2.5 border-none font-normal'
|
||||
btnElement={<>
|
||||
<span className='text-[13px]'>{targetTone}</span>
|
||||
<InformationCircleIcon className='h-4 w-4 text-gray-800 ml-1.5' />
|
||||
</>}
|
||||
htmlContent={<div className='w-[280px]'>
|
||||
<div className='flex justify-between py-2 px-4 font-medium text-sm text-gray-700'>
|
||||
<span>Tone of responses</span>
|
||||
<div>{targetTone}</div>
|
||||
</div>
|
||||
})}
|
||||
</div>}
|
||||
/>
|
||||
<div className='w-6 h-6 rounded-lg flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
|
||||
<XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
|
||||
{['temperature', 'top_p', 'presence_penalty', 'max_tokens', 'stop'].map((param: string, index: number) => {
|
||||
return <div className='flex justify-between py-2 px-4 bg-gray-50' key={index}>
|
||||
<span className='text-xs text-gray-700'>{PARAM_MAP[param as keyof typeof PARAM_MAP]}</span>
|
||||
<span className='text-gray-800 font-medium text-xs'>{getParamValue(param)}</span>
|
||||
</div>
|
||||
})}
|
||||
</div>}
|
||||
/>
|
||||
<div className='w-6 h-6 rounded-lg flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
|
||||
<XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/* Panel Body */}
|
||||
{(varList.length > 0 || (!isChatMode && message_files.length > 0)) && (
|
||||
<div className='px-6 pt-4 pb-2'>
|
||||
<VarPanel
|
||||
varList={varList}
|
||||
message_files={message_files}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isChatMode
|
||||
? <div className="px-6 py-4">
|
||||
<div className='flex h-[18px] items-center space-x-3'>
|
||||
<div className='leading-[18px] text-xs font-semibold text-gray-500 uppercase'>{t('appLog.table.header.output')}</div>
|
||||
<div className='grow h-[1px]' style={{
|
||||
background: 'linear-gradient(270deg, rgba(243, 244, 246, 0) 0%, rgb(243, 244, 246) 100%)',
|
||||
}}></div>
|
||||
{/* Panel Body */}
|
||||
{(varList.length > 0 || (!isChatMode && message_files.length > 0)) && (
|
||||
<div className='px-6 pt-4 pb-2'>
|
||||
<VarPanel
|
||||
varList={varList}
|
||||
message_files={message_files}
|
||||
/>
|
||||
</div>
|
||||
<TextGeneration
|
||||
className='mt-2'
|
||||
content={detail.message.answer}
|
||||
messageId={detail.message.id}
|
||||
isError={false}
|
||||
onRetry={() => { }}
|
||||
isInstalledApp={false}
|
||||
supportFeedback
|
||||
feedback={detail.message.feedbacks.find((item: any) => item.from_source === 'admin')}
|
||||
onFeedback={feedback => onFeedback(detail.message.id, feedback)}
|
||||
supportAnnotation
|
||||
isShowTextToSpeech
|
||||
appId={appDetail?.id}
|
||||
varList={varList}
|
||||
/>
|
||||
</div>
|
||||
: items.length < 8
|
||||
? <div className="px-2.5 pt-4 mb-4">
|
||||
<Chat
|
||||
chatList={items}
|
||||
isHideSendInput={true}
|
||||
onFeedback={onFeedback}
|
||||
displayScene='console'
|
||||
isShowPromptLog
|
||||
)}
|
||||
|
||||
{!isChatMode
|
||||
? <div className="px-6 py-4">
|
||||
<div className='flex h-[18px] items-center space-x-3'>
|
||||
<div className='leading-[18px] text-xs font-semibold text-gray-500 uppercase'>{t('appLog.table.header.output')}</div>
|
||||
<div className='grow h-[1px]' style={{
|
||||
background: 'linear-gradient(270deg, rgba(243, 244, 246, 0) 0%, rgb(243, 244, 246) 100%)',
|
||||
}}></div>
|
||||
</div>
|
||||
<TextGeneration
|
||||
className='mt-2'
|
||||
content={detail.message.answer}
|
||||
messageId={detail.message.id}
|
||||
isError={false}
|
||||
onRetry={() => { }}
|
||||
isInstalledApp={false}
|
||||
supportFeedback
|
||||
feedback={detail.message.feedbacks.find((item: any) => item.from_source === 'admin')}
|
||||
onFeedback={feedback => onFeedback(detail.message.id, feedback)}
|
||||
supportAnnotation
|
||||
isShowTextToSpeech
|
||||
appId={appDetail?.id}
|
||||
onChatListChange={setItems}
|
||||
varList={varList}
|
||||
/>
|
||||
</div>
|
||||
: <div
|
||||
className="px-2.5 py-4"
|
||||
id="scrollableDiv"
|
||||
style={{
|
||||
height: 1000, // Specify a value
|
||||
overflow: 'auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column-reverse',
|
||||
}}>
|
||||
{/* Put the scroll bar always on the bottom */}
|
||||
<InfiniteScroll
|
||||
scrollableTarget="scrollableDiv"
|
||||
dataLength={items.length}
|
||||
next={fetchData}
|
||||
hasMore={hasMore}
|
||||
loader={<div className='text-center text-gray-400 text-xs'>{t('appLog.detail.loading')}...</div>}
|
||||
// endMessage={<div className='text-center'>Nothing more to show</div>}
|
||||
// below props only if you need pull down functionality
|
||||
refreshFunction={fetchData}
|
||||
pullDownToRefresh
|
||||
pullDownToRefreshThreshold={50}
|
||||
// pullDownToRefreshContent={
|
||||
// <div className='text-center'>Pull down to refresh</div>
|
||||
// }
|
||||
// releaseToRefreshContent={
|
||||
// <div className='text-center'>Release to refresh</div>
|
||||
// }
|
||||
// To put endMessage and loader to the top.
|
||||
style={{ display: 'flex', flexDirection: 'column-reverse' }}
|
||||
inverse={true}
|
||||
>
|
||||
: items.length < 8
|
||||
? <div className="px-2.5 pt-4 mb-4">
|
||||
<Chat
|
||||
chatList={items}
|
||||
isHideSendInput={true}
|
||||
onFeedback={onFeedback}
|
||||
displayScene='console'
|
||||
isShowPromptLog
|
||||
supportAnnotation
|
||||
isShowTextToSpeech
|
||||
appId={appDetail?.id}
|
||||
onChatListChange={setItems}
|
||||
/>
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
}
|
||||
</div>)
|
||||
</div>
|
||||
: <div
|
||||
className="px-2.5 py-4"
|
||||
id="scrollableDiv"
|
||||
style={{
|
||||
height: 1000, // Specify a value
|
||||
overflow: 'auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column-reverse',
|
||||
}}>
|
||||
{/* Put the scroll bar always on the bottom */}
|
||||
<InfiniteScroll
|
||||
scrollableTarget="scrollableDiv"
|
||||
dataLength={items.length}
|
||||
next={fetchData}
|
||||
hasMore={hasMore}
|
||||
loader={<div className='text-center text-gray-400 text-xs'>{t('appLog.detail.loading')}...</div>}
|
||||
// endMessage={<div className='text-center'>Nothing more to show</div>}
|
||||
// below props only if you need pull down functionality
|
||||
refreshFunction={fetchData}
|
||||
pullDownToRefresh
|
||||
pullDownToRefreshThreshold={50}
|
||||
// pullDownToRefreshContent={
|
||||
// <div className='text-center'>Pull down to refresh</div>
|
||||
// }
|
||||
// releaseToRefreshContent={
|
||||
// <div className='text-center'>Release to refresh</div>
|
||||
// }
|
||||
// To put endMessage and loader to the top.
|
||||
style={{ display: 'flex', flexDirection: 'column-reverse' }}
|
||||
inverse={true}
|
||||
>
|
||||
<Chat
|
||||
chatList={items}
|
||||
isHideSendInput={true}
|
||||
onFeedback={onFeedback}
|
||||
displayScene='console'
|
||||
isShowPromptLog
|
||||
/>
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
}
|
||||
{showPromptLogModal && (
|
||||
<PromptLogModal
|
||||
width={width}
|
||||
currentLogItem={currentLogItem}
|
||||
onCancel={() => {
|
||||
setCurrentLogItem()
|
||||
setShowPromptLogModal(false)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
import { create } from 'zustand'
|
||||
import type { App } from '@/types/app'
|
||||
import type { IChatItem } from '@/app/components/app/chat/type'
|
||||
|
||||
type State = {
|
||||
appDetail?: App
|
||||
appSidebarExpand: string
|
||||
currentLogItem?: IChatItem
|
||||
showPromptLogModal: boolean
|
||||
showMessageLogModal: boolean
|
||||
}
|
||||
|
||||
type Action = {
|
||||
setAppDetail: (appDetail?: App) => void
|
||||
setAppSiderbarExpand: (state: string) => void
|
||||
setCurrentLogItem: (item?: IChatItem) => void
|
||||
setShowPromptLogModal: (showPromptLogModal: boolean) => void
|
||||
setShowMessageLogModal: (showMessageLogModal: boolean) => void
|
||||
}
|
||||
|
||||
export const useStore = create<State & Action>(set => ({
|
||||
|
|
@ -16,4 +23,10 @@ export const useStore = create<State & Action>(set => ({
|
|||
setAppDetail: appDetail => set(() => ({ appDetail })),
|
||||
appSidebarExpand: '',
|
||||
setAppSiderbarExpand: appSidebarExpand => set(() => ({ appSidebarExpand })),
|
||||
currentLogItem: undefined,
|
||||
setCurrentLogItem: currentLogItem => set(() => ({ currentLogItem })),
|
||||
showPromptLogModal: false,
|
||||
setShowPromptLogModal: showPromptLogModal => set(() => ({ showPromptLogModal })),
|
||||
showMessageLogModal: false,
|
||||
setShowMessageLogModal: showMessageLogModal => set(() => ({ showMessageLogModal })),
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type {
|
|||
FC,
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
import { memo, useEffect, useRef, useState } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
ChatConfig,
|
||||
|
|
@ -18,7 +18,6 @@ import LoadingAnim from '@/app/components/app/chat/loading-anim'
|
|||
import Citation from '@/app/components/app/chat/citation'
|
||||
import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
|
||||
import type { Emoji } from '@/app/components/tools/types'
|
||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||
|
||||
type AnswerProps = {
|
||||
item: ChatItem
|
||||
|
|
@ -50,22 +49,8 @@ const Answer: FC<AnswerProps> = ({
|
|||
} = item
|
||||
const hasAgentThoughts = !!agent_thoughts?.length
|
||||
|
||||
const [showPromptLogModal, setShowPromptLogModal] = useState(false)
|
||||
const [width, setWidth] = useState(0)
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
const adjustModalWidth = () => {
|
||||
if (ref.current)
|
||||
setWidth(document.body.clientWidth - (ref.current?.clientWidth + 56 + 16))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
adjustModalWidth()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex mb-2 last:mb-0' ref={ref}>
|
||||
<div className='flex mb-2 last:mb-0'>
|
||||
<div className='shrink-0 relative w-10 h-10'>
|
||||
{
|
||||
answerIcon || (
|
||||
|
|
@ -93,7 +78,6 @@ const Answer: FC<AnswerProps> = ({
|
|||
question={question}
|
||||
index={index}
|
||||
showPromptLog={showPromptLog}
|
||||
setShowPromptLogModal={setShowPromptLogModal}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -136,13 +120,6 @@ const Answer: FC<AnswerProps> = ({
|
|||
</div>
|
||||
<More more={more} />
|
||||
</div>
|
||||
{showPromptLogModal && (
|
||||
<PromptLogModal
|
||||
width={width}
|
||||
log={item.log || []}
|
||||
onCancel={() => setShowPromptLogModal(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Dispatch, FC, SetStateAction } from 'react'
|
||||
import type { FC } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
|
|
@ -24,14 +24,12 @@ type OperationProps = {
|
|||
question: string
|
||||
index: number
|
||||
showPromptLog?: boolean
|
||||
setShowPromptLogModal: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
const Operation: FC<OperationProps> = ({
|
||||
item,
|
||||
question,
|
||||
index,
|
||||
showPromptLog,
|
||||
setShowPromptLogModal,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
|
|
@ -79,7 +77,7 @@ const Operation: FC<OperationProps> = ({
|
|||
|
||||
<div className='hidden group-hover:flex items-center h-[28px] p-0.5 rounded-lg bg-white border-[0.5px] border-gray-100 shadow-md'>
|
||||
{showPromptLog && (
|
||||
<Log runID={item.workflow_run_id} setShowModal={setShowPromptLogModal} />
|
||||
<Log logItem={item} />
|
||||
)}
|
||||
{(!isOpeningStatement && config?.text_to_speech?.enabled) && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
memo,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThrottleEffect } from 'ahooks'
|
||||
|
|
@ -24,6 +25,8 @@ import { ChatContextProvider } from './context'
|
|||
import type { Emoji } from '@/app/components/tools/types'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { StopCircle } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
|
||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
|
||||
export type ChatProps = {
|
||||
chatList: ChatItem[]
|
||||
|
|
@ -72,6 +75,8 @@ const Chat: FC<ChatProps> = ({
|
|||
onFeedback,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore()
|
||||
const [width, setWidth] = useState(0)
|
||||
const chatContainerRef = useRef<HTMLDivElement>(null)
|
||||
const chatContainerInnerRef = useRef<HTMLDivElement>(null)
|
||||
const chatFooterRef = useRef<HTMLDivElement>(null)
|
||||
|
|
@ -83,6 +88,9 @@ const Chat: FC<ChatProps> = ({
|
|||
}
|
||||
|
||||
const handleWindowResize = () => {
|
||||
if (chatContainerRef.current)
|
||||
setWidth(document.body.clientWidth - (chatContainerRef.current?.clientWidth + 16) - 8)
|
||||
|
||||
if (chatContainerRef.current && chatFooterRef.current)
|
||||
chatFooterRef.current.style.width = `${chatContainerRef.current.clientWidth}px`
|
||||
|
||||
|
|
@ -215,6 +223,16 @@ const Chat: FC<ChatProps> = ({
|
|||
}
|
||||
</div>
|
||||
</div>
|
||||
{showPromptLogModal && (
|
||||
<PromptLogModal
|
||||
width={width}
|
||||
currentLogItem={currentLogItem}
|
||||
onCancel={() => {
|
||||
setCurrentLogItem()
|
||||
setShowPromptLogModal(false)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ChatContextProvider>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ import { useClickAway } from 'ahooks'
|
|||
import Card from './card'
|
||||
import { CopyFeedbackNew } from '@/app/components/base/copy-feedback'
|
||||
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import type { VisionFile } from '@/types/app'
|
||||
import type { IChatItem } from '@/app/components/app/chat/type'
|
||||
|
||||
type PromptLogModalProps = {
|
||||
log: { role: string; text: string; files?: VisionFile[] }[]
|
||||
currentLogItem?: IChatItem
|
||||
width: number
|
||||
onCancel: () => void
|
||||
}
|
||||
const PromptLogModal: FC<PromptLogModalProps> = ({
|
||||
log,
|
||||
currentLogItem,
|
||||
width,
|
||||
onCancel,
|
||||
}) => {
|
||||
|
|
@ -20,17 +20,15 @@ const PromptLogModal: FC<PromptLogModalProps> = ({
|
|||
const [mounted, setMounted] = useState(false)
|
||||
|
||||
useClickAway(() => {
|
||||
if (mounted) {
|
||||
console.log(111)
|
||||
if (mounted)
|
||||
onCancel()
|
||||
}
|
||||
}, ref)
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!log)
|
||||
if (!currentLogItem || !currentLogItem.log)
|
||||
return null
|
||||
|
||||
return (
|
||||
|
|
@ -43,9 +41,9 @@ const PromptLogModal: FC<PromptLogModalProps> = ({
|
|||
<div className='text-base font-semibold text-gray-900'>PROMPT LOG</div>
|
||||
<div className='flex items-center'>
|
||||
{
|
||||
log?.length === 1 && (
|
||||
currentLogItem.log?.length === 1 && (
|
||||
<>
|
||||
<CopyFeedbackNew className='w-6 h-6' content={log[0].text} />
|
||||
<CopyFeedbackNew className='w-6 h-6' content={currentLogItem.log[0].text} />
|
||||
<div className='mx-2.5 w-[1px] h-[14px] bg-gray-200' />
|
||||
</>
|
||||
)
|
||||
|
|
@ -59,7 +57,7 @@ const PromptLogModal: FC<PromptLogModalProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
<div className='grow p-2 overflow-y-auto'>
|
||||
<Card log={log} />
|
||||
<Card log={currentLogItem.log} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -729,7 +729,7 @@ const Main: FC<IMainProps> = ({
|
|||
title={siteInfo.title}
|
||||
icon=''
|
||||
customerIcon={difyIcon}
|
||||
icon_background={siteInfo.icon_background}
|
||||
icon_background={siteInfo.icon_background || ''}
|
||||
isEmbedScene={true}
|
||||
isMobile={isMobile}
|
||||
onCreateNewChat={() => handleConversationIdChange('-1')}
|
||||
|
|
|
|||
Loading…
Reference in New Issue