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="chat-container">
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