update chat page to use a new filter for every conversation
This commit is contained in:
parent
230081e591
commit
15701f8b16
2 changed files with 1620 additions and 1558 deletions
|
|
@ -1,12 +1,11 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Loader2, Zap } from "lucide-react";
|
import { Loader2, Zap } from "lucide-react";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
||||||
import { ProtectedRoute } from "@/components/protected-route";
|
import { ProtectedRoute } from "@/components/protected-route";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { type EndpointType, useChat } from "@/contexts/chat-context";
|
import { type EndpointType, useChat } from "@/contexts/chat-context";
|
||||||
import { useKnowledgeFilter } from "@/contexts/knowledge-filter-context";
|
|
||||||
import { useTask } from "@/contexts/task-context";
|
import { useTask } from "@/contexts/task-context";
|
||||||
import { useChatStreaming } from "@/hooks/useChatStreaming";
|
import { useChatStreaming } from "@/hooks/useChatStreaming";
|
||||||
import { FILE_CONFIRMATION, FILES_REGEX } from "@/lib/constants";
|
import { FILE_CONFIRMATION, FILES_REGEX } from "@/lib/constants";
|
||||||
|
|
@ -40,6 +39,8 @@ function ChatPage() {
|
||||||
previousResponseIds,
|
previousResponseIds,
|
||||||
setPreviousResponseIds,
|
setPreviousResponseIds,
|
||||||
placeholderConversation,
|
placeholderConversation,
|
||||||
|
conversationFilter,
|
||||||
|
setConversationFilter,
|
||||||
} = useChat();
|
} = useChat();
|
||||||
const [messages, setMessages] = useState<Message[]>([
|
const [messages, setMessages] = useState<Message[]>([
|
||||||
{
|
{
|
||||||
|
|
@ -78,8 +79,20 @@ function ChatPage() {
|
||||||
|
|
||||||
const lastLoadedConversationRef = useRef<string | null>(null);
|
const lastLoadedConversationRef = useRef<string | null>(null);
|
||||||
const { addTask } = useTask();
|
const { addTask } = useTask();
|
||||||
const { selectedFilter, parsedFilterData, setSelectedFilter } =
|
|
||||||
useKnowledgeFilter();
|
// Use conversation-specific filter instead of global filter
|
||||||
|
const selectedFilter = conversationFilter;
|
||||||
|
|
||||||
|
// Parse the conversation filter data
|
||||||
|
const parsedFilterData = useMemo(() => {
|
||||||
|
if (!selectedFilter?.query_data) return null;
|
||||||
|
try {
|
||||||
|
return JSON.parse(selectedFilter.query_data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error parsing filter data:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, [selectedFilter]);
|
||||||
|
|
||||||
// Use the chat streaming hook
|
// Use the chat streaming hook
|
||||||
const apiEndpoint = endpoint === "chat" ? "/api/chat" : "/api/langflow";
|
const apiEndpoint = endpoint === "chat" ? "/api/chat" : "/api/langflow";
|
||||||
|
|
@ -323,7 +336,8 @@ function ChatPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFilterSelect = (filter: KnowledgeFilterData | null) => {
|
const handleFilterSelect = (filter: KnowledgeFilterData | null) => {
|
||||||
setSelectedFilter(filter);
|
// Update conversation-specific filter
|
||||||
|
setConversationFilter(filter);
|
||||||
setIsFilterDropdownOpen(false);
|
setIsFilterDropdownOpen(false);
|
||||||
setFilterSearchTerm("");
|
setFilterSearchTerm("");
|
||||||
setIsFilterHighlighted(false);
|
setIsFilterHighlighted(false);
|
||||||
|
|
@ -388,8 +402,7 @@ function ChatPage() {
|
||||||
// 2. It's different from the last loaded conversation AND
|
// 2. It's different from the last loaded conversation AND
|
||||||
// 3. User is not in the middle of an interaction
|
// 3. User is not in the middle of an interaction
|
||||||
if (
|
if (
|
||||||
conversationData &&
|
conversationData?.messages &&
|
||||||
conversationData.messages &&
|
|
||||||
lastLoadedConversationRef.current !== conversationData.response_id &&
|
lastLoadedConversationRef.current !== conversationData.response_id &&
|
||||||
!isUserInteracting &&
|
!isUserInteracting &&
|
||||||
!isForkingInProgress
|
!isForkingInProgress
|
||||||
|
|
@ -1021,7 +1034,7 @@ function ChatPage() {
|
||||||
|
|
||||||
if (isFilterHighlighted) {
|
if (isFilterHighlighted) {
|
||||||
// Second backspace - remove the filter
|
// Second backspace - remove the filter
|
||||||
setSelectedFilter(null);
|
setConversationFilter(null);
|
||||||
setIsFilterHighlighted(false);
|
setIsFilterHighlighted(false);
|
||||||
} else {
|
} else {
|
||||||
// First backspace - highlight the filter
|
// First backspace - highlight the filter
|
||||||
|
|
@ -1344,7 +1357,7 @@ function ChatPage() {
|
||||||
onAtClick={onAtClick}
|
onAtClick={onAtClick}
|
||||||
onFilePickerClick={handleFilePickerClick}
|
onFilePickerClick={handleFilePickerClick}
|
||||||
onFileSelected={setUploadedFile}
|
onFileSelected={setUploadedFile}
|
||||||
setSelectedFilter={setSelectedFilter}
|
setSelectedFilter={setConversationFilter}
|
||||||
setIsFilterHighlighted={setIsFilterHighlighted}
|
setIsFilterHighlighted={setIsFilterHighlighted}
|
||||||
setIsFilterDropdownOpen={setIsFilterDropdownOpen}
|
setIsFilterDropdownOpen={setIsFilterDropdownOpen}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createContext,
|
createContext,
|
||||||
ReactNode,
|
type ReactNode,
|
||||||
useCallback,
|
useCallback,
|
||||||
useContext,
|
useContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
|
|
@ -25,11 +25,22 @@ interface ConversationMessage {
|
||||||
response_id?: string;
|
response_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface KnowledgeFilter {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
query_data: string;
|
||||||
|
owner: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface ConversationData {
|
interface ConversationData {
|
||||||
messages: ConversationMessage[];
|
messages: ConversationMessage[];
|
||||||
endpoint: EndpointType;
|
endpoint: EndpointType;
|
||||||
response_id: string;
|
response_id: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
filter?: KnowledgeFilter | null;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +76,8 @@ interface ChatContextType {
|
||||||
setPlaceholderConversation: (conversation: ConversationData | null) => void;
|
setPlaceholderConversation: (conversation: ConversationData | null) => void;
|
||||||
conversationLoaded: boolean;
|
conversationLoaded: boolean;
|
||||||
setConversationLoaded: (loaded: boolean) => void;
|
setConversationLoaded: (loaded: boolean) => void;
|
||||||
|
conversationFilter: KnowledgeFilter | null;
|
||||||
|
setConversationFilter: (filter: KnowledgeFilter | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatContext = createContext<ChatContextType | undefined>(undefined);
|
const ChatContext = createContext<ChatContextType | undefined>(undefined);
|
||||||
|
|
@ -92,6 +105,8 @@ export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
const [placeholderConversation, setPlaceholderConversation] =
|
const [placeholderConversation, setPlaceholderConversation] =
|
||||||
useState<ConversationData | null>(null);
|
useState<ConversationData | null>(null);
|
||||||
const [conversationLoaded, setConversationLoaded] = useState(false);
|
const [conversationLoaded, setConversationLoaded] = useState(false);
|
||||||
|
const [conversationFilter, setConversationFilterState] =
|
||||||
|
useState<KnowledgeFilter | null>(null);
|
||||||
|
|
||||||
// Debounce refresh requests to prevent excessive reloads
|
// Debounce refresh requests to prevent excessive reloads
|
||||||
const refreshTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
const refreshTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
@ -129,17 +144,31 @@ export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
setRefreshTriggerSilent((prev) => prev + 1);
|
setRefreshTriggerSilent((prev) => prev + 1);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadConversation = useCallback((conversation: ConversationData) => {
|
const loadConversation = useCallback(
|
||||||
|
(conversation: ConversationData) => {
|
||||||
setCurrentConversationId(conversation.response_id);
|
setCurrentConversationId(conversation.response_id);
|
||||||
setEndpoint(conversation.endpoint);
|
setEndpoint(conversation.endpoint);
|
||||||
// Store the full conversation data for the chat page to use
|
// Store the full conversation data for the chat page to use
|
||||||
setConversationData(conversation);
|
setConversationData(conversation);
|
||||||
|
// Load the filter if one exists for this conversation
|
||||||
|
// Only update the filter if this is a different conversation (to preserve user's filter selection)
|
||||||
|
setConversationFilterState((currentFilter) => {
|
||||||
|
// If we're loading a different conversation, load its filter
|
||||||
|
// Otherwise keep the current filter (don't reset it when conversation refreshes)
|
||||||
|
const isDifferentConversation =
|
||||||
|
conversation.response_id !== conversationData?.response_id;
|
||||||
|
return isDifferentConversation
|
||||||
|
? conversation.filter || null
|
||||||
|
: currentFilter;
|
||||||
|
});
|
||||||
// Clear placeholder when loading a real conversation
|
// Clear placeholder when loading a real conversation
|
||||||
setPlaceholderConversation(null);
|
setPlaceholderConversation(null);
|
||||||
setConversationLoaded(true);
|
setConversationLoaded(true);
|
||||||
// Clear conversation docs to prevent duplicates when switching conversations
|
// Clear conversation docs to prevent duplicates when switching conversations
|
||||||
setConversationDocs([]);
|
setConversationDocs([]);
|
||||||
}, []);
|
},
|
||||||
|
[conversationData?.response_id],
|
||||||
|
);
|
||||||
|
|
||||||
const startNewConversation = useCallback(() => {
|
const startNewConversation = useCallback(() => {
|
||||||
// Clear current conversation data and reset state
|
// Clear current conversation data and reset state
|
||||||
|
|
@ -148,6 +177,8 @@ export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
setConversationData(null);
|
setConversationData(null);
|
||||||
setConversationDocs([]);
|
setConversationDocs([]);
|
||||||
setConversationLoaded(false);
|
setConversationLoaded(false);
|
||||||
|
// Clear the filter when starting a new conversation
|
||||||
|
setConversationFilterState(null);
|
||||||
|
|
||||||
// Create a temporary placeholder conversation to show in sidebar
|
// Create a temporary placeholder conversation to show in sidebar
|
||||||
const placeholderConversation: ConversationData = {
|
const placeholderConversation: ConversationData = {
|
||||||
|
|
@ -198,6 +229,21 @@ export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
[endpoint],
|
[endpoint],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setConversationFilter = useCallback(
|
||||||
|
(filter: KnowledgeFilter | null) => {
|
||||||
|
setConversationFilterState(filter);
|
||||||
|
// Update the conversation data to include the filter
|
||||||
|
setConversationData((prev) => {
|
||||||
|
if (!prev) return prev;
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
filter,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const value = useMemo<ChatContextType>(
|
const value = useMemo<ChatContextType>(
|
||||||
() => ({
|
() => ({
|
||||||
endpoint,
|
endpoint,
|
||||||
|
|
@ -221,6 +267,8 @@ export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
setPlaceholderConversation,
|
setPlaceholderConversation,
|
||||||
conversationLoaded,
|
conversationLoaded,
|
||||||
setConversationLoaded,
|
setConversationLoaded,
|
||||||
|
conversationFilter,
|
||||||
|
setConversationFilter,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
endpoint,
|
endpoint,
|
||||||
|
|
@ -239,7 +287,8 @@ export function ChatProvider({ children }: ChatProviderProps) {
|
||||||
clearConversationDocs,
|
clearConversationDocs,
|
||||||
placeholderConversation,
|
placeholderConversation,
|
||||||
conversationLoaded,
|
conversationLoaded,
|
||||||
setConversationLoaded,
|
conversationFilter,
|
||||||
|
setConversationFilter,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue