Spaces:
Paused
Paused
Hemang Thakur
commited on
Commit
·
a7de061
1
Parent(s):
661a2f2
added auto-scroll to the bottom
Browse files
frontend/src/Components/AiPage.css
CHANGED
|
@@ -288,6 +288,11 @@ button.send-btn.stop-btn:hover {
|
|
| 288 |
/* Chat container */
|
| 289 |
.chat-container {
|
| 290 |
flex-grow: 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 291 |
margin-bottom: 40rem;
|
| 292 |
}
|
| 293 |
|
|
@@ -304,4 +309,4 @@ button.send-btn.stop-btn:hover {
|
|
| 304 |
margin: 0;
|
| 305 |
padding: 1rem;
|
| 306 |
}
|
| 307 |
-
}
|
|
|
|
| 288 |
/* Chat container */
|
| 289 |
.chat-container {
|
| 290 |
flex-grow: 1;
|
| 291 |
+
margin-bottom: 9rem;
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
/* When processing a new prompt */
|
| 295 |
+
.chat-container.processing {
|
| 296 |
margin-bottom: 40rem;
|
| 297 |
}
|
| 298 |
|
|
|
|
| 309 |
margin: 0;
|
| 310 |
padding: 1rem;
|
| 311 |
}
|
| 312 |
+
}
|
frontend/src/Components/AiPage.js
CHANGED
|
@@ -45,6 +45,9 @@ function AiPage() {
|
|
| 45 |
const [activeBlockId, setActiveBlockId] = useState(null);
|
| 46 |
const activeEventSourceRef = useRef(null);
|
| 47 |
|
|
|
|
|
|
|
|
|
|
| 48 |
// Snackbar state
|
| 49 |
const [snackbar, setSnackbar] = useState({
|
| 50 |
open: false,
|
|
@@ -71,6 +74,24 @@ function AiPage() {
|
|
| 71 |
const tokenExpiryTimersRef = useRef({});
|
| 72 |
const notificationIdsRef = useRef({});
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
// Function to open the snackbar
|
| 75 |
const openSnackbar = useCallback((message, severity = "success", duration) => {
|
| 76 |
let finalDuration;
|
|
@@ -215,14 +236,6 @@ function AiPage() {
|
|
| 215 |
return Date.now() < expiryTime;
|
| 216 |
};
|
| 217 |
|
| 218 |
-
// Function to get valid token
|
| 219 |
-
const getValidToken = (provider) => {
|
| 220 |
-
if (isTokenValid(provider)) {
|
| 221 |
-
return sessionStorage.getItem(`${provider}_token`);
|
| 222 |
-
}
|
| 223 |
-
return null;
|
| 224 |
-
};
|
| 225 |
-
|
| 226 |
// Function to get provider icon
|
| 227 |
const getProviderIcon = useCallback((provider) => {
|
| 228 |
switch (provider.toLowerCase()) {
|
|
@@ -504,6 +517,11 @@ function AiPage() {
|
|
| 504 |
// Create a new chat block and initiate the SSE
|
| 505 |
const handleSend = () => {
|
| 506 |
if (!searchText.trim()) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
const blockId = new Date().getTime();
|
| 508 |
setActiveBlockId(blockId);
|
| 509 |
setIsProcessing(true);
|
|
@@ -537,6 +555,13 @@ function AiPage() {
|
|
| 537 |
}
|
| 538 |
};
|
| 539 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 540 |
// Stop the user request and close the active SSE connection
|
| 541 |
const handleStop = async () => {
|
| 542 |
// Close the active SSE connection if it exists
|
|
@@ -903,7 +928,7 @@ function AiPage() {
|
|
| 903 |
<main className="main-content">
|
| 904 |
{showChatWindow ? (
|
| 905 |
<>
|
| 906 |
-
<div className=
|
| 907 |
{chatBlocks.map((block) => (
|
| 908 |
<ChatWindow
|
| 909 |
key={block.id}
|
|
|
|
| 45 |
const [activeBlockId, setActiveBlockId] = useState(null);
|
| 46 |
const activeEventSourceRef = useRef(null);
|
| 47 |
|
| 48 |
+
// State to track if we should auto-scroll to the bottom
|
| 49 |
+
const [autoScrollEnabled, setAutoScrollEnabled] = useState(false);
|
| 50 |
+
|
| 51 |
// Snackbar state
|
| 52 |
const [snackbar, setSnackbar] = useState({
|
| 53 |
open: false,
|
|
|
|
| 74 |
const tokenExpiryTimersRef = useRef({});
|
| 75 |
const notificationIdsRef = useRef({});
|
| 76 |
|
| 77 |
+
// Function to check if we are near the bottom of the page
|
| 78 |
+
const checkIfNearBottom = (threshold = 400) => {
|
| 79 |
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
| 80 |
+
const scrollHeight = document.documentElement.scrollHeight;
|
| 81 |
+
const clientHeight = window.innerHeight;
|
| 82 |
+
const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
|
| 83 |
+
|
| 84 |
+
return distanceFromBottom <= threshold;
|
| 85 |
+
};
|
| 86 |
+
|
| 87 |
+
// Helper to scroll to bottom
|
| 88 |
+
const scrollToBottom = (smooth = true) => {
|
| 89 |
+
window.scrollTo({
|
| 90 |
+
top: document.documentElement.scrollHeight,
|
| 91 |
+
behavior: smooth ? 'smooth' : 'auto'
|
| 92 |
+
});
|
| 93 |
+
};
|
| 94 |
+
|
| 95 |
// Function to open the snackbar
|
| 96 |
const openSnackbar = useCallback((message, severity = "success", duration) => {
|
| 97 |
let finalDuration;
|
|
|
|
| 236 |
return Date.now() < expiryTime;
|
| 237 |
};
|
| 238 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
// Function to get provider icon
|
| 240 |
const getProviderIcon = useCallback((provider) => {
|
| 241 |
switch (provider.toLowerCase()) {
|
|
|
|
| 517 |
// Create a new chat block and initiate the SSE
|
| 518 |
const handleSend = () => {
|
| 519 |
if (!searchText.trim()) return;
|
| 520 |
+
|
| 521 |
+
// Check if user is near bottom before adding new block
|
| 522 |
+
const shouldScroll = checkIfNearBottom(1000); // 1000px threshold
|
| 523 |
+
setAutoScrollEnabled(shouldScroll);
|
| 524 |
+
|
| 525 |
const blockId = new Date().getTime();
|
| 526 |
setActiveBlockId(blockId);
|
| 527 |
setIsProcessing(true);
|
|
|
|
| 555 |
}
|
| 556 |
};
|
| 557 |
|
| 558 |
+
// Auto-scroll when chat block is added
|
| 559 |
+
useEffect(() => {
|
| 560 |
+
if (autoScrollEnabled && isProcessing) {
|
| 561 |
+
scrollToBottom();
|
| 562 |
+
}
|
| 563 |
+
}, [isProcessing, autoScrollEnabled]);
|
| 564 |
+
|
| 565 |
// Stop the user request and close the active SSE connection
|
| 566 |
const handleStop = async () => {
|
| 567 |
// Close the active SSE connection if it exists
|
|
|
|
| 928 |
<main className="main-content">
|
| 929 |
{showChatWindow ? (
|
| 930 |
<>
|
| 931 |
+
<div className={`chat-container ${isProcessing ? 'processing' : ''}`}>
|
| 932 |
{chatBlocks.map((block) => (
|
| 933 |
<ChatWindow
|
| 934 |
key={block.id}
|
src/utils/api_key_manager.py
CHANGED
|
@@ -17,6 +17,9 @@ import asyncio
|
|
| 17 |
|
| 18 |
# Tell Pydantic to finish wiring up this dynamic model
|
| 19 |
ChatGoogleGenerativeAI.model_rebuild()
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
ModelProvider = Literal["openai", "anthropic", "google", "xai"]
|
| 22 |
|
|
|
|
| 17 |
|
| 18 |
# Tell Pydantic to finish wiring up this dynamic model
|
| 19 |
ChatGoogleGenerativeAI.model_rebuild()
|
| 20 |
+
ChatAnthropic.model_rebuild()
|
| 21 |
+
ChatOpenAI.model_rebuild()
|
| 22 |
+
ChatXAI.model_rebuild()
|
| 23 |
|
| 24 |
ModelProvider = Literal["openai", "anthropic", "google", "xai"]
|
| 25 |
|