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
sessionId?: string
createdDate: Date
feedbackId?: string
}
export interface IChatMessageFeedback {
@@ -49,6 +48,7 @@ export interface IChatMessageFeedback {
content?: string
chatflowid: string
chatId: string
messageId: string
rating: ChatMessageRatingType
createdDate: Date
}
@@ -40,7 +40,4 @@ export class ChatMessage implements IChatMessage {
@CreateDateColumn()
createdDate: Date
@Column({ nullable: true })
feedbackId?: string
}
@@ -1,8 +1,9 @@
/* eslint-disable */
import { Entity, Column, CreateDateColumn, PrimaryGeneratedColumn, Index } from 'typeorm'
import { ChatMessageRatingType, IChatMessageFeedback } from '../../Interface'
import { Entity, Column, CreateDateColumn, PrimaryGeneratedColumn, Index, Unique } from 'typeorm'
import { IChatMessageFeedback, ChatMessageRatingType } from '../../Interface'
@Entity()
@Unique(['messageId'])
export class ChatMessageFeedback implements IChatMessageFeedback {
@PrimaryGeneratedColumn('uuid')
id: string
@@ -11,15 +12,19 @@ export class ChatMessageFeedback implements IChatMessageFeedback {
@Column()
chatflowid: string
@Column({ type: 'text' })
content?: string
@Index()
@Column()
chatId: string
@Column()
messageId: string
@Column({ nullable: true })
rating: ChatMessageRatingType
@Column({ nullable: true, type: 'text' })
content?: string
@CreateDateColumn()
createdDate: Date
}
@@ -3,8 +3,10 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddFeedback1707213619308 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
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> {
@@ -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 { AddVariableEntity1699325775451 } from './1702200925471-AddVariableEntity'
import { AddFeedback1707213619308 } from './1707213619308-AddFeedback'
import { AddFeedbackToChatMessage1707986407818 } from './1707986407818-AddFeedbackToChatMessage'
export const sqliteMigrations = [
Init1693835579790,
@@ -28,6 +27,5 @@ export const sqliteMigrations = [
AddCategoryToChatFlow1699900910291,
AddFileAnnotationsToChatMessage1700271021237,
AddVariableEntity1699325775451,
AddFeedback1707213619308,
AddFeedbackToChatMessage1707986407818
AddFeedback1707213619308
]
+119 -41
View File
@@ -10,7 +10,7 @@ import logger from './utils/logger'
import { expressRequestLogger } from './utils/logger'
import { v4 as uuidv4 } from 'uuid'
import OpenAI from 'openai'
import { FindOptionsWhere, MoreThanOrEqual, LessThanOrEqual } from 'typeorm'
import { FindOptionsWhere, MoreThanOrEqual, LessThanOrEqual, IsNull, Between } from 'typeorm'
import {
IChatFlow,
IncomingInput,
@@ -22,7 +22,8 @@ import {
IChatMessage,
IChatMessageFeedback,
IDepthQueue,
INodeDirectedGraph
INodeDirectedGraph,
ChatMessageRatingType
} from './Interface'
import {
getNodeModulesPackagePath,
@@ -170,7 +171,8 @@ export class App {
'/api/v1/components-credentials-icon/',
'/api/v1/chatflows-streaming',
'/api/v1/openai-assistants-file',
'/api/v1/ip'
'/api/v1/ip',
'/api/v1/feedback'
]
this.app.use((req, res, next) => {
if (req.url.includes('/api/v1/')) {
@@ -610,31 +612,62 @@ export class App {
// 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) => {
const body = req.body
const results = await this.addChatMessageFeedback(body)
return res.json(results)
})
// Update feedback
// Update chatmessage feedback for id
this.app.put('/api/v1/feedback/:id', async (req: Request, res: Response) => {
const id = req.params.id
const body = req.body
const chatMessageFeedback = await this.AppDataSource.getRepository(ChatMessageFeedback).findOneBy({
id: req.params.id
await this.updateChatMessageFeedback(id, body)
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) {
res.status(404).send(`Feedback ${req.params.id} not found`)
return
const chatMessageFeedbackRepo = this.AppDataSource.getRepository(ChatMessageFeedback)
const totalFeedback = await chatMessageFeedbackRepo.count()
const positiveFeedback = await chatMessageFeedbackRepo.countBy({ rating: ChatMessageRatingType.THUMBS_UP })
const results = {
totalMessages,
totalFeedback,
positiveFeedback
}
const newChatMessageFeedback = new ChatMessageFeedback()
Object.assign(newChatMessageFeedback, body)
this.AppDataSource.getRepository(ChatMessageFeedback).merge(chatMessageFeedback, newChatMessageFeedback)
const results = await this.AppDataSource.getRepository(ChatMessageFeedback).save(chatMessageFeedback)
return res.json(results)
res.json(results)
})
// ----------------------------------------
@@ -1497,6 +1530,28 @@ export class App {
let toDate
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({
where: {
chatflowid,
@@ -1526,39 +1581,61 @@ export class App {
return await this.AppDataSource.getRepository(ChatMessage).save(chatmessage)
}
async updateChatMessage(id: string, update: Partial<IChatMessage>) {
const chatMessage = await this.AppDataSource.getRepository(ChatMessage).findOneBy({
id
/**
* Method that get chat messages.
* @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
*/
async addChatMessageFeedback(chatMessageFeedback: Partial<IChatMessageFeedback> & { messageId: string }): Promise<ChatMessageFeedback> {
const messageId = chatMessageFeedback.messageId
const newFeedback = new ChatMessageFeedback()
Object.assign(newFeedback, chatMessageFeedback)
async addChatMessageFeedback(chatMessageFeedback: Partial<IChatMessageFeedback>): Promise<ChatMessageFeedback> {
const newChatMessageFeedback = new ChatMessageFeedback()
Object.assign(newChatMessageFeedback, chatMessageFeedback)
const feedback = this.AppDataSource.getRepository(ChatMessageFeedback).create(newFeedback)
const results = 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
const feedback = this.AppDataSource.getRepository(ChatMessageFeedback).create(newChatMessageFeedback)
return await this.AppDataSource.getRepository(ChatMessageFeedback).save(feedback)
}
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) {
try {
@@ -1941,7 +2018,7 @@ export class App {
sessionId,
createdDate: userMessageDateTime
}
await this.addChatMessage(userMessage)
const newMessage = await this.addChatMessage(userMessage)
let resultText = ''
if (result.text) resultText = result.text
@@ -1974,6 +2051,7 @@ export class App {
// Prepare response
result.chatId = chatId
if (newMessage.id && !isInternal) result.messageId = newMessage.id
if (sessionId) result.sessionId = sessionId
if (memoryType) result.memoryType = memoryType