From 3aa78fe3afc3ab9a982ce0876fa6e6ea3f82b40a Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 7 Jan 2025 13:32:11 +0100 Subject: [PATCH] Now returning resource in static resource function --- front/lib/api/assistant/feedback.ts | 48 ++++- .../agent_message_feedback_resource.ts | 170 +++++++++--------- front/lib/swr/assistants.ts | 1 - front/lib/workspace_usage.ts | 23 ++- 4 files changed, 142 insertions(+), 100 deletions(-) diff --git a/front/lib/api/assistant/feedback.ts b/front/lib/api/assistant/feedback.ts index 7ce4086ab99b..5e2f441b30b7 100644 --- a/front/lib/api/assistant/feedback.ts +++ b/front/lib/api/assistant/feedback.ts @@ -30,28 +30,55 @@ export type AgentMessageFeedbackType = { isConversationShared: boolean; }; -export type AgentMessageFeedbackWithMetadataType = AgentMessageFeedbackType & { - conversationId: string | null; +export type FeedbackUserInfo = { userName: string; userEmail: string; userImageUrl: string | null; }; +export type FeedbackConversationInfo = { + conversationId: string | null; +}; + +export type AgentMessageFeedbackWithMetadataType = AgentMessageFeedbackType & + FeedbackConversationInfo & + FeedbackUserInfo; + export async function getConversationFeedbacksForUser( auth: Authenticator, conversation: ConversationType | ConversationWithoutContentType -): Promise> { +) { if (!canAccessConversation(auth, conversation)) { return new Err(new ConversationError("conversation_access_restricted")); } - const feedbacks = + const feedbacksRes = await AgentMessageFeedbackResource.getConversationFeedbacksForUser( auth, conversation ); - return feedbacks; + const feedbacks = feedbacksRes + .filter( + (feedback): feedback is AgentMessageFeedbackResource => feedback !== null + ) + .map((feedback) => { + const jsonFeedback = feedback.toJSON(); + return { + id: jsonFeedback.id, + messageId: jsonFeedback.messageId, + agentMessageId: jsonFeedback.agentMessageId, + userId: jsonFeedback.userId, + thumbDirection: jsonFeedback.thumbDirection, + content: jsonFeedback.content, + isConversationShared: jsonFeedback.isConversationShared, + createdAt: jsonFeedback.createdAt, + agentConfigurationId: jsonFeedback.agentConfigurationId, + agentConfigurationVersion: jsonFeedback.agentConfigurationVersion, + } as AgentMessageFeedbackType; + }); + + return new Ok(feedbacks); } /** @@ -204,20 +231,23 @@ export async function getAgentFeedbacks({ workspace: owner, agentConfiguration, paginationParams, - withMetadata, } ); + const feedbacks = feedbacksRes.map((feedback) => feedback.toJSON()); + if (!withMetadata) { - return new Ok(feedbacksRes); + return new Ok(feedbacks as AgentMessageFeedbackType[]); } - const feedbacksWithHiddenConversationId = feedbacksRes.map((feedback) => ({ + const feedbacksWithHiddenConversationId = feedbacks.map((feedback) => ({ ...feedback, // Redact the conversationId if user did not share the conversation. conversationId: feedback.isConversationShared ? (feedback as AgentMessageFeedbackWithMetadataType).conversationId : null, })); - return new Ok(feedbacksWithHiddenConversationId); + return new Ok( + feedbacksWithHiddenConversationId as AgentMessageFeedbackWithMetadataType[] + ); } diff --git a/front/lib/resources/agent_message_feedback_resource.ts b/front/lib/resources/agent_message_feedback_resource.ts index ec5b13b7b6e4..45d61be1de47 100644 --- a/front/lib/resources/agent_message_feedback_resource.ts +++ b/front/lib/resources/agent_message_feedback_resource.ts @@ -1,7 +1,6 @@ import type { AgentConfigurationType, AgentMessageType, - ConversationError, ConversationType, ConversationWithoutContentType, LightAgentConfigurationType, @@ -16,21 +15,18 @@ import type { Attributes, ModelStatic, WhereOptions } from "sequelize"; import type { CreationAttributes, Transaction } from "sequelize"; import { Op } from "sequelize"; -import type { - AgentMessageFeedbackType, - AgentMessageFeedbackWithMetadataType, -} from "@app/lib/api/assistant/feedback"; import type { PaginationParams } from "@app/lib/api/pagination"; import type { Authenticator } from "@app/lib/auth"; import { AgentConfiguration } from "@app/lib/models/assistant/agent"; -import { AgentMessage } from "@app/lib/models/assistant/conversation"; import { + AgentMessage, AgentMessage as AgentMessageModel, AgentMessageFeedback, Conversation, Message, } from "@app/lib/models/assistant/conversation"; import { BaseResource } from "@app/lib/resources/base_resource"; +import type { UserModel } from "@app/lib/resources/storage/models/user"; import type { ReadonlyAttributesType } from "@app/lib/resources/storage/types"; import { UserResource } from "@app/lib/resources/user_resource"; @@ -44,15 +40,35 @@ export interface AgentMessageFeedbackResource export class AgentMessageFeedbackResource extends BaseResource { static model: ModelStatic = AgentMessageFeedback; + readonly message?: Attributes; + readonly user?: Attributes; + readonly conversationId?: string; + constructor( model: ModelStatic, - blob: Attributes + blob: Attributes, + { + message, + user, + conversationId, + }: { + message?: Attributes; + user?: Attributes; + conversationId?: string; + } = {} ) { super(AgentMessageFeedback, blob); + + this.message = message; + this.user = user; + this.conversationId = conversationId; } static async makeNew( - blob: CreationAttributes + blob: CreationAttributes, + message?: Attributes, + user?: Attributes, + conversationId?: string ): Promise { const agentMessageFeedback = await AgentMessageFeedback.create({ ...blob, @@ -60,7 +76,8 @@ export class AgentMessageFeedbackResource extends BaseResource { + }) { const where: WhereOptions = { // Safety check: global models share ids across workspaces and some have had feedbacks. workspaceId: workspace.id, @@ -157,45 +170,17 @@ export class AgentMessageFeedbackResource extends BaseResource !!feedback.agentMessage?.message?.conversation - ) - .map((feedback) => { - return { - id: feedback.id, - messageId: feedback.agentMessage.message.sId, - agentMessageId: feedback.agentMessageId, - userId: feedback.userId, - thumbDirection: feedback.thumbDirection, - content: feedback.content - ? feedback.content.replace(/\r?\n/g, "\\n") - : null, - isConversationShared: feedback.isConversationShared, - createdAt: feedback.createdAt, - agentConfigurationId: feedback.agentConfigurationId, - agentConfigurationVersion: feedback.agentConfigurationVersion, - - ...(withMetadata && { - // This field is sensitive, it allows accessing the conversation - conversationId: feedback.isConversationShared - ? feedback.agentMessage.message.conversation.sId - : null, - userName: feedback.user.name, - userEmail: feedback.user.email, - userImageUrl: feedback.user.imageUrl, - }), - }; - }) - ); + return agentMessageFeedback.map((feedback) => { + return new AgentMessageFeedbackResource( + AgentMessageFeedback, + feedback.get(), + { + message: feedback.agentMessage?.message, + user: feedback.user, + conversationId: feedback.agentMessage?.message?.conversation?.sId, + } + ); + }); } static async getFeedbackUsageDataForWorkspace({ @@ -231,24 +216,23 @@ export class AgentMessageFeedbackResource extends BaseResource { - return { - id: feedback.id, - createdAt: feedback.createdAt, - userName: feedback.user.name, - userEmail: feedback.user.email, - agentConfigurationId: feedback.agentConfigurationId, - agentConfigurationVersion: feedback.agentConfigurationVersion, - thumb: feedback.thumbDirection, - content: feedback.content?.replace(/\r?\n/g, "\\n") || null, - }; - }); + return agentMessageFeedback + .filter((feedback) => !!feedback.user) + .map((feedback) => { + return new AgentMessageFeedbackResource( + AgentMessageFeedback, + feedback.get(), + { + user: feedback.user, + } + ); + }); } static async getConversationFeedbacksForUser( auth: Authenticator, conversation: ConversationType | ConversationWithoutContentType - ): Promise> { + ) { const user = auth.getNonNullableUser(); const feedbackForMessages = await Message.findAll({ @@ -276,36 +260,27 @@ export class AgentMessageFeedbackResource extends BaseResource !!message.agentMessage?.feedbacks && message.agentMessage.feedbacks.length > 0 ) .map((message) => { - // Only one feedback can be associated with a message - const feedback = message.agentMessage.feedbacks[0]; - return { - id: feedback.id, - messageId: message.sId, - agentMessageId: feedback.agentMessageId, - userId: feedback.userId, - thumbDirection: feedback.thumbDirection, - content: feedback.content, - isConversationShared: feedback.isConversationShared, - createdAt: feedback.createdAt, - agentConfigurationId: feedback.agentConfigurationId, - agentConfigurationVersion: feedback.agentConfigurationVersion, - } as AgentMessageFeedbackType; + const feedback = message.agentMessage?.feedbacks?.[0]; + return new AgentMessageFeedbackResource( + AgentMessageFeedback, + feedback.get(), + { + message, + } + ); }); - - return new Ok(feedbacksWithMessageId); + return feedbacks; } static async getFeedbackWithConversationContext({ @@ -436,4 +411,27 @@ export class AgentMessageFeedbackResource extends BaseResource { - console.log("previousPageData", previousPageData); if (!agentConfigurationId) { return null; } diff --git a/front/lib/workspace_usage.ts b/front/lib/workspace_usage.ts index 428c46511a3f..aec3181d2fa2 100644 --- a/front/lib/workspace_usage.ts +++ b/front/lib/workspace_usage.ts @@ -441,15 +441,30 @@ export async function getFeedbacksUsageData( workspace: WorkspaceType ): Promise { const feedbacks = - (await AgentMessageFeedbackResource.getFeedbackUsageDataForWorkspace({ + await AgentMessageFeedbackResource.getFeedbackUsageDataForWorkspace({ startDate, endDate, workspace, - })) as FeedbackQueryResult[]; - if (!feedbacks.length) { + }); + + if (!feedbacks || feedbacks.length === 0) { return "No data available for the selected period."; } - return generateCsvFromQueryResult(feedbacks); + + const feedbacksWithMinimalFields = feedbacks.map((feedback) => { + const jsonFeedback = feedback.toJSON(); + return { + id: jsonFeedback.id, + createdAt: jsonFeedback.createdAt, + userName: jsonFeedback.userName, + userEmail: jsonFeedback.userEmail, + agentConfigurationId: jsonFeedback.agentConfigurationId, + agentConfigurationVersion: jsonFeedback.agentConfigurationVersion, + thumb: jsonFeedback.thumbDirection, + content: jsonFeedback.content?.replace(/\r?\n/g, "\\n") || null, + }; + }) as FeedbackQueryResult[]; + return generateCsvFromQueryResult(feedbacksWithMinimalFields); } function generateCsvFromQueryResult(