mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-05-11 12:20:24 +02:00
Add predefined feedback option
This commit is contained in:
parent
957d3625c2
commit
7f1ffa3921
@ -0,0 +1,25 @@
|
|||||||
|
"""Add pre-defined feedback
|
||||||
|
|
||||||
|
Revision ID: f1c6478c3fd8
|
||||||
|
Revises: 643a84a42a33
|
||||||
|
Create Date: 2024-05-09 18:11:49.210667
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
revision = "f1c6478c3fd8"
|
||||||
|
down_revision = "643a84a42a33"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.add_column(
|
||||||
|
"chat_feedback",
|
||||||
|
sa.Column("predefined_feedback", sa.String(), nullable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_column("chat_feedback", "predefined_feedback")
|
@ -148,8 +148,14 @@ def create_chat_message_feedback(
|
|||||||
db_session: Session,
|
db_session: Session,
|
||||||
# Slack user requested help from human
|
# Slack user requested help from human
|
||||||
required_followup: bool | None = None,
|
required_followup: bool | None = None,
|
||||||
|
predefined_feedback: str | None = None, # Added predefined_feedback parameter
|
||||||
) -> None:
|
) -> None:
|
||||||
if is_positive is None and feedback_text is None and required_followup is None:
|
if (
|
||||||
|
is_positive is None
|
||||||
|
and feedback_text is None
|
||||||
|
and required_followup is None
|
||||||
|
and predefined_feedback is None
|
||||||
|
):
|
||||||
raise ValueError("No feedback provided")
|
raise ValueError("No feedback provided")
|
||||||
|
|
||||||
chat_message = get_chat_message(
|
chat_message = get_chat_message(
|
||||||
@ -164,6 +170,7 @@ def create_chat_message_feedback(
|
|||||||
is_positive=is_positive,
|
is_positive=is_positive,
|
||||||
feedback_text=feedback_text,
|
feedback_text=feedback_text,
|
||||||
required_followup=required_followup,
|
required_followup=required_followup,
|
||||||
|
predefined_feedback=predefined_feedback,
|
||||||
)
|
)
|
||||||
|
|
||||||
db_session.add(message_feedback)
|
db_session.add(message_feedback)
|
||||||
|
@ -763,6 +763,7 @@ class ChatMessageFeedback(Base):
|
|||||||
is_positive: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
is_positive: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
||||||
required_followup: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
required_followup: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
||||||
feedback_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
feedback_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
predefined_feedback: Mapped[str | None] = mapped_column(String, nullable=True)
|
||||||
|
|
||||||
chat_message: Mapped[ChatMessage] = relationship(
|
chat_message: Mapped[ChatMessage] = relationship(
|
||||||
"ChatMessage", back_populates="chat_message_feedbacks"
|
"ChatMessage", back_populates="chat_message_feedbacks"
|
||||||
|
@ -288,6 +288,7 @@ def create_chat_feedback(
|
|||||||
create_chat_message_feedback(
|
create_chat_message_feedback(
|
||||||
is_positive=feedback.is_positive,
|
is_positive=feedback.is_positive,
|
||||||
feedback_text=feedback.feedback_text,
|
feedback_text=feedback.feedback_text,
|
||||||
|
predefined_feedback=feedback.predefined_feedback,
|
||||||
chat_message_id=feedback.chat_message_id,
|
chat_message_id=feedback.chat_message_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
db_session=db_session,
|
db_session=db_session,
|
||||||
|
@ -51,6 +51,7 @@ class ChatFeedbackRequest(BaseModel):
|
|||||||
chat_message_id: int
|
chat_message_id: int
|
||||||
is_positive: bool | None = None
|
is_positive: bool | None = None
|
||||||
feedback_text: str | None = None
|
feedback_text: str | None = None
|
||||||
|
predefined_feedback: str | None = None
|
||||||
|
|
||||||
@root_validator
|
@root_validator
|
||||||
def check_is_positive_or_feedback_text(cls: BaseModel, values: dict) -> dict:
|
def check_is_positive_or_feedback_text(cls: BaseModel, values: dict) -> dict:
|
||||||
|
@ -201,6 +201,8 @@ services:
|
|||||||
args:
|
args:
|
||||||
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
||||||
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
||||||
|
- NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
|
- NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
depends_on:
|
depends_on:
|
||||||
- api_server
|
- api_server
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -197,6 +197,8 @@ services:
|
|||||||
args:
|
args:
|
||||||
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
||||||
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
||||||
|
- NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
|
- NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
depends_on:
|
depends_on:
|
||||||
- api_server
|
- api_server
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -73,6 +73,8 @@ services:
|
|||||||
args:
|
args:
|
||||||
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
||||||
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
||||||
|
- NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
|
- NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
depends_on:
|
depends_on:
|
||||||
- api_server
|
- api_server
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -73,6 +73,8 @@ services:
|
|||||||
args:
|
args:
|
||||||
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
- NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false}
|
||||||
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
- NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA:-false}
|
||||||
|
- NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
|
- NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS:-}
|
||||||
depends_on:
|
depends_on:
|
||||||
- api_server
|
- api_server
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -44,6 +44,13 @@ ENV NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING}
|
|||||||
ARG NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA
|
ARG NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA
|
||||||
ENV NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA}
|
ENV NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA}
|
||||||
|
|
||||||
|
# allow user to specify custom feedback options
|
||||||
|
ARG NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS
|
||||||
|
ENV NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS}
|
||||||
|
|
||||||
|
ARG NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS
|
||||||
|
ENV NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS}
|
||||||
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Step 3. Production image, copy all the files and run next
|
# Step 3. Production image, copy all the files and run next
|
||||||
@ -82,6 +89,13 @@ ENV NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING}
|
|||||||
ARG NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA
|
ARG NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA
|
||||||
ENV NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA}
|
ENV NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA}
|
||||||
|
|
||||||
|
# allow user to specify custom feedback options
|
||||||
|
ARG NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS
|
||||||
|
ENV NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS}
|
||||||
|
|
||||||
|
ARG NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS
|
||||||
|
ENV NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS}
|
||||||
|
|
||||||
# Note: Don't expose ports here, Compose will handle that for us if necessary.
|
# Note: Don't expose ports here, Compose will handle that for us if necessary.
|
||||||
# If you want to run this without compose, specify the ports to
|
# If you want to run this without compose, specify the ports to
|
||||||
# expose via cli
|
# expose via cli
|
||||||
|
@ -576,7 +576,8 @@ export function ChatPage({
|
|||||||
const onFeedback = async (
|
const onFeedback = async (
|
||||||
messageId: number,
|
messageId: number,
|
||||||
feedbackType: FeedbackType,
|
feedbackType: FeedbackType,
|
||||||
feedbackDetails: string
|
feedbackDetails: string,
|
||||||
|
predefinedFeedback: string | undefined
|
||||||
) => {
|
) => {
|
||||||
if (chatSessionId === null) {
|
if (chatSessionId === null) {
|
||||||
return;
|
return;
|
||||||
@ -585,7 +586,8 @@ export function ChatPage({
|
|||||||
const response = await handleChatFeedback(
|
const response = await handleChatFeedback(
|
||||||
messageId,
|
messageId,
|
||||||
feedbackType,
|
feedbackType,
|
||||||
feedbackDetails
|
feedbackDetails,
|
||||||
|
predefinedFeedback
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@ -648,11 +650,12 @@ export function ChatPage({
|
|||||||
<FeedbackModal
|
<FeedbackModal
|
||||||
feedbackType={currentFeedback[0]}
|
feedbackType={currentFeedback[0]}
|
||||||
onClose={() => setCurrentFeedback(null)}
|
onClose={() => setCurrentFeedback(null)}
|
||||||
onSubmit={(feedbackDetails) => {
|
onSubmit={({ message, predefinedFeedback }) => {
|
||||||
onFeedback(
|
onFeedback(
|
||||||
currentFeedback[1],
|
currentFeedback[1],
|
||||||
currentFeedback[0],
|
currentFeedback[0],
|
||||||
feedbackDetails
|
message,
|
||||||
|
predefinedFeedback
|
||||||
);
|
);
|
||||||
setCurrentFeedback(null);
|
setCurrentFeedback(null);
|
||||||
}}
|
}}
|
||||||
|
@ -150,7 +150,8 @@ export async function nameChatSession(chatSessionId: number, message: string) {
|
|||||||
export async function handleChatFeedback(
|
export async function handleChatFeedback(
|
||||||
messageId: number,
|
messageId: number,
|
||||||
feedback: FeedbackType,
|
feedback: FeedbackType,
|
||||||
feedbackDetails: string
|
feedbackDetails: string,
|
||||||
|
predefinedFeedback: string | undefined
|
||||||
) {
|
) {
|
||||||
const response = await fetch("/api/chat/create-chat-message-feedback", {
|
const response = await fetch("/api/chat/create-chat-message-feedback", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@ -161,11 +162,11 @@ export async function handleChatFeedback(
|
|||||||
chat_message_id: messageId,
|
chat_message_id: messageId,
|
||||||
is_positive: feedback === "like",
|
is_positive: feedback === "like",
|
||||||
feedback_text: feedbackDetails,
|
feedback_text: feedbackDetails,
|
||||||
|
predefined_feedback: predefinedFeedback,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renameChatSession(
|
export async function renameChatSession(
|
||||||
chatSessionId: number,
|
chatSessionId: number,
|
||||||
newName: string
|
newName: string
|
||||||
|
@ -5,10 +5,23 @@ import { FeedbackType } from "../types";
|
|||||||
import { FiThumbsDown, FiThumbsUp } from "react-icons/fi";
|
import { FiThumbsDown, FiThumbsUp } from "react-icons/fi";
|
||||||
import { ModalWrapper } from "./ModalWrapper";
|
import { ModalWrapper } from "./ModalWrapper";
|
||||||
|
|
||||||
|
const predefinedPositiveFeedbackOptions =
|
||||||
|
process.env.NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS?.split(",") ||
|
||||||
|
[];
|
||||||
|
const predefinedNegativeFeedbackOptions =
|
||||||
|
process.env.NEXT_PUBLIC_NEGATIVE_PREDEFINED_FEEDBACK_OPTIONS?.split(",") || [
|
||||||
|
"Retrieved documents were not relevant",
|
||||||
|
"AI misread the documents",
|
||||||
|
"Cited source had incorrect information",
|
||||||
|
];
|
||||||
|
|
||||||
interface FeedbackModalProps {
|
interface FeedbackModalProps {
|
||||||
feedbackType: FeedbackType;
|
feedbackType: FeedbackType;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSubmit: (feedbackDetails: string) => void;
|
onSubmit: (feedbackDetails: {
|
||||||
|
message: string;
|
||||||
|
predefinedFeedback?: string;
|
||||||
|
}) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FeedbackModal = ({
|
export const FeedbackModal = ({
|
||||||
@ -17,6 +30,23 @@ export const FeedbackModal = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
}: FeedbackModalProps) => {
|
}: FeedbackModalProps) => {
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
|
const [predefinedFeedback, setPredefinedFeedback] = useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
|
|
||||||
|
const handlePredefinedFeedback = (feedback: string) => {
|
||||||
|
setPredefinedFeedback(feedback);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
onSubmit({ message, predefinedFeedback });
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const predefinedFeedbackOptions =
|
||||||
|
feedbackType === "like"
|
||||||
|
? predefinedPositiveFeedbackOptions
|
||||||
|
: predefinedNegativeFeedbackOptions;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalWrapper onClose={onClose} modalClassName="max-w-5xl">
|
<ModalWrapper onClose={onClose} modalClassName="max-w-5xl">
|
||||||
@ -31,49 +61,43 @@ export const FeedbackModal = ({
|
|||||||
</div>
|
</div>
|
||||||
Provide additional feedback
|
Provide additional feedback
|
||||||
</h2>
|
</h2>
|
||||||
|
<div className="mb-4 flex flex-wrap justify-start">
|
||||||
|
{predefinedFeedbackOptions.map((feedback, index) => (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
className={`bg-border hover:bg-hover text-default py-2 px-4 rounded m-1
|
||||||
|
${predefinedFeedback === feedback && "ring-2 ring-accent"}`}
|
||||||
|
onClick={() => handlePredefinedFeedback(feedback)}
|
||||||
|
>
|
||||||
|
{feedback}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
<textarea
|
<textarea
|
||||||
autoFocus
|
autoFocus
|
||||||
className={`
|
className={`
|
||||||
w-full
|
w-full flex-grow
|
||||||
flex-grow
|
border border-border-strong rounded
|
||||||
ml-2
|
outline-none placeholder-subtle
|
||||||
border
|
pl-4 pr-4 py-4 bg-background
|
||||||
border-border-strong
|
overflow-hidden h-28
|
||||||
rounded
|
whitespace-normal resize-none
|
||||||
outline-none
|
break-all overscroll-contain
|
||||||
placeholder-subtle
|
`}
|
||||||
pl-4
|
|
||||||
pr-14
|
|
||||||
py-4
|
|
||||||
bg-background
|
|
||||||
overflow-hidden
|
|
||||||
h-28
|
|
||||||
whitespace-normal
|
|
||||||
resize-none
|
|
||||||
break-all
|
|
||||||
overscroll-contain`}
|
|
||||||
role="textarea"
|
role="textarea"
|
||||||
aria-multiline
|
aria-multiline
|
||||||
placeholder={
|
placeholder={
|
||||||
feedbackType === "like"
|
feedbackType === "like"
|
||||||
? "What did you like about this response?"
|
? "(Optional) What did you like about this response?"
|
||||||
: "What was the issue with the response? How could it be improved?"
|
: "(Optional) What was the issue with the response? How could it be improved?"
|
||||||
}
|
}
|
||||||
value={message}
|
value={message}
|
||||||
onChange={(e) => setMessage(e.target.value)}
|
onChange={(e) => setMessage(e.target.value)}
|
||||||
onKeyDown={(event) => {
|
|
||||||
if (event.key === "Enter" && !event.shiftKey) {
|
|
||||||
onSubmit(message);
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
suppressContentEditableWarning={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex mt-2">
|
<div className="flex mt-2">
|
||||||
<button
|
<button
|
||||||
className="bg-accent text-white py-2 px-4 rounded hover:bg-blue-600 focus:outline-none mx-auto"
|
className="bg-accent text-white py-2 px-4 rounded hover:bg-blue-600 focus:outline-none mx-auto"
|
||||||
onClick={() => onSubmit(message)}
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
Submit feedback
|
Submit feedback
|
||||||
</button>
|
</button>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user