Fix merge conflict and update how feedback is saved/retrieved

This commit is contained in:
Ilango
2024-02-20 14:38:36 +05:30
parent f9f26204be
commit 3bb2b39896
12 changed files with 289 additions and 77 deletions
+1 -1
View File
@@ -41,7 +41,6 @@ export interface IChatMessage {
memoryType?: string memoryType?: string
sessionId?: string sessionId?: string
createdDate: Date createdDate: Date
feedbackId?: string
} }
export interface IChatMessageFeedback { export interface IChatMessageFeedback {
@@ -49,6 +48,7 @@ export interface IChatMessageFeedback {
content?: string content?: string
chatflowid: string chatflowid: string
chatId: string chatId: string
messageId: string
rating: ChatMessageRatingType rating: ChatMessageRatingType
createdDate: Date createdDate: Date
} }
@@ -40,7 +40,4 @@ export class ChatMessage implements IChatMessage {
@CreateDateColumn() @CreateDateColumn()
createdDate: Date createdDate: Date
@Column({ nullable: true })
feedbackId?: string
} }
@@ -1,8 +1,9 @@
/* eslint-disable */ /* eslint-disable */
import { Entity, Column, CreateDateColumn, PrimaryGeneratedColumn, Index } from 'typeorm' import { Entity, Column, CreateDateColumn, PrimaryGeneratedColumn, Index, Unique } from 'typeorm'
import { ChatMessageRatingType, IChatMessageFeedback } from '../../Interface' import { IChatMessageFeedback, ChatMessageRatingType } from '../../Interface'
@Entity() @Entity()
@Unique(['messageId'])
export class ChatMessageFeedback implements IChatMessageFeedback { export class ChatMessageFeedback implements IChatMessageFeedback {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
id: string id: string
@@ -11,15 +12,19 @@ export class ChatMessageFeedback implements IChatMessageFeedback {
@Column() @Column()
chatflowid: string chatflowid: string
@Column({ type: 'text' }) @Index()
content?: string
@Column() @Column()
chatId: string chatId: string
@Column() @Column()
messageId: string
@Column({ nullable: true })
rating: ChatMessageRatingType rating: ChatMessageRatingType
@Column({ nullable: true, type: 'text' })
content?: string
@CreateDateColumn() @CreateDateColumn()
createdDate: Date createdDate: Date
} }
@@ -3,8 +3,10 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddFeedback1707213619308 implements MigrationInterface { export class AddFeedback1707213619308 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "chat_message_feedback" ("id" varchar PRIMARY KEY NOT NULL, "chatflowid" varchar NOT NULL, "content" text, "chatId" varchar NOT NULL, "rating" varchar NOT NULL, "createdDate" datetime NOT NULL DEFAULT (datetime('now')));` `CREATE TABLE IF NOT EXISTS "chat_message_feedback" ("id" varchar PRIMARY KEY NOT NULL, "chatflowid" varchar NOT NULL, "chatId" varchar NOT NULL, "messageId" varchar NOT NULL, "rating" varchar NOT NULL, "content" text, "createdDate" datetime NOT NULL DEFAULT (datetime('now')));`
) )
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_e574527322272fd838f4f0f3d3" ON "chat_message_feedback" ("chatflowid") ;`)
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_e574527322272fd838f4f0f3d3" ON "chat_message_feedback" ("chatId") ;`)
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
@@ -1,20 +0,0 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddFeedbackToChatMessage1707986407818 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "temp_chat_message" ("id" varchar PRIMARY KEY NOT NULL, "role" varchar NOT NULL, "chatflowid" varchar NOT NULL, "content" text NOT NULL, "sourceDocuments" text, "usedTools" text, "fileAnnotations" text, "createdDate" datetime NOT NULL DEFAULT (datetime('now')), "chatType" VARCHAR NOT NULL DEFAULT 'INTERNAL', "chatId" VARCHAR NOT NULL, "memoryType" VARCHAR, "sessionId" VARCHAR, "feedbackId" varchar);`
)
await queryRunner.query(
`INSERT INTO "temp_chat_message" ("id", "role", "chatflowid", "content", "sourceDocuments", "usedTools", "fileAnnotations", "createdDate", "chatType", "chatId", "memoryType", "sessionId") SELECT "id", "role", "chatflowid", "content", "sourceDocuments", "usedTools", "fileAnnotations", "createdDate", "chatType", "chatId", "memoryType", "sessionId" FROM "chat_message";`
)
await queryRunner.query(`DROP TABLE "chat_message";`)
await queryRunner.query(`ALTER TABLE "temp_chat_message" RENAME TO "chat_message";`)
await queryRunner.query(`CREATE INDEX "IDX_e574527322272fd838f4f0f3d3" ON "chat_message" ("chatflowid") ;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE IF EXISTS "temp_chat_message";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "feedbackId";`)
}
}
@@ -12,7 +12,6 @@ import { AddCategoryToChatFlow1699900910291 } from './1699900910291-AddCategoryT
import { AddFileAnnotationsToChatMessage1700271021237 } from './1700271021237-AddFileAnnotationsToChatMessage' import { AddFileAnnotationsToChatMessage1700271021237 } from './1700271021237-AddFileAnnotationsToChatMessage'
import { AddVariableEntity1699325775451 } from './1702200925471-AddVariableEntity' import { AddVariableEntity1699325775451 } from './1702200925471-AddVariableEntity'
import { AddFeedback1707213619308 } from './1707213619308-AddFeedback' import { AddFeedback1707213619308 } from './1707213619308-AddFeedback'
import { AddFeedbackToChatMessage1707986407818 } from './1707986407818-AddFeedbackToChatMessage'
export const sqliteMigrations = [ export const sqliteMigrations = [
Init1693835579790, Init1693835579790,
@@ -28,6 +27,5 @@ export const sqliteMigrations = [
AddCategoryToChatFlow1699900910291, AddCategoryToChatFlow1699900910291,
AddFileAnnotationsToChatMessage1700271021237, AddFileAnnotationsToChatMessage1700271021237,
AddVariableEntity1699325775451, AddVariableEntity1699325775451,
AddFeedback1707213619308, AddFeedback1707213619308
AddFeedbackToChatMessage1707986407818
] ]
+119 -41
View File
@@ -10,7 +10,7 @@ import logger from './utils/logger'
import { expressRequestLogger } from './utils/logger' import { expressRequestLogger } from './utils/logger'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import OpenAI from 'openai' import OpenAI from 'openai'
import { FindOptionsWhere, MoreThanOrEqual, LessThanOrEqual } from 'typeorm' import { FindOptionsWhere, MoreThanOrEqual, LessThanOrEqual, IsNull, Between } from 'typeorm'
import { import {
IChatFlow, IChatFlow,
IncomingInput, IncomingInput,
@@ -22,7 +22,8 @@ import {
IChatMessage, IChatMessage,
IChatMessageFeedback, IChatMessageFeedback,
IDepthQueue, IDepthQueue,
INodeDirectedGraph INodeDirectedGraph,
ChatMessageRatingType
} from './Interface' } from './Interface'
import { import {
getNodeModulesPackagePath, getNodeModulesPackagePath,
@@ -170,7 +171,8 @@ export class App {
'/api/v1/components-credentials-icon/', '/api/v1/components-credentials-icon/',
'/api/v1/chatflows-streaming', '/api/v1/chatflows-streaming',
'/api/v1/openai-assistants-file', '/api/v1/openai-assistants-file',
'/api/v1/ip' '/api/v1/ip',
'/api/v1/feedback'
] ]
this.app.use((req, res, next) => { this.app.use((req, res, next) => {
if (req.url.includes('/api/v1/')) { if (req.url.includes('/api/v1/')) {
@@ -610,31 +612,62 @@ export class App {
// Chat Message Feedback // Chat Message Feedback
// ---------------------------------------- // ----------------------------------------
// Create new feedback // Get all chatmessage feedback from chatflowid
this.app.get('/api/v1/feedback/:id', async (req: Request, res: Response) => {
const chatflowid = req.params.id
const chatId = req.query?.chatId as string | undefined
const sortOrder = req.query?.order as string | undefined
const startDate = req.query?.startDate as string | undefined
const endDate = req.query?.endDate as string | undefined
const feedback = await this.getChatMessageFeedback(chatflowid, chatId, sortOrder, startDate, endDate)
return res.json(feedback)
})
// Add chatmessage feedback for chatflowid
this.app.post('/api/v1/feedback/:id', async (req: Request, res: Response) => { this.app.post('/api/v1/feedback/:id', async (req: Request, res: Response) => {
const body = req.body const body = req.body
const results = await this.addChatMessageFeedback(body) const results = await this.addChatMessageFeedback(body)
return res.json(results) return res.json(results)
}) })
// Update feedback // Update chatmessage feedback for id
this.app.put('/api/v1/feedback/:id', async (req: Request, res: Response) => { this.app.put('/api/v1/feedback/:id', async (req: Request, res: Response) => {
const id = req.params.id
const body = req.body const body = req.body
const chatMessageFeedback = await this.AppDataSource.getRepository(ChatMessageFeedback).findOneBy({ await this.updateChatMessageFeedback(id, body)
id: req.params.id return res.json({ status: 'OK' })
})
// ----------------------------------------
// stats
// ----------------------------------------
//
// 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
const totalMessages = await this.AppDataSource.getRepository(ChatMessage).count({
where: {
chatflowid,
chatType: chatTypeFilter
}
}) })
if (!chatMessageFeedback) { const chatMessageFeedbackRepo = this.AppDataSource.getRepository(ChatMessageFeedback)
res.status(404).send(`Feedback ${req.params.id} not found`)
return const totalFeedback = await chatMessageFeedbackRepo.count()
const positiveFeedback = await chatMessageFeedbackRepo.countBy({ rating: ChatMessageRatingType.THUMBS_UP })
const results = {
totalMessages,
totalFeedback,
positiveFeedback
} }
const newChatMessageFeedback = new ChatMessageFeedback() res.json(results)
Object.assign(newChatMessageFeedback, body)
this.AppDataSource.getRepository(ChatMessageFeedback).merge(chatMessageFeedback, newChatMessageFeedback)
const results = await this.AppDataSource.getRepository(ChatMessageFeedback).save(chatMessageFeedback)
return res.json(results)
}) })
// ---------------------------------------- // ----------------------------------------
@@ -1497,6 +1530,28 @@ export class App {
let toDate let toDate
if (endDate) toDate = setDateToStartOrEndOfDay(endDate, 'end') if (endDate) toDate = setDateToStartOrEndOfDay(endDate, 'end')
if (feedback) {
const messages = await this.AppDataSource.getRepository(ChatMessage)
.createQueryBuilder('chat_message')
.leftJoinAndMapOne('chat_message.feedback', ChatMessageFeedback, 'feedback', 'feedback.messageId = chat_message.id')
.where('chat_message.chatflowid = :chatflowid', { chatflowid })
.andWhere(chatType ? 'chat_message.chatType = :chatType' : 'TRUE', { chatType })
.andWhere(chatId ? 'chat_message.chatId = :chatId' : 'TRUE', { chatId })
.andWhere(memoryType ? 'chat_message.memoryType = :memoryType' : 'TRUE', {
memoryType: memoryType ?? (chatId ? IsNull() : undefined)
})
.andWhere(sessionId ? 'chat_message.sessionId = :sessionId' : 'TRUE', {
sessionId: sessionId ?? (chatId ? IsNull() : undefined)
})
.andWhere(fromDate && toDate ? 'chat_message.createdDate = :createdDate' : 'TRUE', {
createdDate: toDate && fromDate ? Between(fromDate, toDate) : undefined
})
.orderBy('chat_message.createdDate', sortOrder === 'DESC' ? 'DESC' : 'ASC')
.getMany()
return messages
}
return await this.AppDataSource.getRepository(ChatMessage).find({ return await this.AppDataSource.getRepository(ChatMessage).find({
where: { where: {
chatflowid, chatflowid,
@@ -1526,39 +1581,61 @@ export class App {
return await this.AppDataSource.getRepository(ChatMessage).save(chatmessage) return await this.AppDataSource.getRepository(ChatMessage).save(chatmessage)
} }
async updateChatMessage(id: string, update: Partial<IChatMessage>) { /**
const chatMessage = await this.AppDataSource.getRepository(ChatMessage).findOneBy({ * Method that get chat messages.
id * @param {string} chatflowid
* @param {string} sortOrder
* @param {string} chatId
* @param {string} startDate
* @param {string} endDate
*/
async getChatMessageFeedback(
chatflowid: string,
chatId?: string,
sortOrder: string = 'ASC',
startDate?: string,
endDate?: string
): Promise<ChatMessageFeedback[]> {
let fromDate
if (startDate) fromDate = new Date(startDate)
let toDate
if (endDate) toDate = new Date(endDate)
return await this.AppDataSource.getRepository(ChatMessageFeedback).find({
where: {
chatflowid,
chatId,
createdDate: toDate && fromDate ? Between(fromDate, toDate) : undefined
},
order: {
createdDate: sortOrder === 'DESC' ? 'DESC' : 'ASC'
}
}) })
if (!chatMessage) return
const newChatMessage = new ChatMessage()
Object.assign(newChatMessage, update)
this.AppDataSource.getRepository(ChatMessage).merge(chatMessage, newChatMessage)
return await this.AppDataSource.getRepository(ChatMessage).save(chatMessage)
} }
/** /**
* Method that adds feedback for a chat message and updates the chat message with the feedback id. * Method that add chat message feedback.
* @param {Partial<IChatMessageFeedback>} chatMessageFeedback * @param {Partial<IChatMessageFeedback>} chatMessageFeedback
*/ */
async addChatMessageFeedback(chatMessageFeedback: Partial<IChatMessageFeedback> & { messageId: string }): Promise<ChatMessageFeedback> { async addChatMessageFeedback(chatMessageFeedback: Partial<IChatMessageFeedback>): Promise<ChatMessageFeedback> {
const messageId = chatMessageFeedback.messageId const newChatMessageFeedback = new ChatMessageFeedback()
const newFeedback = new ChatMessageFeedback() Object.assign(newChatMessageFeedback, chatMessageFeedback)
Object.assign(newFeedback, chatMessageFeedback)
const feedback = this.AppDataSource.getRepository(ChatMessageFeedback).create(newFeedback) const feedback = this.AppDataSource.getRepository(ChatMessageFeedback).create(newChatMessageFeedback)
const results = await this.AppDataSource.getRepository(ChatMessageFeedback).save(feedback) return await this.AppDataSource.getRepository(ChatMessageFeedback).save(feedback)
// use the message id to update the chat message with feedback id
await this.updateChatMessage(messageId, { feedbackId: results.id })
return results
} }
async updateChatMessageFeedback(id: string, update: Partial<IChatMessageFeedback>) {} /**
* Method that updates chat message feedback.
* @param {string} id
* @param {Partial<IChatMessageFeedback>} chatMessageFeedback
*/
async updateChatMessageFeedback(id: string, chatMessageFeedback: Partial<IChatMessageFeedback>) {
const newChatMessageFeedback = new ChatMessageFeedback()
Object.assign(newChatMessageFeedback, chatMessageFeedback)
await this.AppDataSource.getRepository(ChatMessageFeedback).update({ id }, chatMessageFeedback)
}
async upsertVector(req: Request, res: Response, isInternal: boolean = false) { async upsertVector(req: Request, res: Response, isInternal: boolean = false) {
try { try {
@@ -1941,7 +2018,7 @@ export class App {
sessionId, sessionId,
createdDate: userMessageDateTime createdDate: userMessageDateTime
} }
await this.addChatMessage(userMessage) const newMessage = await this.addChatMessage(userMessage)
let resultText = '' let resultText = ''
if (result.text) resultText = result.text if (result.text) resultText = result.text
@@ -1974,6 +2051,7 @@ export class App {
// Prepare response // Prepare response
result.chatId = chatId result.chatId = chatId
if (newMessage.id && !isInternal) result.messageId = newMessage.id
if (sessionId) result.sessionId = sessionId if (sessionId) result.sessionId = sessionId
if (memoryType) result.memoryType = memoryType if (memoryType) result.memoryType = memoryType
+3 -2
View File
@@ -1,8 +1,9 @@
import client from './client' import client from './client'
const getInternalChatmessageFromChatflow = (id) => client.get(`/internal-chatmessage/${id}`) const getInternalChatmessageFromChatflow = (id) => client.get(`/internal-chatmessage/${id}`)
const getAllChatmessageFromChatflow = (id, params = {}) => client.get(`/chatmessage/${id}`, { params: { order: 'DESC', ...params } }) const getAllChatmessageFromChatflow = (id, params = {}) =>
const getChatmessageFromPK = (id, params = {}) => client.get(`/chatmessage/${id}`, { params: { order: 'ASC', ...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 } })
const deleteChatmessage = (id, params = {}) => client.delete(`/chatmessage/${id}`, { params: { ...params } }) const deleteChatmessage = (id, params = {}) => client.delete(`/chatmessage/${id}`, { params: { ...params } })
export default { export default {
+7
View File
@@ -0,0 +1,7 @@
import client from './client'
const getStatsFromChatflow = (id) => client.get(`/stats/${id}`)
export default {
getStatsFromChatflow
}
@@ -0,0 +1,29 @@
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import Typography from '@mui/material/Typography'
const StatsCard = ({ title, stat }) => {
const customization = useSelector((state) => state.customization)
return (
<Card sx={{ border: '1px solid #e0e0e0', borderRadius: `${customization.borderRadius}px` }}>
<CardContent>
<Typography sx={{ fontSize: 14 }} color='text.secondary' gutterBottom>
{title}
</Typography>
<Typography sx={{ fontSize: 30, fontWeight: 500 }} color='text.secondary'>
{stat}
</Typography>
</CardContent>
</Card>
)
}
StatsCard.propTypes = {
title: PropTypes.string,
stat: PropTypes.string
}
export default StatsCard
@@ -37,12 +37,15 @@ import { CodeBlock } from 'ui-component/markdown/CodeBlock'
import SourceDocDialog from 'ui-component/dialog/SourceDocDialog' import SourceDocDialog from 'ui-component/dialog/SourceDocDialog'
import { MultiDropdown } from 'ui-component/dropdown/MultiDropdown' import { MultiDropdown } from 'ui-component/dropdown/MultiDropdown'
import { StyledButton } from 'ui-component/button/StyledButton' import { StyledButton } from 'ui-component/button/StyledButton'
import StatsCard from 'ui-component/cards/StatsCard'
import Feedback from 'ui-component/extended/Feedback'
// store // store
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
// API // API
import chatmessageApi from 'api/chatmessage' import chatmessageApi from 'api/chatmessage'
import feedbackApi from 'api/feedback'
import useApi from 'hooks/useApi' import useApi from 'hooks/useApi'
import useConfirm from 'hooks/useConfirm' import useConfirm from 'hooks/useConfirm'
@@ -83,6 +86,7 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
const [chatlogs, setChatLogs] = useState([]) const [chatlogs, setChatLogs] = useState([])
const [allChatlogs, setAllChatLogs] = useState([]) const [allChatlogs, setAllChatLogs] = useState([])
const [chatMessages, setChatMessages] = useState([]) const [chatMessages, setChatMessages] = useState([])
const [stats, setStats] = useState([])
const [selectedMessageIndex, setSelectedMessageIndex] = useState(0) const [selectedMessageIndex, setSelectedMessageIndex] = useState(0)
const [sourceDialogOpen, setSourceDialogOpen] = useState(false) const [sourceDialogOpen, setSourceDialogOpen] = useState(false)
const [sourceDialogProps, setSourceDialogProps] = useState({}) const [sourceDialogProps, setSourceDialogProps] = useState({})
@@ -92,6 +96,7 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
const getChatmessageApi = useApi(chatmessageApi.getAllChatmessageFromChatflow) const getChatmessageApi = useApi(chatmessageApi.getAllChatmessageFromChatflow)
const getChatmessageFromPKApi = useApi(chatmessageApi.getChatmessageFromPK) const getChatmessageFromPKApi = useApi(chatmessageApi.getChatmessageFromPK)
const getStatsApi = useApi(feedbackApi.getStatsFromChatflow)
const onStartDateSelected = (date) => { const onStartDateSelected = (date) => {
setStartDate(date) setStartDate(date)
@@ -366,9 +371,16 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [getChatmessageApi.data]) }, [getChatmessageApi.data])
useEffect(() => {
if (getStatsApi.data) {
setStats(getStatsApi.data)
}
}, [getStatsApi.data])
useEffect(() => { useEffect(() => {
if (dialogProps.chatflow) { if (dialogProps.chatflow) {
getChatmessageApi.request(dialogProps.chatflow.id) getChatmessageApi.request(dialogProps.chatflow.id)
getStatsApi.request(dialogProps.chatflow.id)
} }
return () => { return () => {
@@ -410,7 +422,33 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
<> <>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', width: '100%', marginBottom: 10 }}> <div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
gap: 10,
marginBottom: 16,
marginLeft: 8,
marginRight: 8
}}
>
<StatsCard title='Total Messages (External)' stat={`${stats.totalMessages}`} />
<StatsCard title='Total Feedback Received' stat={`${stats.totalFeedback}`} />
<StatsCard
title='Positive Feedback'
stat={`${((stats.positiveFeedback / stats.totalFeedback) * 100 || 0).toFixed(2)}%`}
/>
</div>
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
marginBottom: 16,
marginLeft: 8,
marginRight: 8
}}
>
<div style={{ marginRight: 10 }}> <div style={{ marginRight: 10 }}>
<b style={{ marginRight: 10 }}>From Date</b> <b style={{ marginRight: 10 }}>From Date</b>
<DatePicker <DatePicker
@@ -728,6 +766,12 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
})} })}
</div> </div>
)} )}
{message.type === 'apiMessage' && message.feedback ? (
<Feedback
content={message.feedback?.content || ''}
rating={message.feedback?.rating}
/>
) : null}
</div> </div>
</Box> </Box>
) )
@@ -0,0 +1,71 @@
import { Alert, IconButton } from '@mui/material'
import { useTheme } from '@mui/material/styles'
import PropTypes from 'prop-types'
const ThumbsUpIcon = () => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
width='20'
height='20'
viewBox='0 0 24 24'
fill='none'
stroke='currentColor'
strokeWidth='2'
strokeLinecap='round'
strokeLinejoin='round'
>
<path d='M7 10v12' />
<path d='M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z' />
</svg>
)
}
const ThumbsDownIcon = () => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
width='20'
height='20'
viewBox='0 0 24 24'
fill='none'
stroke='currentColor'
strokeWidth='2'
strokeLinecap='round'
strokeLinejoin='round'
>
<path d='M17 14V2' />
<path d='M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z' />
</svg>
)
}
const Feedback = ({ content, rating }) => {
const theme = useTheme()
return (
<div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'start' }}>
{content ? (
<Alert
icon={rating === 'THUMBS_UP' ? <ThumbsUpIcon /> : <ThumbsDownIcon />}
severity={rating === 'THUMBS_UP' ? 'success' : 'error'}
style={{ marginBottom: 14 }}
variant='outlined'
>
{content ? <span style={{ color: theme.palette.text.primary }}>{content}</span> : null}
</Alert>
) : (
<IconButton color={rating === 'THUMBS_UP' ? 'success' : 'error'} style={{ marginBottom: 14 }}>
{rating === 'THUMBS_UP' ? <ThumbsUpIcon /> : <ThumbsDownIcon />}
</IconButton>
)}
</div>
)
}
Feedback.propTypes = {
rating: PropTypes.oneOf(['THUMBS_UP', 'THUMBS_DOWN']),
content: PropTypes.string
}
export default Feedback