Skip to content

Commit

Permalink
Merge branch 'feat/workflow' into deploy/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
zxhlyh committed Mar 15, 2024
2 parents 2ffae0e + 129a68b commit 308535c
Show file tree
Hide file tree
Showing 23 changed files with 271 additions and 219 deletions.
44 changes: 24 additions & 20 deletions web/app/components/app/chat/answer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'use client'
import type { FC, ReactNode } from 'react'
import React, { useState } from 'react'
import React, { useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { UserCircleIcon } from '@heroicons/react/24/solid'
import cn from 'classnames'
import type { CitationItem, DisplayScene, FeedbackFunc, Feedbacktype, IChatItem } from '../type'
import OperationBtn from '../operation'
import LoadingAnim from '../loading-anim'
import { EditIconSolid, RatingIcon } from '../icon-component'
import { RatingIcon } from '../icon-component'
import s from '../style.module.css'
import MoreInfo from '../more-info'
import CopyBtn from '../copy-btn'
Expand All @@ -26,16 +26,8 @@ import { MessageFast } from '@/app/components/base/icons/src/vender/solid/commun
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'

const Divider: FC<{ name: string }> = ({ name }) => {
const { t } = useTranslation()
return <div className='flex items-center my-2'>
<span className='text-xs text-gray-500 inline-flex items-center mr-2'>
<EditIconSolid className='mr-1' />{t('appLog.detail.annotationTip', { user: name })}
</span>
<div className='h-[1px] bg-gray-200 flex-1'></div>
</div>
}
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'}>
{children}
Expand Down Expand Up @@ -64,6 +56,7 @@ export type IAnswerProps = {
onAnnotationAdded?: (annotationId: string, authorName: string, question: string, answer: string, index: number) => void
onAnnotationRemoved?: (index: number) => void
allToolIcons?: Record<string, string | Emoji>
isShowPromptLog?: boolean
}
// The component needs to maintain its own state to control whether to display input component
const Answer: FC<IAnswerProps> = ({
Expand All @@ -87,12 +80,11 @@ const Answer: FC<IAnswerProps> = ({
onAnnotationAdded,
onAnnotationRemoved,
allToolIcons,
isShowPromptLog,
}) => {
const { id, content, more, feedback, adminFeedback, annotation, agent_thoughts } = item
const isAgentMode = !!agent_thoughts && agent_thoughts.length > 0
const hasAnnotation = !!annotation?.id
const [showEdit, setShowEdit] = useState(false)
const [loading, setLoading] = useState(false)
// const [annotation, setAnnotation] = useState<Annotation | undefined | null>(initAnnotation)
// const [inputValue, setInputValue] = useState<string>(initAnnotation?.content ?? '')
const [localAdminFeedback, setLocalAdminFeedback] = useState<Feedbacktype | undefined | null>(adminFeedback)
Expand Down Expand Up @@ -241,9 +233,11 @@ const Answer: FC<IAnswerProps> = ({
</div>
)

const ref = useRef(null)

return (
// data-id for debug the item message is right
<div key={id} data-id={id}>
<div key={id} data-id={id} ref={ref}>
<div className='flex items-start'>
{
answerIcon || (
Expand All @@ -257,7 +251,7 @@ const Answer: FC<IAnswerProps> = ({
)
}
<div className={cn(s.answerWrapWrap, 'chat-answer-container group')}>
<div className={`${s.answerWrap} ${showEdit ? 'w-full' : ''}`}>
<div className={s.answerWrap}>
<div className={`${s.answer} relative text-sm text-gray-900`}>
<div className={'ml-2 py-3 px-4 bg-gray-100 rounded-tr-2xl rounded-b-2xl'}>
{(isResponding && (isAgentMode ? (!content && (agent_thoughts || []).filter(item => !!item.thought || !!item.tool).length === 0) : !content))
Expand Down Expand Up @@ -326,11 +320,21 @@ const Answer: FC<IAnswerProps> = ({
className={cn(s.copyBtn, 'mr-1')}
/>
)}
{!item.isOpeningStatement && isShowTextToSpeech && (
<AudioBtn
value={content}
className={cn(s.playBtn, 'mr-1')}
/>
{((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} log={item.log!} containerRef={ref} />
)}
{!item.isOpeningStatement && isShowTextToSpeech && (
<>
<div className='mx-1 w-[1px] h-[14px] bg-gray-200'/>
<AudioBtn
value={content}
className={cn(s.playBtn)}
/>
</>
)}
</div>
)}
{(!item.isOpeningStatement && supportAnnotation) && (
<AnnotationCtrlBtn
Expand Down
241 changes: 117 additions & 124 deletions web/app/components/app/chat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ const Chat: FC<IChatProps> = ({
onAnnotationAdded={handleAnnotationAdded}
onAnnotationRemoved={handleAnnotationRemoved}
allToolIcons={allToolIcons}
isShowPromptLog={isShowPromptLog}
/>
}
return (
Expand All @@ -316,140 +317,132 @@ const Chat: FC<IChatProps> = ({
)
})}
</div>
{
!isHideSendInput && (
<div className={cn(!feedbackDisabled && '!left-3.5 !right-3.5', 'absolute z-10 bottom-0 left-0 right-0')}>
{/* Thinking is sync and can not be stopped */}
{(isResponding && canStopResponding && ((!!chatList[chatList.length - 1]?.content) || (chatList[chatList.length - 1]?.agent_thoughts && chatList[chatList.length - 1].agent_thoughts!.length > 0))) && (
<div className='flex justify-center mb-4'>
<Button className='flex items-center space-x-1 bg-white' onClick={() => abortResponding?.()}>
{stopIcon}
<span className='text-xs text-gray-500 font-normal'>{t('appDebug.operation.stopResponding')}</span>
</Button>
{!isHideSendInput && (
<div className={cn(!feedbackDisabled && '!left-3.5 !right-3.5', 'absolute z-10 bottom-0 left-0 right-0')}>
{/* Thinking is sync and can not be stopped */}
{(isResponding && canStopResponding && ((!!chatList[chatList.length - 1]?.content) || (chatList[chatList.length - 1]?.agent_thoughts && chatList[chatList.length - 1].agent_thoughts!.length > 0))) && (
<div className='flex justify-center mb-4'>
<Button className='flex items-center space-x-1 bg-white' onClick={() => abortResponding?.()}>
{stopIcon}
<span className='text-xs text-gray-500 font-normal'>{t('appDebug.operation.stopResponding')}</span>
</Button>
</div>
)}
{isShowSuggestion && (
<div className='pt-2'>
<div className='flex items-center justify-center mb-2.5'>
<div className='grow h-[1px]'
style={{
background: 'linear-gradient(270deg, #F3F4F6 0%, rgba(243, 244, 246, 0) 100%)',
}}></div>
<div className='shrink-0 flex items-center px-3 space-x-1'>
{TryToAskIcon}
<span className='text-xs text-gray-500 font-medium'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.tryToAsk')}</span>
</div>
<div className='grow h-[1px]'
style={{
background: 'linear-gradient(270deg, rgba(243, 244, 246, 0) 0%, #F3F4F6 100%)',
}}></div>
</div>
)}
{
isShowSuggestion && (
<div className='pt-2'>
<div className='flex items-center justify-center mb-2.5'>
<div className='grow h-[1px]'
style={{
background: 'linear-gradient(270deg, #F3F4F6 0%, rgba(243, 244, 246, 0) 100%)',
}}></div>
<div className='shrink-0 flex items-center px-3 space-x-1'>
{TryToAskIcon}
<span className='text-xs text-gray-500 font-medium'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.tryToAsk')}</span>
</div>
<div className='grow h-[1px]'
style={{
background: 'linear-gradient(270deg, rgba(243, 244, 246, 0) 0%, #F3F4F6 100%)',
}}></div>
</div>
{/* has scrollbar would hide part of first item */}
<div ref={suggestionListRef} className={cn(!hasScrollbar && 'justify-center', 'flex overflow-x-auto pb-2')}>
{suggestionList?.map((item, index) => (
<div key={item} className='shrink-0 flex justify-center mr-2'>
<Button
key={index}
onClick={() => onQueryChange(item)}
>
<span className='text-primary-600 text-xs font-medium'>{item}</span>
</Button>
</div>
))}
{/* has scrollbar would hide part of first item */}
<div ref={suggestionListRef} className={cn(!hasScrollbar && 'justify-center', 'flex overflow-x-auto pb-2')}>
{suggestionList?.map((item, index) => (
<div key={item} className='shrink-0 flex justify-center mr-2'>
<Button
key={index}
onClick={() => onQueryChange(item)}
>
<span className='text-primary-600 text-xs font-medium'>{item}</span>
</Button>
</div>
</div>)
}
<div className={cn('p-[5.5px] max-h-[150px] bg-white border-[1.5px] border-gray-200 rounded-xl overflow-y-auto', isDragActive && 'border-primary-600')}>
))}
</div>
</div>
)}
<div className={cn('p-[5.5px] max-h-[150px] bg-white border-[1.5px] border-gray-200 rounded-xl overflow-y-auto', isDragActive && 'border-primary-600')}>
{visionConfig?.enabled && (
<>
<div className='absolute bottom-2 left-2 flex items-center'>
<ChatImageUploader
settings={visionConfig}
onUpload={onUpload}
disabled={files.length >= visionConfig.number_limits}
/>
<div className='mx-1 w-[1px] h-4 bg-black/5' />
</div>
<div className='pl-[52px]'>
<ImageList
list={files}
onRemove={onRemove}
onReUpload={onReUpload}
onImageLinkLoadSuccess={onImageLinkLoadSuccess}
onImageLinkLoadError={onImageLinkLoadError}
/>
</div>
</>
)}
<Textarea
className={`
block w-full px-2 pr-[118px] py-[7px] leading-5 max-h-none text-sm text-gray-700 outline-none appearance-none resize-none
${visionConfig?.enabled && 'pl-12'}
`}
value={query}
onChange={handleContentChange}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
onPaste={onPaste}
onDragEnter={onDragEnter}
onDragLeave={onDragLeave}
onDragOver={onDragOver}
onDrop={onDrop}
autoSize
/>
<div className="absolute bottom-2 right-2 flex items-center h-8">
<div className={`${s.count} mr-4 h-5 leading-5 text-sm bg-gray-50 text-gray-500`}>{query.trim().length}</div>
{
visionConfig?.enabled && (
<>
<div className='absolute bottom-2 left-2 flex items-center'>
<ChatImageUploader
settings={visionConfig}
onUpload={onUpload}
disabled={files.length >= visionConfig.number_limits}
/>
<div className='mx-1 w-[1px] h-4 bg-black/5' />
query
? (
<div className='flex justify-center items-center w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg' onClick={() => onQueryChange('')}>
<XCircle className='w-4 h-4 text-[#98A2B3]' />
</div>
<div className='pl-[52px]'>
<ImageList
list={files}
onRemove={onRemove}
onReUpload={onReUpload}
onImageLinkLoadSuccess={onImageLinkLoadSuccess}
onImageLinkLoadError={onImageLinkLoadError}
/>
</div>
</>
)
}
<Textarea
className={`
block w-full px-2 pr-[118px] py-[7px] leading-5 max-h-none text-sm text-gray-700 outline-none appearance-none resize-none
${visionConfig?.enabled && 'pl-12'}
`}
value={query}
onChange={handleContentChange}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
onPaste={onPaste}
onDragEnter={onDragEnter}
onDragLeave={onDragLeave}
onDragOver={onDragOver}
onDrop={onDrop}
autoSize
/>
<div className="absolute bottom-2 right-2 flex items-center h-8">
<div className={`${s.count} mr-4 h-5 leading-5 text-sm bg-gray-50 text-gray-500`}>{query.trim().length}</div>
{
query
)
: isShowSpeechToText
? (
<div className='flex justify-center items-center w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg' onClick={() => onQueryChange('')}>
<XCircle className='w-4 h-4 text-[#98A2B3]' />
<div
className='group flex justify-center items-center w-8 h-8 hover:bg-primary-50 rounded-lg cursor-pointer'
onClick={handleVoiceInputShow}
>
<Microphone01 className='block w-4 h-4 text-gray-500 group-hover:hidden' />
<Microphone01Solid className='hidden w-4 h-4 text-primary-600 group-hover:block' />
</div>
)
: isShowSpeechToText
? (
<div
className='group flex justify-center items-center w-8 h-8 hover:bg-primary-50 rounded-lg cursor-pointer'
onClick={handleVoiceInputShow}
>
<Microphone01 className='block w-4 h-4 text-gray-500 group-hover:hidden' />
<Microphone01Solid className='hidden w-4 h-4 text-primary-600 group-hover:block' />
</div>
)
: null
}
<div className='mx-2 w-[1px] h-4 bg-black opacity-5' />
{isMobile
? sendBtn
: (
<TooltipPlus
popupContent={
<div>
<div>{t('common.operation.send')} Enter</div>
<div>{t('common.operation.lineBreak')} Shift Enter</div>
</div>
}
>
{sendBtn}
</TooltipPlus>
)}
</div>
{
voiceInputShow && (
<VoiceInput
onCancel={() => setVoiceInputShow(false)}
onConverted={text => onQueryChange(text)}
/>
)
: null
}
<div className='mx-2 w-[1px] h-4 bg-black opacity-5' />
{isMobile
? sendBtn
: (
<TooltipPlus
popupContent={
<div>
<div>{t('common.operation.send')} Enter</div>
<div>{t('common.operation.lineBreak')} Shift Enter</div>
</div>
}
>
{sendBtn}
</TooltipPlus>
)}
</div>
{voiceInputShow && (
<VoiceInput
onCancel={() => setVoiceInputShow(false)}
onConverted={text => onQueryChange(text)}
/>
)}
</div>
)
}

</div>
)}
</div>
)
}
Expand Down
Loading

0 comments on commit 308535c

Please sign in to comment.