LibreChat/packages/data-provider/src/feedback.ts
Ruben Talstra 4cbab86b45
📈 feat: Chat rating for feedback (#5878)
* feat: working started for feedback implementation.

TODO:
- needs some refactoring.
- needs some UI animations.

* feat: working rate functionality

* feat: works now as well to reader the already rated responses from the server.

* feat: added the option to give feedback in text (optional)

* feat: added Dismiss option `x` to the `FeedbackTagOptions`

*  feat: Add rating and ratingContent fields to message schema

* 🔧 chore: Bump version to 0.0.3 in package.json

*  feat: Enhance feedback localization and update UI elements

* 🚀 feat: Implement feedback tagging system with thumbs up/down options

* 🚀 feat: Add data-provider package to unused i18n keys detection

* 🎨 style: update HoverButtons' style

* 🎨 style: Update HoverButtons and Fork components for improved styling and visibility

* 🔧 feat: Implement feedback system with rating and content options

* 🔧 feat: Enhance feedback handling with improved rating toggle and tag options

* 🔧 feat: Integrate toast notifications for feedback submission and clean up unused state

* 🔧 feat: Remove unused feedback tag options from translation file

*  refactor: clean up Feedback component and improve HoverButtons structure

*  refactor: remove unused settings switches for auto scroll, hide side panel, and user message markdown

* refactor: reorganize import order

*  refactor: enhance HoverButtons and Fork components with improved styles and animations

*  refactor: update feedback response phrases for improved user engagement

*  refactor: add CheckboxOption component and streamline fork options rendering

* Refactor feedback components and logic

- Consolidated feedback handling into a single Feedback component, removing FeedbackButtons and FeedbackTagOptions.
- Introduced new feedback tagging system with detailed tags for both thumbs up and thumbs down ratings.
- Updated feedback schema to include new tags and improved type definitions.
- Enhanced user interface for feedback collection, including a dialog for additional comments.
- Removed obsolete files and adjusted imports accordingly.
- Updated translations for new feedback tags and placeholders.

*  refactor: update feedback handling by replacing rating fields with feedback in message updates

* fix: add missing validateMessageReq middleware to feedback route and refactor feedback system

* 🗑️ chore: Remove redundant fork option explanations from translation file

* 🔧 refactor: Remove unused dependency from feedback callback

* 🔧 refactor: Simplify message update response structure and improve error logging

* Chore: removed unused tests.

---------

Co-authored-by: Marco Beretta <81851188+berry-13@users.noreply.github.com>
2025-05-30 12:16:34 -04:00

141 lines
3.2 KiB
TypeScript

import { z } from 'zod';
export type TFeedbackRating = 'thumbsUp' | 'thumbsDown';
export const FEEDBACK_RATINGS = ['thumbsUp', 'thumbsDown'] as const;
export const FEEDBACK_REASON_KEYS = [
// Down
'not_matched',
'inaccurate',
'bad_style',
'missing_image',
'unjustified_refusal',
'not_helpful',
'other',
// Up
'accurate_reliable',
'creative_solution',
'clear_well_written',
'attention_to_detail',
] as const;
export type TFeedbackTagKey = (typeof FEEDBACK_REASON_KEYS)[number];
export interface TFeedbackTag {
key: TFeedbackTagKey;
label: string;
direction: TFeedbackRating;
icon: string;
}
// --- Tag Registry ---
export const FEEDBACK_TAGS: TFeedbackTag[] = [
// Thumbs Down
{
key: 'not_matched',
label: 'com_ui_feedback_tag_not_matched',
direction: 'thumbsDown',
icon: 'AlertCircle',
},
{
key: 'inaccurate',
label: 'com_ui_feedback_tag_inaccurate',
direction: 'thumbsDown',
icon: 'AlertCircle',
},
{
key: 'bad_style',
label: 'com_ui_feedback_tag_bad_style',
direction: 'thumbsDown',
icon: 'PenTool',
},
{
key: 'missing_image',
label: 'com_ui_feedback_tag_missing_image',
direction: 'thumbsDown',
icon: 'ImageOff',
},
{
key: 'unjustified_refusal',
label: 'com_ui_feedback_tag_unjustified_refusal',
direction: 'thumbsDown',
icon: 'Ban',
},
{
key: 'not_helpful',
label: 'com_ui_feedback_tag_not_helpful',
direction: 'thumbsDown',
icon: 'ThumbsDown',
},
{
key: 'other',
label: 'com_ui_feedback_tag_other',
direction: 'thumbsDown',
icon: 'HelpCircle',
},
// Thumbs Up
{
key: 'accurate_reliable',
label: 'com_ui_feedback_tag_accurate_reliable',
direction: 'thumbsUp',
icon: 'CheckCircle',
},
{
key: 'creative_solution',
label: 'com_ui_feedback_tag_creative_solution',
direction: 'thumbsUp',
icon: 'Lightbulb',
},
{
key: 'clear_well_written',
label: 'com_ui_feedback_tag_clear_well_written',
direction: 'thumbsUp',
icon: 'PenTool',
},
{
key: 'attention_to_detail',
label: 'com_ui_feedback_tag_attention_to_detail',
direction: 'thumbsUp',
icon: 'Search',
},
];
export function getTagsForRating(rating: TFeedbackRating): TFeedbackTag[] {
return FEEDBACK_TAGS.filter((tag) => tag.direction === rating);
}
export const feedbackTagKeySchema = z.enum(FEEDBACK_REASON_KEYS);
export const feedbackRatingSchema = z.enum(FEEDBACK_RATINGS);
export const feedbackSchema = z.object({
rating: feedbackRatingSchema,
tag: feedbackTagKeySchema,
text: z.string().max(1024).optional(),
});
export type TMinimalFeedback = z.infer<typeof feedbackSchema>;
export type TFeedback = {
rating: TFeedbackRating;
tag: TFeedbackTag | undefined;
text?: string;
};
export function toMinimalFeedback(feedback: TFeedback | undefined): TMinimalFeedback | undefined {
if (!feedback?.rating || !feedback?.tag || !feedback.tag.key) {
return undefined;
}
return {
rating: feedback.rating,
tag: feedback.tag.key,
text: feedback.text,
};
}
export function getTagByKey(key: TFeedbackTagKey | undefined): TFeedbackTag | undefined {
if (!key) {
return undefined;
}
return FEEDBACK_TAGS.find((tag) => tag.key === key);
}