Skip to content

Commit

Permalink
Merge pull request #1444 from Niharika0104/Fixes-#1260
Browse files Browse the repository at this point in the history
Fixed edit and resend issue
  • Loading branch information
dartpain authored Nov 25, 2024
2 parents 289bd41 + 8a67f18 commit 8d8423b
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 148 deletions.
36 changes: 26 additions & 10 deletions application/api/answer/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,19 @@ def is_azure_configured():
)


def save_conversation(conversation_id, question, response, source_log_docs, llm):
if conversation_id is not None and conversation_id != "None":
def save_conversation(conversation_id, question, response, source_log_docs, llm,index=None):
if conversation_id is not None and index is not None:
conversations_collection.update_one(
{"_id": ObjectId(conversation_id), f"queries.{index}": {"$exists": True}},
{
"$set": {
f"queries.{index}.prompt": question,
f"queries.{index}.response": response,
f"queries.{index}.sources": source_log_docs,
}
}
)
elif conversation_id is not None and conversation_id != "None":
conversations_collection.update_one(
{"_id": ObjectId(conversation_id)},
{
Expand Down Expand Up @@ -186,7 +197,7 @@ def get_prompt(prompt_id):


def complete_stream(
question, retriever, conversation_id, user_api_key, isNoneDoc=False
question, retriever, conversation_id, user_api_key, isNoneDoc=False,index=None
):

try:
Expand Down Expand Up @@ -217,7 +228,7 @@ def complete_stream(
)
if user_api_key is None:
conversation_id = save_conversation(
conversation_id, question, response_full, source_log_docs, llm
conversation_id, question, response_full, source_log_docs, llm,index
)
# send data.type = "end" to indicate that the stream has ended as json
data = json.dumps({"type": "id", "id": str(conversation_id)})
Expand Down Expand Up @@ -282,6 +293,9 @@ class Stream(Resource):
"isNoneDoc": fields.Boolean(
required=False, description="Flag indicating if no document is used"
),
"index":fields.Integer(
required=False, description="The position where query is to be updated"
),
},
)

Expand All @@ -290,23 +304,24 @@ class Stream(Resource):
def post(self):
data = request.get_json()
required_fields = ["question"]

if "index" in data:
required_fields = ["question","conversation_id"]
missing_fields = check_required_fields(data, required_fields)
if missing_fields:
return missing_fields

try:
question = data["question"]
history = data.get("history", [])
history = json.loads(history)
history = str(data.get("history", []))
history = str(json.loads(history))
conversation_id = data.get("conversation_id")
prompt_id = data.get("prompt_id", "default")


index=data.get("index",None)
chunks = int(data.get("chunks", 2))
token_limit = data.get("token_limit", settings.DEFAULT_MAX_HISTORY)
retriever_name = data.get("retriever", "classic")

if "api_key" in data:
data_key = get_data_from_api_key(data["api_key"])
chunks = int(data_key.get("chunks", 2))
Expand Down Expand Up @@ -343,14 +358,15 @@ def post(self):
gpt_model=gpt_model,
user_api_key=user_api_key,
)

return Response(
complete_stream(
question=question,
retriever=retriever,
conversation_id=conversation_id,
user_api_key=user_api_key,
isNoneDoc=data.get("isNoneDoc"),
index=index,
),
mimetype="text/event-stream",
)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const endpoints = {
TOKEN_ANALYTICS: '/api/get_token_analytics',
FEEDBACK_ANALYTICS: '/api/get_feedback_analytics',
LOGS: `/api/get_user_logs`,
MANAGE_SYNC: '/api/manage_sync',
MANAGE_SYNC: '/api/manage_sync'
},
CONVERSATION: {
ANSWER: '/api/answer',
Expand Down
36 changes: 28 additions & 8 deletions frontend/src/conversation/Conversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import { useDarkTheme, useMediaQuery } from '../hooks';
import { ShareConversationModal } from '../modals/ShareConversationModal';
import { selectConversationId } from '../preferences/preferenceSlice';
import { AppDispatch } from '../store';
import conversationService from '../api/services/conversationService';
import ConversationBubble from './ConversationBubble';
import { handleSendFeedback } from './conversationHandlers';
import { FEEDBACK, Query } from './conversationModels';
import {
addQuery,
fetchAnswer,
resendQuery,
selectQueries,
selectStatus,
setConversation,
Expand Down Expand Up @@ -85,15 +87,25 @@ export default function Conversation() {
const handleQuestion = ({
question,
isRetry = false,
updated = null,
indx = undefined,
}: {
question: string;
isRetry?: boolean;
updated?: boolean | null;
indx?: number;
}) => {
question = question.trim();
if (question === '') return;
setEventInterrupt(false);
!isRetry && dispatch(addQuery({ prompt: question })); //dispatch only new queries
fetchStream.current = dispatch(fetchAnswer({ question }));
if (updated === true) {
!isRetry &&
dispatch(resendQuery({ index: indx as number, prompt: question })); //dispatch only new queries
fetchStream.current = dispatch(fetchAnswer({ question, indx }));
} else {
question = question.trim();
if (question === '') return;
setEventInterrupt(false);
!isRetry && dispatch(addQuery({ prompt: question })); //dispatch only new queries
fetchStream.current = dispatch(fetchAnswer({ question }));
}
};

const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => {
Expand All @@ -104,8 +116,14 @@ export default function Conversation() {
);
};

const handleQuestionSubmission = () => {
if (inputRef.current?.value && status !== 'loading') {
const handleQuestionSubmission = (
updatedQuestion?: string,
updated?: boolean,
indx?: number,
) => {
if (updated === true) {
handleQuestion({ question: updatedQuestion as string, updated, indx });
} else if (inputRef.current?.value && status !== 'loading') {
if (lastQueryReturnedErr) {
// update last failed query with new prompt
dispatch(
Expand Down Expand Up @@ -290,6 +308,8 @@ export default function Conversation() {
key={`${index}QUESTION`}
message={query.prompt}
type="QUESTION"
handleUpdatedQuestionSubmission={handleQuestionSubmission}
questionNumber={index}
sources={query.sources}
></ConversationBubble>

Expand Down Expand Up @@ -328,7 +348,7 @@ export default function Conversation() {
<div className="mx-1 cursor-pointer rounded-full p-3 text-center hover:bg-gray-3000 dark:hover:bg-dark-charcoal">
<img
className="ml-[4px] h-6 w-6 text-white "
onClick={handleQuestionSubmission}
onClick={() => handleQuestionSubmission()}
src={isDarkTheme ? SendDark : Send}
></img>
</div>
Expand Down
86 changes: 77 additions & 9 deletions frontend/src/conversation/ConversationBubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Document from '../assets/document.svg';
import Like from '../assets/like.svg?react';
import Link from '../assets/link.svg';
import Sources from '../assets/sources.svg';
import Edit from '../assets/edit.svg';
import Avatar from '../components/Avatar';
import CopyButton from '../components/CopyButton';
import Sidebar from '../components/Sidebar';
Expand All @@ -38,37 +39,104 @@ const ConversationBubble = forwardRef<
handleFeedback?: (feedback: FEEDBACK) => void;
sources?: { title: string; text: string; source: string }[];
retryBtn?: React.ReactElement;
questionNumber?: number;
handleUpdatedQuestionSubmission?: (
updatedquestion?: string,
updated?: boolean,
index?: number,
) => void;
}
>(function ConversationBubble(
{ message, type, className, feedback, handleFeedback, sources, retryBtn },
{
message,
type,
className,
feedback,
handleFeedback,
sources,
retryBtn,
questionNumber,
handleUpdatedQuestionSubmission,
},
ref,
) {
// const bubbleRef = useRef<HTMLDivElement | null>(null);
const chunks = useSelector(selectChunks);
const selectedDocs = useSelector(selectSelectedDocs);
const [isLikeHovered, setIsLikeHovered] = useState(false);
const [isEditClicked, setIsEditClicked] = useState(false);
const [isDislikeHovered, setIsDislikeHovered] = useState(false);
const [isQuestionHovered, setIsQuestionHovered] = useState(false);
const [editInputBox, setEditInputBox] = useState<string>('');

const [isLikeClicked, setIsLikeClicked] = useState(false);
const [isDislikeClicked, setIsDislikeClicked] = useState(false);
const [activeTooltip, setActiveTooltip] = useState<number | null>(null);
const [isSidebarOpen, setIsSidebarOpen] = useState<boolean>(false);

const handleEditClick = () => {
setIsEditClicked(false);
handleUpdatedQuestionSubmission?.(editInputBox, true, questionNumber);
};
let bubble;
if (type === 'QUESTION') {
bubble = (
<div
ref={ref}
className={`flex flex-row-reverse self-end flex-wrap ${className}`}
onMouseEnter={() => setIsQuestionHovered(true)}
onMouseLeave={() => setIsQuestionHovered(false)}
>
<Avatar className="mt-2 text-2xl" avatar="🧑‍💻"></Avatar>
<div
style={{
wordBreak: 'break-word',
}}
className="ml-10 mr-2 flex items-center rounded-[28px] bg-purple-30 py-[14px] px-[19px] text-white max-w-full whitespace-pre-wrap leading-normal"
ref={ref}
className={`flex flex-row-reverse self-end flex-wrap ${className}`}
>
{message}
<Avatar className="mt-2 text-2xl" avatar="🧑‍💻"></Avatar>
{!isEditClicked && (
<div
style={{
wordBreak: 'break-word',
}}
className="ml-2 mr-2 flex items-center rounded-[28px] bg-purple-30 py-[14px] px-[19px] text-white max-w-full whitespace-pre-wrap leading-normal"
>
{message}
</div>
)}
{isEditClicked && (
<input
onChange={(e) => setEditInputBox(e.target.value)}
value={editInputBox}
className="w-[85%] ml-2 mr-2 rounded-[28px] py-[12px] dark:border-[0.5px] dark:border-white dark:bg-raisin-black dark:text-white px-[18px] border-[1.5px] border-black"
/>
)}
<div
className={` flex items-center ${isQuestionHovered ? 'visible' : 'invisible'}`}
>
<img
src={Edit}
alt="Edit"
className="cursor-pointer"
onClick={() => {
setIsEditClicked(true);
setEditInputBox(message);
}}
/>
</div>
</div>
{isEditClicked && (
<div className={`flex gap-3 self-end mt-3 `}>
<button
className="ml-2 mr-2 flex items-center rounded-[28px] font-semibold hover:font-bold py-[14px] px-[19px] no-underline hover:underline text-purple-500 max-w-full whitespace-pre-wrap leading-normal"
onClick={() => setIsEditClicked(false)}
>
Cancel
</button>
<button
className="ml-2 mr-2 flex items-center rounded-full bg-purple-300 hover:bg-purple-100 font-bold px-[19px] py-[2px] text-purple-500 max-w-full whitespace-pre-wrap leading-none"
onClick={() => handleEditClick()}
>
Update
</button>
</div>
)}
</div>
);
} else {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/conversation/conversationHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export function handleFetchAnswerSteaming(
chunks: string,
token_limit: number,
onEvent: (event: MessageEvent) => void,
indx?: number,
): Promise<Answer> {
history = history.map((item) => {
return { prompt: item.prompt, response: item.response };
Expand All @@ -87,6 +88,7 @@ export function handleFetchAnswerSteaming(
chunks: chunks,
token_limit: token_limit,
isNoneDoc: selectedDocs === null,
index: indx,
};
if (selectedDocs && 'id' in selectedDocs) {
payload.active_docs = selectedDocs.id as string;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/conversation/conversationModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ export interface RetrievalPayload {
chunks: string;
token_limit: number;
isNoneDoc: boolean;
index?: number;
}
Loading

0 comments on commit 8d8423b

Please sign in to comment.