From 3046ccc6a798b5a72ca7aa8a0404f620c7f2a177 Mon Sep 17 00:00:00 2001 From: YISH Date: Wed, 28 Feb 2024 15:32:00 +0800 Subject: [PATCH 1/8] Fix the logic error of `getStartingNodes` --- packages/server/src/utils/index.ts | 41 ++++++++++-------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 8092fbd8..cab482e6 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -162,39 +162,22 @@ export const constructGraphs = ( * @param {string} endNodeId */ export const getStartingNodes = (graph: INodeDirectedGraph, endNodeId: string) => { - const visited = new Set() - const queue: Array<[string, number]> = [[endNodeId, 0]] const depthQueue: IDepthQueue = { [endNodeId]: 0 } - let maxDepth = 0 - let startingNodeIds: string[] = [] - - while (queue.length > 0) { - const [currentNode, depth] = queue.shift()! - - if (visited.has(currentNode)) { - continue - } - - visited.add(currentNode) - - if (depth > maxDepth) { - maxDepth = depth - startingNodeIds = [currentNode] - } else if (depth === maxDepth) { - startingNodeIds.push(currentNode) - } - - for (const neighbor of graph[currentNode]) { - if (!visited.has(neighbor)) { - queue.push([neighbor, depth + 1]) - depthQueue[neighbor] = depth + 1 - } - } + // Assuming that this is a directed acyclic graph, there will be no infinite loop problem. + const walkGraph = (nodeId: string) => { + const depth = depthQueue[nodeId] + graph[nodeId].flatMap((id) => { + depthQueue[id] = Math.max(depthQueue[id] ?? 0, depth + 1) + walkGraph(id) + }) } + walkGraph(endNodeId) + + const maxDepth = Math.max(...Object.values(depthQueue)) const depthQueueReversed: IDepthQueue = {} for (const nodeId in depthQueue) { if (Object.prototype.hasOwnProperty.call(depthQueue, nodeId)) { @@ -202,6 +185,10 @@ export const getStartingNodes = (graph: INodeDirectedGraph, endNodeId: string) = } } + const startingNodeIds = Object.entries(depthQueueReversed) + .filter(([_, depth]) => depth === 0) + .map(([id, _]) => id) + return { startingNodeIds, depthQueue: depthQueueReversed } } From 131eccef455976d272697985f842a165f2b90d20 Mon Sep 17 00:00:00 2001 From: Ilango Date: Mon, 11 Mar 2024 21:07:20 +0530 Subject: [PATCH 2/8] Implement chat message feedback for UI chat window --- packages/server/src/index.ts | 22 ++- packages/ui/src/api/chatmessage.js | 3 +- packages/ui/src/api/chatmessagefeedback.js | 9 ++ .../button/CopyToClipboardButton.js | 31 ++++ .../ui-component/button/ThumbsDownButton.js | 31 ++++ .../src/ui-component/button/ThumbsUpButton.js | 31 ++++ .../dialog/ChatFeedbackContentDialog.js | 73 ++++++++++ .../ui/src/views/chatmessage/ChatMessage.js | 133 +++++++++++++++++- 8 files changed, 330 insertions(+), 3 deletions(-) create mode 100644 packages/ui/src/api/chatmessagefeedback.js create mode 100644 packages/ui/src/ui-component/button/CopyToClipboardButton.js create mode 100644 packages/ui/src/ui-component/button/ThumbsDownButton.js create mode 100644 packages/ui/src/ui-component/button/ThumbsUpButton.js create mode 100644 packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index f087e40b..c40581bf 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -595,7 +595,27 @@ export class App { // Get internal chatmessages from chatflowid this.app.get('/api/v1/internal-chatmessage/:id', async (req: Request, res: Response) => { - const chatmessages = await this.getChatMessage(req.params.id, chatType.INTERNAL) + const sortOrder = req.query?.order as string | undefined + const chatId = req.query?.chatId as string | undefined + const memoryType = req.query?.memoryType as string | undefined + const sessionId = req.query?.sessionId as string | undefined + const messageId = req.query?.messageId as string | undefined + const startDate = req.query?.startDate as string | undefined + const endDate = req.query?.endDate as string | undefined + const feedback = req.query?.feedback as boolean | undefined + + const chatmessages = await this.getChatMessage( + req.params.id, + chatType.INTERNAL, + sortOrder, + chatId, + memoryType, + sessionId, + startDate, + endDate, + messageId, + feedback + ) return res.json(chatmessages) }) diff --git a/packages/ui/src/api/chatmessage.js b/packages/ui/src/api/chatmessage.js index 7941ccf5..8760ce07 100644 --- a/packages/ui/src/api/chatmessage.js +++ b/packages/ui/src/api/chatmessage.js @@ -1,6 +1,7 @@ import client from './client' -const getInternalChatmessageFromChatflow = (id) => client.get(`/internal-chatmessage/${id}`) +const getInternalChatmessageFromChatflow = (id, params = {}) => + client.get(`/internal-chatmessage/${id}`, { params: { feedback: true, ...params } }) const getAllChatmessageFromChatflow = (id, params = {}) => client.get(`/chatmessage/${id}`, { params: { order: 'DESC', feedback: true, ...params } }) const getChatmessageFromPK = (id, params = {}) => client.get(`/chatmessage/${id}`, { params: { order: 'ASC', feedback: true, ...params } }) diff --git a/packages/ui/src/api/chatmessagefeedback.js b/packages/ui/src/api/chatmessagefeedback.js new file mode 100644 index 00000000..1916cfed --- /dev/null +++ b/packages/ui/src/api/chatmessagefeedback.js @@ -0,0 +1,9 @@ +import client from './client' + +const addFeedback = (id, body) => client.post(`/feedback/${id}`, body) +const updateFeedback = (id, body) => client.put(`/feedback/${id}`, body) + +export default { + addFeedback, + updateFeedback +} diff --git a/packages/ui/src/ui-component/button/CopyToClipboardButton.js b/packages/ui/src/ui-component/button/CopyToClipboardButton.js new file mode 100644 index 00000000..ee9cc752 --- /dev/null +++ b/packages/ui/src/ui-component/button/CopyToClipboardButton.js @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types' +import { useSelector } from 'react-redux' +import { IconButton } from '@mui/material' +import { IconClipboard } from '@tabler/icons' + +const CopyToClipboardButton = (props) => { + const customization = useSelector((state) => state.customization) + + return ( + + + + ) +} + +CopyToClipboardButton.propTypes = { + isDisabled: PropTypes.bool, + isLoading: PropTypes.bool, + onClick: PropTypes.func +} + +export default CopyToClipboardButton diff --git a/packages/ui/src/ui-component/button/ThumbsDownButton.js b/packages/ui/src/ui-component/button/ThumbsDownButton.js new file mode 100644 index 00000000..6ee9e09a --- /dev/null +++ b/packages/ui/src/ui-component/button/ThumbsDownButton.js @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types' +import { useSelector } from 'react-redux' +import { IconButton } from '@mui/material' +import { IconThumbDown } from '@tabler/icons' + +const ThumbsDownButton = (props) => { + const customization = useSelector((state) => state.customization) + return ( + + + + ) +} + +ThumbsDownButton.propTypes = { + isDisabled: PropTypes.bool, + isLoading: PropTypes.bool, + onClick: PropTypes.func, + rating: PropTypes.string +} + +export default ThumbsDownButton diff --git a/packages/ui/src/ui-component/button/ThumbsUpButton.js b/packages/ui/src/ui-component/button/ThumbsUpButton.js new file mode 100644 index 00000000..c1b5106e --- /dev/null +++ b/packages/ui/src/ui-component/button/ThumbsUpButton.js @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types' +import { useSelector } from 'react-redux' +import { IconButton } from '@mui/material' +import { IconThumbUp } from '@tabler/icons' + +const ThumbsUpButton = (props) => { + const customization = useSelector((state) => state.customization) + return ( + + + + ) +} + +ThumbsUpButton.propTypes = { + isDisabled: PropTypes.bool, + isLoading: PropTypes.bool, + onClick: PropTypes.func, + rating: PropTypes.string +} + +export default ThumbsUpButton diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js b/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js new file mode 100644 index 00000000..56d81d14 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js @@ -0,0 +1,73 @@ +import { useCallback, useEffect } from 'react' +import { createPortal } from 'react-dom' +import { useDispatch } from 'react-redux' + +// material-ui +import { Button, Dialog, DialogContent, DialogTitle, DialogActions, Box, OutlinedInput } from '@mui/material' +import { useState } from 'react' + +// Project import +import { StyledButton } from 'ui-component/button/StyledButton' + +// store +import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' + +const ChatFeedbackContentDialog = ({ show, onCancel, onConfirm }) => { + const portalElement = document.getElementById('portal') + const dispatch = useDispatch() + + const [feedbackContent, setFeedbackContent] = useState('') + + const onChange = useCallback((e) => setFeedbackContent(e.target.value), [setFeedbackContent]) + + const onSave = () => { + onConfirm(feedbackContent) + } + + useEffect(() => { + if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) + else dispatch({ type: HIDE_CANVAS_DIALOG }) + return () => dispatch({ type: HIDE_CANVAS_DIALOG }) + }, [show, dispatch]) + + const component = show ? ( + + + Provide additional feedback + + + + + + + + + + Submit Feedback + + + + ) : null + + return createPortal(component, portalElement) +} + +export default ChatFeedbackContentDialog diff --git a/packages/ui/src/views/chatmessage/ChatMessage.js b/packages/ui/src/views/chatmessage/ChatMessage.js index 75a466d3..55a157d1 100644 --- a/packages/ui/src/views/chatmessage/ChatMessage.js +++ b/packages/ui/src/views/chatmessage/ChatMessage.js @@ -32,9 +32,13 @@ import audioUploadSVG from 'assets/images/wave-sound.jpg' import { CodeBlock } from 'ui-component/markdown/CodeBlock' import { MemoizedReactMarkdown } from 'ui-component/markdown/MemoizedReactMarkdown' import SourceDocDialog from 'ui-component/dialog/SourceDocDialog' +import ChatFeedbackContentDialog from 'ui-component/dialog/ChatFeedbackContentDialog' import StarterPromptsCard from 'ui-component/cards/StarterPromptsCard' import { cancelAudioRecording, startAudioRecording, stopAudioRecording } from './audio-recording' import { ImageButton, ImageSrc, ImageBackdrop, ImageMarked } from 'ui-component/button/ImageButton' +import CopyToClipboardButton from 'ui-component/button/CopyToClipboardButton' +import ThumbsUpButton from 'ui-component/button/ThumbsUpButton' +import ThumbsDownButton from 'ui-component/button/ThumbsDownButton' import './ChatMessage.css' import './audio-recording.css' @@ -42,6 +46,7 @@ import './audio-recording.css' import chatmessageApi from 'api/chatmessage' import chatflowsApi from 'api/chatflows' import predictionApi from 'api/prediction' +import chatmessagefeedbackApi from 'api/chatmessagefeedback' // Hooks import useApi from 'hooks/useApi' @@ -86,6 +91,9 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews const getChatflowConfig = useApi(chatflowsApi.getSpecificChatflow) const [starterPrompts, setStarterPrompts] = useState([]) + const [chatFeedbackStatus, setChatFeedbackStatus] = useState(false) + const [feedbackId, setFeedbackId] = useState('') + const [showFeedbackContentDialog, setShowFeedbackContentDialog] = useState(false) // drag & drop and file input const fileUploadRef = useRef(null) @@ -318,6 +326,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews let allMessages = [...cloneDeep(prevMessages)] if (allMessages[allMessages.length - 1].type === 'userMessage') return allMessages allMessages[allMessages.length - 1].message += text + allMessages[allMessages.length - 1].feedback = null return allMessages }) } @@ -389,6 +398,14 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews if (response.data) { const data = response.data + setMessages((prevMessages) => { + let allMessages = [...cloneDeep(prevMessages)] + if (allMessages[allMessages.length - 1].type === 'apiMessage') { + allMessages[allMessages.length - 1].id = data?.chatMessageId + } + return allMessages + }) + if (!chatId) setChatId(data.chatId) if (input === '' && data.question) { @@ -412,10 +429,12 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews ...prevMessages, { message: text, + id: data?.chatMessageId, sourceDocuments: data?.sourceDocuments, usedTools: data?.usedTools, fileAnnotations: data?.fileAnnotations, - type: 'apiMessage' + type: 'apiMessage', + feedback: null } ]) } @@ -474,7 +493,9 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews setChatId(chatId) const loadedMessages = getChatmessageApi.data.map((message) => { const obj = { + id: message.id, message: message.content, + feedback: message.feedback, type: message.role } if (message.sourceDocuments) obj.sourceDocuments = JSON.parse(message.sourceDocuments) @@ -527,6 +548,9 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews }) setStarterPrompts(inputFields) } + if (config.chatFeedback) { + setChatFeedbackStatus(config.chatFeedback.status) + } } } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -604,6 +628,83 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews // eslint-disable-next-line }, [previews]) + const copyMessageToClipboard = async (text) => { + try { + await navigator.clipboard.writeText(text || '') + } catch (error) { + console.error('Error copying to clipboard:', error) + } + } + + const onThumbsUpClick = async (messageId) => { + const body = { + chatflowid, + chatId, + messageId, + rating: 'THUMBS_UP', + content: '' + } + const result = await chatmessagefeedbackApi.addFeedback(chatflowid, body) + if (result.data) { + const data = result.data + let id = '' + if (data && data.id) id = data.id + setMessages((prevMessages) => { + const allMessages = [...cloneDeep(prevMessages)] + return allMessages.map((message) => { + if (message.id === messageId) { + message.feedback = { + rating: 'THUMBS_UP' + } + } + return message + }) + }) + setFeedbackId(id) + setShowFeedbackContentDialog(true) + } + } + + const onThumbsDownClick = async (messageId) => { + const body = { + chatflowid, + chatId, + messageId, + rating: 'THUMBS_DOWN', + content: '' + } + const result = await chatmessagefeedbackApi.addFeedback(chatflowid, body) + if (result.data) { + const data = result.data + let id = '' + if (data && data.id) id = data.id + setMessages((prevMessages) => { + const allMessages = [...cloneDeep(prevMessages)] + return allMessages.map((message) => { + if (message.id === messageId) { + message.feedback = { + rating: 'THUMBS_DOWN' + } + } + return message + }) + }) + setFeedbackId(id) + setShowFeedbackContentDialog(true) + } + } + + const submitFeedbackContent = async (text) => { + const body = { + content: text + } + const result = await chatmessagefeedbackApi.updateFeedback(feedbackId, body) + if (result.data) { + setFeedbackId('') + setShowFeedbackContentDialog(false) + } + } + return (
{isDragActive && ( @@ -747,6 +848,36 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews {message.message}
+ {message.type === 'apiMessage' && message.id && chatFeedbackStatus ? ( + <> + + copyMessageToClipboard(message.message)} /> + {!message.feedback || + message.feedback.rating === '' || + message.feedback.rating === 'THUMBS_UP' ? ( + onThumbsUpClick(message.id)} + /> + ) : null} + {!message.feedback || + message.feedback.rating === '' || + message.feedback.rating === 'THUMBS_DOWN' ? ( + onThumbsDownClick(message.id)} + /> + ) : null} + + setShowFeedbackContentDialog(false)} + onConfirm={submitFeedbackContent} + /> + + ) : null} {message.fileAnnotations && (
{message.fileAnnotations.map((fileAnnotation, index) => { From ed6b3b2a6d7becc887b534cdbcf1919d5822b697 Mon Sep 17 00:00:00 2001 From: Ilango Date: Mon, 11 Mar 2024 21:54:42 +0530 Subject: [PATCH 3/8] Update stats API - date and source filters apply to stats --- packages/server/src/index.ts | 40 +++++++++++---- packages/ui/src/api/feedback.js | 2 +- .../ui-component/dialog/ViewMessagesDialog.js | 50 ++++++++++++------- 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index c40581bf..1877eca8 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -723,19 +723,41 @@ export class App { // get stats for showing in chatflow this.app.get('/api/v1/stats/:id', async (req: Request, res: Response) => { const chatflowid = req.params.id - const chatTypeFilter = chatType.EXTERNAL + let chatTypeFilter = req.query?.chatType as chatType | undefined + const startDate = req.query?.startDate as string | undefined + const endDate = req.query?.endDate as string | undefined - const totalMessages = await this.AppDataSource.getRepository(ChatMessage).count({ - where: { - chatflowid, - chatType: chatTypeFilter + if (chatTypeFilter) { + try { + const chatTypeFilterArray = JSON.parse(chatTypeFilter) + if (chatTypeFilterArray.includes(chatType.EXTERNAL) && chatTypeFilterArray.includes(chatType.INTERNAL)) { + chatTypeFilter = undefined + } else if (chatTypeFilterArray.includes(chatType.EXTERNAL)) { + chatTypeFilter = chatType.EXTERNAL + } else if (chatTypeFilterArray.includes(chatType.INTERNAL)) { + chatTypeFilter = chatType.INTERNAL + } + } catch (e) { + return res.status(500).send(e) } - }) + } - const chatMessageFeedbackRepo = this.AppDataSource.getRepository(ChatMessageFeedback) + const chatmessages = (await this.getChatMessage( + chatflowid, + chatTypeFilter, + undefined, + undefined, + undefined, + undefined, + startDate, + endDate, + '', + true + )) as Array + const totalMessages = chatmessages.length - const totalFeedback = await chatMessageFeedbackRepo.count({ where: { chatflowid } }) - const positiveFeedback = await chatMessageFeedbackRepo.countBy({ chatflowid, rating: ChatMessageRatingType.THUMBS_UP }) + const totalFeedback = chatmessages.filter((message) => !message?.feedback).length + const positiveFeedback = chatmessages.filter((message) => message?.feedback?.rating === 'THUMBS_UP').length const results = { totalMessages, diff --git a/packages/ui/src/api/feedback.js b/packages/ui/src/api/feedback.js index 5b32ca26..4c2becf8 100644 --- a/packages/ui/src/api/feedback.js +++ b/packages/ui/src/api/feedback.js @@ -1,6 +1,6 @@ import client from './client' -const getStatsFromChatflow = (id) => client.get(`/stats/${id}`) +const getStatsFromChatflow = (id, params) => client.get(`/stats/${id}`, { params: { ...params } }) export default { getStatsFromChatflow diff --git a/packages/ui/src/ui-component/dialog/ViewMessagesDialog.js b/packages/ui/src/ui-component/dialog/ViewMessagesDialog.js index a0b3e396..240d1421 100644 --- a/packages/ui/src/ui-component/dialog/ViewMessagesDialog.js +++ b/packages/ui/src/ui-component/dialog/ViewMessagesDialog.js @@ -115,6 +115,11 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { endDate: endDate, chatType: chatTypeFilter.length ? chatTypeFilter : undefined }) + getStatsApi.request(dialogProps.chatflow.id, { + startDate: date, + endDate: endDate, + chatType: chatTypeFilter.length ? chatTypeFilter : undefined + }) } const onEndDateSelected = (date) => { @@ -124,6 +129,11 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { startDate: startDate, chatType: chatTypeFilter.length ? chatTypeFilter : undefined }) + getStatsApi.request(dialogProps.chatflow.id, { + endDate: date, + startDate: startDate, + chatType: chatTypeFilter.length ? chatTypeFilter : undefined + }) } const onChatTypeSelected = (chatTypes) => { @@ -133,6 +143,11 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { startDate: startDate, endDate: endDate }) + getStatsApi.request(dialogProps.chatflow.id, { + chatType: chatTypes.length ? chatTypes : undefined, + startDate: startDate, + endDate: endDate + }) } const exportMessages = async () => { @@ -432,6 +447,7 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { setSelectedMessageIndex(0) setStartDate(new Date().setMonth(new Date().getMonth() - 1)) setEndDate(new Date()) + setStats([]) } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -463,23 +479,6 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { <> -
- - - -
{
+
+ + + +
{chatlogs && chatlogs.length == 0 && ( From 2a30dbfd4c693b257fb65526f588e8c66a599750 Mon Sep 17 00:00:00 2001 From: Ilango Date: Mon, 11 Mar 2024 22:00:43 +0530 Subject: [PATCH 4/8] Fix issue in total feedback received stat --- packages/server/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 1877eca8..56a3451a 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -756,7 +756,7 @@ export class App { )) as Array const totalMessages = chatmessages.length - const totalFeedback = chatmessages.filter((message) => !message?.feedback).length + const totalFeedback = chatmessages.filter((message) => message?.feedback).length const positiveFeedback = chatmessages.filter((message) => message?.feedback?.rating === 'THUMBS_UP').length const results = { From f16254203e3543b6e332f7abc42333e01dfae5e6 Mon Sep 17 00:00:00 2001 From: Ilango Date: Tue, 12 Mar 2024 13:33:47 +0530 Subject: [PATCH 5/8] Fix build errors --- ...boardButton.js => CopyToClipboardButton.jsx} | 0 ...ThumbsDownButton.js => ThumbsDownButton.jsx} | 0 .../{ThumbsUpButton.js => ThumbsUpButton.jsx} | 0 .../cards/{StatsCard.js => StatsCard.jsx} | 0 ...tDialog.js => ChatFeedbackContentDialog.jsx} | 4 ++-- ...FeedbackDialog.js => ChatFeedbackDialog.jsx} | 17 +++++++++++------ .../extended/{Feedback.js => Feedback.jsx} | 0 7 files changed, 13 insertions(+), 8 deletions(-) rename packages/ui/src/ui-component/button/{CopyToClipboardButton.js => CopyToClipboardButton.jsx} (100%) rename packages/ui/src/ui-component/button/{ThumbsDownButton.js => ThumbsDownButton.jsx} (100%) rename packages/ui/src/ui-component/button/{ThumbsUpButton.js => ThumbsUpButton.jsx} (100%) rename packages/ui/src/ui-component/cards/{StatsCard.js => StatsCard.jsx} (100%) rename packages/ui/src/ui-component/dialog/{ChatFeedbackContentDialog.js => ChatFeedbackContentDialog.jsx} (94%) rename packages/ui/src/ui-component/dialog/{ChatFeedbackDialog.js => ChatFeedbackDialog.jsx} (91%) rename packages/ui/src/ui-component/extended/{Feedback.js => Feedback.jsx} (100%) diff --git a/packages/ui/src/ui-component/button/CopyToClipboardButton.js b/packages/ui/src/ui-component/button/CopyToClipboardButton.jsx similarity index 100% rename from packages/ui/src/ui-component/button/CopyToClipboardButton.js rename to packages/ui/src/ui-component/button/CopyToClipboardButton.jsx diff --git a/packages/ui/src/ui-component/button/ThumbsDownButton.js b/packages/ui/src/ui-component/button/ThumbsDownButton.jsx similarity index 100% rename from packages/ui/src/ui-component/button/ThumbsDownButton.js rename to packages/ui/src/ui-component/button/ThumbsDownButton.jsx diff --git a/packages/ui/src/ui-component/button/ThumbsUpButton.js b/packages/ui/src/ui-component/button/ThumbsUpButton.jsx similarity index 100% rename from packages/ui/src/ui-component/button/ThumbsUpButton.js rename to packages/ui/src/ui-component/button/ThumbsUpButton.jsx diff --git a/packages/ui/src/ui-component/cards/StatsCard.js b/packages/ui/src/ui-component/cards/StatsCard.jsx similarity index 100% rename from packages/ui/src/ui-component/cards/StatsCard.js rename to packages/ui/src/ui-component/cards/StatsCard.jsx diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js b/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx similarity index 94% rename from packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js rename to packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx index 56d81d14..3bb5524d 100644 --- a/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.js +++ b/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx @@ -7,10 +7,10 @@ import { Button, Dialog, DialogContent, DialogTitle, DialogActions, Box, Outline import { useState } from 'react' // Project import -import { StyledButton } from 'ui-component/button/StyledButton' +import { StyledButton } from '@/ui-component/button/StyledButton' // store -import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' +import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' const ChatFeedbackContentDialog = ({ show, onCancel, onConfirm }) => { const portalElement = document.getElementById('portal') diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx similarity index 91% rename from packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js rename to packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx index a88c6f35..54bb4408 100644 --- a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js +++ b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx @@ -2,22 +2,27 @@ import { createPortal } from 'react-dom' import { useDispatch } from 'react-redux' import { useState, useEffect } from 'react' import PropTypes from 'prop-types' -import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions' // material-ui import { Button, Dialog, DialogContent, DialogTitle, DialogActions, Box } from '@mui/material' import { IconX } from '@tabler/icons' // Project import -import { StyledButton } from 'ui-component/button/StyledButton' -import { SwitchInput } from 'ui-component/switch/Switch' +import { StyledButton } from '@/ui-component/button/StyledButton' +import { SwitchInput } from '@/ui-component/switch/Switch' // store -import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' -import useNotifier from 'utils/useNotifier' +import { + enqueueSnackbar as enqueueSnackbarAction, + closeSnackbar as closeSnackbarAction, + SET_CHATFLOW, + HIDE_CANVAS_DIALOG, + SHOW_CANVAS_DIALOG +} from '@/store/actions' +import useNotifier from '@/utils/useNotifier' // API -import chatflowsApi from 'api/chatflows' +import chatflowsApi from '@/api/chatflows' const ChatFeedbackDialog = ({ show, dialogProps, onCancel, onConfirm }) => { const portalElement = document.getElementById('portal') diff --git a/packages/ui/src/ui-component/extended/Feedback.js b/packages/ui/src/ui-component/extended/Feedback.jsx similarity index 100% rename from packages/ui/src/ui-component/extended/Feedback.js rename to packages/ui/src/ui-component/extended/Feedback.jsx From c557d8d19c595bb4744740b041b3988707afdfa3 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 12 Mar 2024 16:53:20 +0800 Subject: [PATCH 6/8] update pnpm wordings --- README.md | 2 +- .../components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts | 4 ---- packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts | 4 ---- packages/components/nodes/llms/HuggingFaceInference/core.ts | 2 +- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6ada9a2f..7c5473de 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Flowise has 3 different modules in a single mono repository. ### Prerequisite -- Install [Yarn v1](https://pnpm.io/installation) +- Install [PNPM](https://pnpm.io/installation) ```bash npm i -g pnpm ``` diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index 31d78270..ab5bc0df 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -6,10 +6,6 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' /** - * I had to run the following to build the component - * and get the icon copied over to the dist directory - * Flowise/packages/components > yarn build - * * @author Michael Connor */ class AWSChatBedrock_ChatModels implements INode { diff --git a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts index 7b095fb9..4516e044 100644 --- a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts +++ b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts @@ -6,10 +6,6 @@ import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../ import { BaseBedrockInput } from '@langchain/community/dist/utils/bedrock' /** - * I had to run the following to build the component - * and get the icon copied over to the dist directory - * Flowise/packages/components > yarn build - * * @author Michael Connor */ class AWSBedrock_LLMs implements INode { diff --git a/packages/components/nodes/llms/HuggingFaceInference/core.ts b/packages/components/nodes/llms/HuggingFaceInference/core.ts index 0d74bbe7..eb99d4a3 100644 --- a/packages/components/nodes/llms/HuggingFaceInference/core.ts +++ b/packages/components/nodes/llms/HuggingFaceInference/core.ts @@ -107,7 +107,7 @@ export class HuggingFaceInference extends LLM implements HFInput { const { HfInference } = await import('@huggingface/inference') return { HfInference } } catch (e) { - throw new Error('Please install huggingface as a dependency with, e.g. `yarn add @huggingface/inference`') + throw new Error('Please install huggingface as a dependency with, e.g. `pnpm add @huggingface/inference`') } } } From 25000305ee08de29d591fd7d9598becf6d927515 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 12 Mar 2024 17:10:15 +0800 Subject: [PATCH 7/8] fix missing human message --- .../nodes/chains/ConversationChain/ConversationChain.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index 16493adc..94c1e14f 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -199,14 +199,15 @@ const prepareChatPrompt = (nodeData: INodeData, humanImageMessages: MessageConte const messages: BaseMessagePromptTemplateLike[] = [ SystemMessagePromptTemplate.fromTemplate(prompt ? prompt : systemMessage), - new MessagesPlaceholder(memory.memoryKey ?? 'chat_history') + new MessagesPlaceholder(memory.memoryKey ?? 'chat_history'), + HumanMessagePromptTemplate.fromTemplate(`{${inputKey}}`) ] // OpenAI works better when separate images into standalone human messages if (model instanceof ChatOpenAI && humanImageMessages.length) { - messages.push(HumanMessagePromptTemplate.fromTemplate(`{${inputKey}}`)) messages.push(new HumanMessage({ content: [...humanImageMessages] })) } else if (humanImageMessages.length) { + messages.pop() messages.push(HumanMessagePromptTemplate.fromTemplate([`{${inputKey}}`, ...humanImageMessages])) } From 2853b3149bf3b049e1db9b0e5704ce4644f59776 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 12 Mar 2024 18:46:34 +0800 Subject: [PATCH 8/8] update dialog position, and clear feedback content after dialog disappear --- .../ui-component/dialog/ChatFeedbackContentDialog.jsx | 5 ++++- packages/ui/src/views/chatmessage/ChatMessage.jsx | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx b/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx index 3bb5524d..6b34aeca 100644 --- a/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx +++ b/packages/ui/src/ui-component/dialog/ChatFeedbackContentDialog.jsx @@ -27,7 +27,10 @@ const ChatFeedbackContentDialog = ({ show, onCancel, onConfirm }) => { useEffect(() => { if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) else dispatch({ type: HIDE_CANVAS_DIALOG }) - return () => dispatch({ type: HIDE_CANVAS_DIALOG }) + return () => { + dispatch({ type: HIDE_CANVAS_DIALOG }) + setFeedbackContent('') + } }, [show, dispatch]) const component = show ? ( diff --git a/packages/ui/src/views/chatmessage/ChatMessage.jsx b/packages/ui/src/views/chatmessage/ChatMessage.jsx index 9e748fc0..e083552a 100644 --- a/packages/ui/src/views/chatmessage/ChatMessage.jsx +++ b/packages/ui/src/views/chatmessage/ChatMessage.jsx @@ -871,11 +871,6 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews /> ) : null} - setShowFeedbackContentDialog(false)} - onConfirm={submitFeedbackContent} - /> ) : null} {message.fileAnnotations && ( @@ -1124,6 +1119,11 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews )}
setSourceDialogOpen(false)} /> + setShowFeedbackContentDialog(false)} + onConfirm={submitFeedbackContent} + /> ) }