mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-09-21 08:41:32 +00:00
feat(app): allow stopping requests
This commit is contained in:
@@ -50,6 +50,9 @@ const Chat = ({
|
||||
const messageEnd = useRef<HTMLDivElement | null>(null);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const SCROLL_THRESHOLD = 250; // pixels from bottom to consider "at bottom"
|
||||
const [currentMessageId, setCurrentMessageId] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
// Check if user is at bottom of page
|
||||
useEffect(() => {
|
||||
@@ -166,6 +169,33 @@ const Chat = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Track the last user messageId when loading starts
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
// Find the last user message
|
||||
const lastUserMsg = [...messages]
|
||||
.reverse()
|
||||
.find((m) => m.role === 'user');
|
||||
setCurrentMessageId(lastUserMsg?.messageId);
|
||||
} else {
|
||||
setCurrentMessageId(undefined);
|
||||
}
|
||||
}, [loading, messages]);
|
||||
|
||||
// Cancel handler
|
||||
const handleCancel = async () => {
|
||||
if (!currentMessageId) return;
|
||||
try {
|
||||
await fetch('/api/chat/cancel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ messageId: currentMessageId }),
|
||||
});
|
||||
} catch (e) {
|
||||
// Optionally handle error
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="space-y-6 pt-8 pb-48 sm:mx-4 md:mx-8">
|
||||
{messages.map((msg, i) => {
|
||||
@@ -234,6 +264,7 @@ const Chat = ({
|
||||
setOptimizationMode={setOptimizationMode}
|
||||
focusMode={focusMode}
|
||||
setFocusMode={setFocusMode}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
</div>
|
||||
<div ref={messageEnd} className="h-0" />
|
||||
|
@@ -67,6 +67,7 @@ const MessageBox = ({
|
||||
className="w-full p-3 text-lg bg-light-100 dark:bg-dark-100 rounded-lg border border-light-secondary dark:border-dark-secondary text-black dark:text-white focus:outline-none focus:border-[#24A0ED] transition duration-200 min-h-[120px] font-medium"
|
||||
value={editedContent}
|
||||
onChange={(e) => setEditedContent(e.target.value)}
|
||||
placeholder="Edit your message..."
|
||||
autoFocus
|
||||
/>
|
||||
<div className="flex flex-row space-x-2 mt-3 justify-end">
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ArrowRight, ArrowUp } from 'lucide-react';
|
||||
import { ArrowRight, ArrowUp, Square } from 'lucide-react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import TextareaAutosize from 'react-textarea-autosize';
|
||||
import { File } from './ChatWindow';
|
||||
@@ -19,6 +19,7 @@ const MessageInput = ({
|
||||
focusMode,
|
||||
setFocusMode,
|
||||
firstMessage,
|
||||
onCancel,
|
||||
}: {
|
||||
sendMessage: (message: string) => void;
|
||||
loading: boolean;
|
||||
@@ -31,6 +32,7 @@ const MessageInput = ({
|
||||
focusMode: string;
|
||||
setFocusMode: (mode: string) => void;
|
||||
firstMessage: boolean;
|
||||
onCancel?: () => void;
|
||||
}) => {
|
||||
const [message, setMessage] = useState('');
|
||||
const [selectedModel, setSelectedModel] = useState<{
|
||||
@@ -129,17 +131,33 @@ const MessageInput = ({
|
||||
optimizationMode={optimizationMode}
|
||||
setOptimizationMode={setOptimizationMode}
|
||||
/>
|
||||
<button
|
||||
disabled={message.trim().length === 0}
|
||||
className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 disabled:bg-[#e0e0dc] dark:disabled:bg-[#ececec21] hover:bg-opacity-85 transition duration-100 rounded-full p-2"
|
||||
type="submit"
|
||||
>
|
||||
{firstMessage ? (
|
||||
<ArrowRight className="bg-background" size={17} />
|
||||
) : (
|
||||
<ArrowUp className="bg-background" size={17} />
|
||||
)}
|
||||
</button>
|
||||
{loading ? (
|
||||
<button
|
||||
type="button"
|
||||
className="bg-red-700 text-white hover:bg-red-800 transition duration-100 rounded-full p-2 relative group"
|
||||
onClick={onCancel}
|
||||
aria-label="Cancel"
|
||||
>
|
||||
{loading && (
|
||||
<div className="absolute inset-0 rounded-full border-2 border-white/30 border-t-white animate-spin" />
|
||||
)}
|
||||
<span className="relative flex items-center justify-center w-[17px] h-[17px]">
|
||||
<Square size={17} className="text-white" />
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
disabled={message.trim().length === 0}
|
||||
className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 disabled:bg-[#e0e0dc] dark:disabled:bg-[#ececec21] hover:bg-opacity-85 transition duration-100 rounded-full p-2"
|
||||
type="submit"
|
||||
>
|
||||
{firstMessage ? (
|
||||
<ArrowRight className="bg-background" size={17} />
|
||||
) : (
|
||||
<ArrowUp className="bg-background" size={17} />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user