Skip to content

Commit

Permalink
Add support for interrupting messages after they've been sent.
Browse files Browse the repository at this point in the history
  • Loading branch information
sabaimran committed Nov 13, 2024
1 parent d607ad7 commit 4a1b1e8
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 14 deletions.
35 changes: 34 additions & 1 deletion src/interface/web/app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface ChatBodyDataProps {
isMobileWidth?: boolean;
isLoggedIn: boolean;
setImages: (images: string[]) => void;
setTriggeredAbort: (triggeredAbort: boolean) => void;
}

function ChatBodyData(props: ChatBodyDataProps) {
Expand Down Expand Up @@ -160,6 +161,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
setUploadedFiles={props.setUploadedFiles}
ref={chatInputRef}
isResearchModeEnabled={isInResearchMode}
setTriggeredAbort={props.setTriggeredAbort}
/>
</div>
</>
Expand All @@ -178,6 +180,10 @@ export default function Chat() {
const [uploadedFiles, setUploadedFiles] = useState<AttachedFileText[] | undefined>(undefined);
const [images, setImages] = useState<string[]>([]);

const [abortMessageStreamController, setAbortMessageStreamController] =
useState<AbortController | null>(null);
const [triggeredAbort, setTriggeredAbort] = useState(false);

const locationData = useIPLocationData() || {
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
};
Expand All @@ -202,6 +208,15 @@ export default function Chat() {
welcomeConsole();
}, []);

useEffect(() => {
if (triggeredAbort) {
abortMessageStreamController?.abort();
handleAbortedMessage();
setTriggeredAbort(false);
}
}),
[triggeredAbort];

useEffect(() => {
if (queryToProcess) {
const newStreamMessage: StreamMessage = {
Expand All @@ -218,6 +233,7 @@ export default function Chat() {
};
setMessages((prevMessages) => [...prevMessages, newStreamMessage]);
setProcessQuerySignal(true);
setAbortMessageStreamController(new AbortController());
}
}, [queryToProcess]);

Expand Down Expand Up @@ -283,6 +299,17 @@ export default function Chat() {
}
}

function handleAbortedMessage() {
const currentMessage = messages.find((message) => !message.completed);
if (!currentMessage) return;

currentMessage.rawResponse = `I've stopped processing this message. If you'd like to continue, please send another message.`;
currentMessage.completed = true;
setMessages([...messages]);
setQueryToProcess("");
setProcessQuerySignal(false);
}

async function chat() {
localStorage.removeItem("message");
if (!queryToProcess || !conversationId) return;
Expand All @@ -308,6 +335,7 @@ export default function Chat() {
"Content-Type": "application/json",
},
body: JSON.stringify(chatAPIBody),
signal: abortMessageStreamController?.signal,
});

try {
Expand All @@ -321,14 +349,18 @@ export default function Chat() {

// Render error message as current message
const errorMessage = (err as Error).message;
const errorName = (err as Error).name;
if (errorMessage.includes("Error in input stream"))
currentMessage.rawResponse = `Woops! The connection broke while I was writing my thoughts down. Maybe try again in a bit or dislike this message if the issue persists?`;
else if (response.status === 429) {
"detail" in apiError
? (currentMessage.rawResponse = `${apiError.detail}`)
: (currentMessage.rawResponse = `I'm a bit overwhelmed at the moment. Could you try again in a bit or dislike this message if the issue persists?`);
} else
} else if (errorName === "AbortError") {
currentMessage.rawResponse = `I've stopped processing this message. If you'd like to continue, please send the message again.`;
} else {
currentMessage.rawResponse = `Umm, not sure what just happened. I see this error message: ${errorMessage}. Could you try again or dislike this message if the issue persists?`;
}

// Complete message streaming teardown properly
currentMessage.completed = true;
Expand Down Expand Up @@ -388,6 +420,7 @@ export default function Chat() {
isMobileWidth={isMobileWidth}
onConversationIdChange={handleConversationIdChange}
setImages={setImages}
setTriggeredAbort={setTriggeredAbort}
/>
</Suspense>
</div>
Expand Down
39 changes: 26 additions & 13 deletions src/interface/web/app/components/chatInputArea/chatInputArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ interface ChatInputProps {
isLoggedIn: boolean;
agentColor?: string;
isResearchModeEnabled?: boolean;
setTriggeredAbort: (value: boolean) => void;
}

export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((props, ref) => {
Expand Down Expand Up @@ -678,28 +679,40 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="default"
className={`${!message || recording || "hidden"} ${props.agentColor ? convertToBGClass(props.agentColor) : "bg-orange-300 hover:bg-orange-500"} rounded-full p-1 m-2 h-auto text-3xl transition transform md:hover:-translate-y-1`}
onClick={() => {
setMessage("Listening...");
setRecording(!recording);
}}
disabled={props.sendDisabled}
>
<Microphone weight="fill" className="w-6 h-6" />
</Button>
{props.sendDisabled ? (
<Button
variant="default"
className={`${props.agentColor ? convertToBGClass(props.agentColor) : "bg-orange-300 hover:bg-orange-500"} rounded-full p-1 m-2 h-auto text-3xl transition transform md:hover:-translate-y-1`}
onClick={() => {
props.setTriggeredAbort(true);
}}
>
<Stop weight="fill" className="w-6 h-6" />
</Button>
) : (
<Button
variant="default"
className={`${!message || recording || "hidden"} ${props.agentColor ? convertToBGClass(props.agentColor) : "bg-orange-300 hover:bg-orange-500"} rounded-full p-1 m-2 h-auto text-3xl transition transform md:hover:-translate-y-1`}
onClick={() => {
setMessage("Listening...");
setRecording(!recording);
}}
>
<Microphone weight="fill" className="w-6 h-6" />
</Button>
)}
</TooltipTrigger>
<TooltipContent>
Click to transcribe your message with voice.
{props.sendDisabled
? "Click here to stop the streaming."
: "Click to transcribe your message with voice."}
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
<Button
className={`${(!message || recording) && "hidden"} ${props.agentColor ? convertToBGClass(props.agentColor) : "bg-orange-300 hover:bg-orange-500"} rounded-full p-1 m-2 h-auto text-3xl transition transform md:hover:-translate-y-1`}
onClick={onSendMessage}
disabled={props.sendDisabled}
>
<ArrowUp className="w-6 h-6" weight="bold" />
</Button>
Expand Down
2 changes: 2 additions & 0 deletions src/interface/web/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
setUploadedFiles={props.setUploadedFiles}
agentColor={agents.find((agent) => agent.slug === selectedAgent)?.color}
ref={chatInputRef}
setTriggeredAbort={() => {}}
/>
</div>
)}
Expand Down Expand Up @@ -394,6 +395,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
setUploadedFiles={props.setUploadedFiles}
agentColor={agents.find((agent) => agent.slug === selectedAgent)?.color}
ref={chatInputRef}
setTriggeredAbort={() => {}}
/>
</div>
</>
Expand Down
1 change: 1 addition & 0 deletions src/interface/web/app/share/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
agentColor={agentMetadata?.color}
isMobileWidth={props.isMobileWidth}
setUploadedFiles={props.setUploadedFiles}
setTriggeredAbort={() => {}}
ref={chatInputRef}
/>
</div>
Expand Down

0 comments on commit 4a1b1e8

Please sign in to comment.