file uploader

This commit is contained in:
StyleZhang 2024-08-08 10:27:21 +08:00
parent e2962da1b8
commit 26bca75884
10 changed files with 103 additions and 43 deletions

View File

@ -129,23 +129,27 @@ const ChatWrapper = () => {
])
return (
<Chat
appData={appData}
config={appConfig}
chatList={chatList}
isResponding={isResponding}
chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[720px] ${isMobile && 'px-4'}`}
chatFooterClassName='pb-4'
chatFooterInnerClassName={`mx-auto w-full max-w-[720px] ${isMobile && 'px-4'}`}
onSend={doSend}
onStopResponding={handleStop}
chatNode={chatNode}
allToolIcons={appMeta?.tool_icons || {}}
onFeedback={handleFeedback}
suggestedQuestions={suggestedQuestions}
hideProcessDetail
themeBuilder={themeBuilder}
/>
<div
className='h-full bg-chatbot-bg overflow-hidden'
>
<Chat
appData={appData}
config={appConfig}
chatList={chatList}
isResponding={isResponding}
chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[720px] ${isMobile && 'px-4'}`}
chatFooterClassName='pb-4'
chatFooterInnerClassName={`mx-auto w-full max-w-[720px] ${isMobile && 'px-4'}`}
onSend={doSend}
onStopResponding={handleStop}
chatNode={chatNode}
allToolIcons={appMeta?.tool_icons || {}}
onFeedback={handleFeedback}
suggestedQuestions={suggestedQuestions}
hideProcessDetail
themeBuilder={themeBuilder}
/>
</div>
)
}

View File

@ -36,7 +36,7 @@ const AgentContent: FC<AgentContentProps> = ({
return (
<div>
{agent_thoughts?.map((thought, index) => (
<div key={index}>
<div key={index} className='px-2 py-1'>
{thought.thought && (
<Markdown content={thought.thought} />
)}

View File

@ -2,6 +2,7 @@ import type { FC } from 'react'
import { memo } from 'react'
import type { ChatItem } from '../../types'
import { Markdown } from '@/app/components/base/markdown'
import cn from '@/utils/classnames'
type BasicContentProps = {
item: ChatItem
@ -15,9 +16,17 @@ const BasicContent: FC<BasicContentProps> = ({
} = item
if (annotation?.logAnnotation)
return <Markdown content={annotation?.logAnnotation.content || ''} />
return <Markdown content={annotation?.logAnnotation.content || ''} className='px-2 py-1' />
return <Markdown content={content} className={`${item.isError && '!text-[#F04438]'}`} />
return (
<Markdown
className={cn(
'px-2 py-1',
item.isError && '!text-[#F04438]',
)}
content={content}
/>
)
}
export default memo(BasicContent)

View File

@ -15,13 +15,13 @@ import BasicContent from './basic-content'
import SuggestedQuestions from './suggested-questions'
import More from './more'
import WorkflowProcess from './workflow-process'
import { AnswerTriangle } from '@/app/components/base/icons/src/vender/solid/general'
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
import Citation from '@/app/components/base/chat/chat/citation'
import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
import type { Emoji } from '@/app/components/tools/types'
import type { AppData } from '@/models/share'
import cn from '@/utils/classnames'
type AnswerProps = {
item: ChatItem
@ -105,13 +105,12 @@ const Answer: FC<AnswerProps> = ({
</div>
<div className='chat-answer-container group grow w-0 ml-4' ref={containerRef}>
<div className={`group relative pr-10 ${chatAnswerContainerInner}`}>
<AnswerTriangle className='absolute -left-2 top-0 w-2 h-3 text-gray-100' />
<div
ref={contentRef}
className={`
relative inline-block px-4 py-3 max-w-full bg-gray-100 rounded-b-2xl rounded-tr-2xl text-sm text-gray-900
${workflowProcess && 'w-full'}
`}
className={cn(
'relative inline-block p-2 max-w-full bg-chat-bubble-bg rounded-2xl border-t border-t-divider-subtle text-sm text-gray-900',
workflowProcess && 'w-full',
)}
>
{annotation?.id && (
<div

View File

@ -1,6 +1,7 @@
import {
memo,
useCallback,
useRef,
useState,
} from 'react'
import Textarea from 'rc-textarea'
@ -15,7 +16,7 @@ import type { Theme } from '../../embedded-chatbot/theme/theme-context'
import { useTextAreaHeight } from './hooks'
import Operation from './operation'
import cn from '@/utils/classnames'
import { FileListFlexOperation } from '@/app/components/base/file-uploader'
// import { FileListFlexOperation } from '@/app/components/base/file-uploader'
import VoiceInput from '@/app/components/base/voice-input'
import { useToastContext } from '@/app/components/base/toast'
@ -41,9 +42,38 @@ const ChatInputArea = ({
handleTextareaResize,
isMultipleLine,
} = useTextAreaHeight()
const [value, setValue] = useState('')
const [query, setQuery] = useState('')
const isUseInputMethod = useRef(false)
const [showVoiceInput, setShowVoiceInput] = useState(false)
const handleSend = () => {
if (onSend) {
if (!query || !query.trim()) {
notify({ type: 'info', message: t('appAnnotation.errorMessage.queryRequired') })
return
}
onSend(query)
setQuery('')
}
}
const handleKeyUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.code === 'Enter') {
e.preventDefault()
// prevent send message when using input method enter
if (!e.shiftKey && !isUseInputMethod.current)
handleSend()
}
}
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
isUseInputMethod.current = e.nativeEvent.isComposing
if (e.code === 'Enter' && !e.shiftKey) {
setQuery(query.replace(/\n$/, ''))
e.preventDefault()
}
}
const handleShowVoiceInput = useCallback(() => {
(Recorder as any).getPermission().then(() => {
setShowVoiceInput(true)
@ -63,11 +93,11 @@ const ChatInputArea = ({
return (
<div
className={cn(
'py-[9px] bg-components-panel-bg-blur border border-blue-300 rounded-xl shadow-md',
'py-[9px] bg-components-panel-bg-blur border border-components-chat-input-border rounded-xl shadow-md',
)}
>
<div className='relative px-[9px] max-h-[158px] overflow-y-auto'>
<FileListFlexOperation />
<div className='relative px-[9px] max-h-[158px] overflow-x-hidden overflow-y-auto'>
{/* <FileListFlexOperation /> */}
<div
ref={wrapperRef}
className='flex items-center justify-between'
@ -77,7 +107,7 @@ const ChatInputArea = ({
ref={textValueRef}
className='absolute w-auto h-auto p-1 leading-6 body-lg-regular pointer-events-none whitespace-pre invisible'
>
{value}
{query}
</div>
<Textarea
ref={textareaRef}
@ -85,11 +115,13 @@ const ChatInputArea = ({
placeholder='Enter message...'
autoSize={{ minRows: 1 }}
onResize={handleTextareaResize}
value={value}
value={query}
onChange={(e) => {
setValue(e.target.value)
setQuery(e.target.value)
handleTextareaResize()
}}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
/>
</div>
{
@ -100,7 +132,7 @@ const ChatInputArea = ({
showVoiceInput && (
<VoiceInput
onCancel={() => setShowVoiceInput(false)}
onConverted={text => setValue(text)}
onConverted={text => setQuery(text)}
/>
)
}

View File

@ -21,7 +21,8 @@ import type {
import type { ThemeBuilder } from '../embedded-chatbot/theme/theme-context'
import Question from './question'
import Answer from './answer'
import ChatInput from './chat-input'
// import ChatInput from './chat-input'
import ChatInputArea from './chat-input-area'
import TryToAsk from './try-to-ask'
import { ChatContextProvider } from './context'
import classNames from '@/utils/classnames'
@ -261,7 +262,7 @@ const Chat: FC<ChatProps> = ({
/>
)
}
{
{/* {
!noChatInput && (
<ChatInput
visionConfig={config?.file_upload?.image}
@ -270,6 +271,16 @@ const Chat: FC<ChatProps> = ({
theme={themeBuilder?.theme}
/>
)
} */}
{
!noChatInput && (
<ChatInputArea
visionConfig={config?.file_upload?.image}
speechToTextConfig={config?.speech_to_text}
onSend={onSend}
theme={themeBuilder?.theme}
/>
)
}
</div>
</div>

View File

@ -8,7 +8,6 @@ import {
import type { ChatItem } from '../types'
import type { Theme } from '../embedded-chatbot/theme/theme-context'
import { CssTransform } from '../embedded-chatbot/theme/utils'
import { QuestionTriangle } from '@/app/components/base/icons/src/vender/solid/general'
import { User } from '@/app/components/base/icons/src/public/avatar'
import { Markdown } from '@/app/components/base/markdown'
import ImageGallery from '@/app/components/base/image-gallery'
@ -32,12 +31,8 @@ const Question: FC<QuestionProps> = ({
return (
<div className='flex justify-end mb-2 last:mb-0 pl-10'>
<div className='group relative mr-4'>
<QuestionTriangle
className='absolute -right-2 top-0 w-2 h-3 text-[#D1E9FF]/50'
style={theme ? { color: theme.chatBubbleColor } : {}}
/>
<div
className='px-4 py-3 bg-[#D1E9FF]/50 rounded-b-2xl rounded-tl-2xl text-sm text-gray-900'
className='px-4 py-3 bg-util-colors-blue-brand-blue-brand-500 rounded-2xl text-sm text-gray-900'
style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}}
>
{

View File

@ -88,6 +88,10 @@ module.exports = {
fontSize: {
'2xs': '0.625rem',
},
backgroundImage: {
'chatbot-bg': 'var(--color-chatbot-bg)',
'chat-bubble-bg': 'var(--color-chat-bubble-bg)',
},
},
},
plugins: [

View File

@ -559,4 +559,7 @@ html[data-theme="dark"] {
--color-third-party-LangChain: #FFFFFF;
--color-third-party-Langfuse: #FFFFFF;
--color-chatbot-bg: linear-gradient(180deg, rgba(34, 34, 37, 0.90) 0%, rgba(29, 29, 32, 0.90) 90.48%);
--color-chat-bubble-bg: linear-gradient(180deg, rgba(200, 206, 218, 0.08) 0%, rgba(200, 206, 218, 0.02) 100%);
}

View File

@ -559,4 +559,7 @@ html[data-theme="light"] {
--color-third-party-LangChain: #1C3C3C;
--color-third-party-Langfuse: #000000;
--color-chatbot-bg: linear-gradient(180deg, rgba(249, 250, 251, 0.90) 0%, rgba(242, 244, 247, 0.90) 90.48%);
--color-chat-bubble-bg: linear-gradient(180deg, #FFF 0%, rgba(255, 255, 255, 0.60) 100%);
}