This commit is contained in:
phact 2025-08-22 03:22:00 -04:00
parent e11d631702
commit 97afd8f481
3 changed files with 84 additions and 35 deletions

View file

@ -4,15 +4,17 @@ import Link from "next/link"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { Library, MessageSquare, Settings2, Plus, FileText } from "lucide-react" import { Library, MessageSquare, Settings2, Plus, FileText } from "lucide-react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { useState, useEffect, useRef } from "react" import { useState, useEffect, useRef, useCallback } from "react"
import { useChat } from "@/contexts/chat-context" import { useChat } from "@/contexts/chat-context"
interface ChatConversation { import { EndpointType } from "@/contexts/chat-context"
interface RawConversation {
response_id: string response_id: string
title: string title: string
endpoint: 'chat' | 'langflow' endpoint: string
messages: Array<{ messages: Array<{
role: 'user' | 'assistant' role: string
content: string content: string
timestamp?: string timestamp?: string
response_id?: string response_id?: string
@ -21,6 +23,24 @@ interface ChatConversation {
last_activity?: string last_activity?: string
previous_response_id?: string previous_response_id?: string
total_messages: number total_messages: number
[key: string]: unknown
}
interface ChatConversation {
response_id: string
title: string
endpoint: EndpointType
messages: Array<{
role: string
content: string
timestamp?: string
response_id?: string
}>
created_at?: string
last_activity?: string
previous_response_id?: string
total_messages: number
[key: string]: unknown
} }
@ -128,14 +148,7 @@ export function Navigation() {
const isOnChatPage = pathname === "/" || pathname === "/chat" const isOnChatPage = pathname === "/" || pathname === "/chat"
// Fetch chat conversations when on chat page, endpoint changes, or refresh is triggered const fetchConversations = useCallback(async () => {
useEffect(() => {
if (isOnChatPage) {
fetchConversations()
}
}, [isOnChatPage, endpoint, refreshTrigger])
const fetchConversations = async () => {
setLoadingConversations(true) setLoadingConversations(true)
try { try {
// Fetch from the selected endpoint only // Fetch from the selected endpoint only
@ -144,7 +157,13 @@ export function Navigation() {
const response = await fetch(apiEndpoint) const response = await fetch(apiEndpoint)
if (response.ok) { if (response.ok) {
const history = await response.json() const history = await response.json()
const conversations = history.conversations || [] const rawConversations = history.conversations || []
// Cast conversations to proper type and ensure endpoint is correct
const conversations: ChatConversation[] = rawConversations.map((conv: RawConversation) => ({
...conv,
endpoint: conv.endpoint as EndpointType
}))
// Sort conversations by last activity (most recent first) // Sort conversations by last activity (most recent first)
conversations.sort((a: ChatConversation, b: ChatConversation) => { conversations.sort((a: ChatConversation, b: ChatConversation) => {
@ -166,7 +185,14 @@ export function Navigation() {
} finally { } finally {
setLoadingConversations(false) setLoadingConversations(false)
} }
} }, [endpoint])
// Fetch chat conversations when on chat page, endpoint changes, or refresh is triggered
useEffect(() => {
if (isOnChatPage) {
fetchConversations()
}
}, [isOnChatPage, endpoint, refreshTrigger, fetchConversations])
return ( return (
<div className="space-y-4 py-4 flex flex-col h-full bg-background"> <div className="space-y-4 py-4 flex flex-col h-full bg-background">

View file

@ -70,7 +70,7 @@ interface RequestBody {
function ChatPage() { function ChatPage() {
const isDebugMode = process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_OPENRAG_DEBUG === 'true' const isDebugMode = process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_OPENRAG_DEBUG === 'true'
const { user } = useAuth() const { user } = useAuth()
const { endpoint, setEndpoint, refreshConversations, currentConversationId, conversationData, setCurrentConversationId, addConversationDoc, startNewConversation } = useChat() const { endpoint, setEndpoint, currentConversationId, conversationData, setCurrentConversationId, addConversationDoc, forkFromResponse } = useChat()
const [messages, setMessages] = useState<Message[]>([ const [messages, setMessages] = useState<Message[]>([
{ {
role: "assistant", role: "assistant",
@ -370,8 +370,13 @@ function ChatPage() {
if (conversationData && conversationData.messages) { if (conversationData && conversationData.messages) {
console.log("Loading conversation with", conversationData.messages.length, "messages") console.log("Loading conversation with", conversationData.messages.length, "messages")
// Convert backend message format to frontend Message interface // Convert backend message format to frontend Message interface
const convertedMessages: Message[] = conversationData.messages.map((msg: any) => ({ const convertedMessages: Message[] = conversationData.messages.map((msg: {
role: msg.role, role: string;
content: string;
timestamp?: string;
response_id?: string;
}) => ({
role: msg.role as "user" | "assistant",
content: msg.content, content: msg.content,
timestamp: new Date(msg.timestamp || new Date()), timestamp: new Date(msg.timestamp || new Date()),
// Add any other necessary properties // Add any other necessary properties
@ -1097,19 +1102,23 @@ function ChatPage() {
// This means we're continuing the conversation thread from that point // This means we're continuing the conversation thread from that point
const responseIdToForkFrom = currentConversationId || previousResponseIds[endpoint] const responseIdToForkFrom = currentConversationId || previousResponseIds[endpoint]
// Create a new conversation by clearing the current conversation ID // Create a new conversation by properly forking
// but keeping the messages truncated to the fork point
setMessages(messagesToKeep) setMessages(messagesToKeep)
setCurrentConversationId(null) // This creates a new conversation thread
// We'll handle clearing conversation data differently // Use the chat context's fork method which handles creating a new conversation properly
if (forkFromResponse) {
// Set the response_id we want to continue from as the previous response ID forkFromResponse(responseIdToForkFrom || '')
// This tells the backend to continue the conversation from this point } else {
setPreviousResponseIds(prev => ({ // Fallback to manual approach
...prev, setCurrentConversationId(null) // This creates a new conversation thread
[endpoint]: responseIdToForkFrom
})) // Set the response_id we want to continue from as the previous response ID
// This tells the backend to continue the conversation from this point
setPreviousResponseIds(prev => ({
...prev,
[endpoint]: responseIdToForkFrom
}))
}
console.log("Forked conversation with", messagesToKeep.length, "messages") console.log("Forked conversation with", messagesToKeep.length, "messages")

View file

@ -9,6 +9,20 @@ interface ConversationDocument {
uploadTime: Date uploadTime: Date
} }
interface ConversationMessage {
role: string
content: string
timestamp?: string
response_id?: string
}
interface ConversationData {
messages: ConversationMessage[]
endpoint: EndpointType
response_id: string
[key: string]: unknown
}
interface ChatContextType { interface ChatContextType {
endpoint: EndpointType endpoint: EndpointType
setEndpoint: (endpoint: EndpointType) => void setEndpoint: (endpoint: EndpointType) => void
@ -21,10 +35,10 @@ interface ChatContextType {
setPreviousResponseIds: (ids: { chat: string | null; langflow: string | null }) => void setPreviousResponseIds: (ids: { chat: string | null; langflow: string | null }) => void
refreshConversations: () => void refreshConversations: () => void
refreshTrigger: number refreshTrigger: number
loadConversation: (conversation: any) => void loadConversation: (conversation: ConversationData) => void
startNewConversation: () => void startNewConversation: () => void
conversationData: any conversationData: ConversationData | null
forkFromResponse: (responseId: string, messagesToKeep: any[]) => void forkFromResponse: (responseId: string) => void
conversationDocs: ConversationDocument[] conversationDocs: ConversationDocument[]
addConversationDoc: (filename: string) => void addConversationDoc: (filename: string) => void
clearConversationDocs: () => void clearConversationDocs: () => void
@ -44,14 +58,14 @@ export function ChatProvider({ children }: ChatProviderProps) {
langflow: string | null langflow: string | null
}>({ chat: null, langflow: null }) }>({ chat: null, langflow: null })
const [refreshTrigger, setRefreshTrigger] = useState(0) const [refreshTrigger, setRefreshTrigger] = useState(0)
const [conversationData, setConversationData] = useState<any>(null) const [conversationData, setConversationData] = useState<ConversationData | null>(null)
const [conversationDocs, setConversationDocs] = useState<ConversationDocument[]>([]) const [conversationDocs, setConversationDocs] = useState<ConversationDocument[]>([])
const refreshConversations = () => { const refreshConversations = () => {
setRefreshTrigger(prev => prev + 1) setRefreshTrigger(prev => prev + 1)
} }
const loadConversation = (conversation: any) => { const loadConversation = (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
@ -74,10 +88,10 @@ export function ChatProvider({ children }: ChatProviderProps) {
setConversationDocs([]) setConversationDocs([])
} }
const forkFromResponse = (responseId: string, messagesToKeep: any[]) => { const forkFromResponse = (responseId: string) => {
// Start a new conversation with the messages up to the fork point // Start a new conversation with the messages up to the fork point
setCurrentConversationId(null) // Clear current conversation to indicate new conversation setCurrentConversationId(null) // Clear current conversation to indicate new conversation
// Don't clear conversation data - let the chat page manage the messages setConversationData(null) // Clear conversation data to prevent reloading
// Set the response ID that we're forking from as the previous response ID // Set the response ID that we're forking from as the previous response ID
setPreviousResponseIds(prev => ({ setPreviousResponseIds(prev => ({
...prev, ...prev,