Spaces:
Sleeping
Sleeping
| import { useState, useEffect, useRef } from 'react'; | |
| import { ApiResponse, ChatMessage, UserProfile } from '../../interface'; | |
| import { CHAT_ENDPOINT } from '../../endpoint'; | |
| export function useChatInterface(userProfile: UserProfile, isProfileComplete?: boolean) { | |
| const [chatHistory, setChatHistory] = useState<ChatMessage[]>([]); | |
| const [isLoading, setIsLoading] = useState(false); | |
| const [currentMessage, setCurrentMessage] = useState(''); | |
| const [showPlanRecs, setShowPlanRecs] = useState<boolean>(false); | |
| const chatEndRef = useRef<HTMLDivElement>(null); | |
| const inputRef = useRef<HTMLInputElement>(null); | |
| // threadId is generated once per chat session and persists for the hook's lifetime | |
| const [threadId] = useState(() => crypto.randomUUID()); | |
| useEffect(() => { | |
| chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }); | |
| // Focus input after chatHistory changes (i.e., after response is rendered) | |
| if (inputRef.current) { | |
| inputRef.current.focus(); | |
| } | |
| }, [chatHistory]); | |
| // Prevent double API call: only send initial chat message once when userProfile is complete | |
| const hasSentInitialMessage = useRef(false); | |
| useEffect(() => { | |
| // TODO: review this logic | |
| // Check if userProfile is complete before sending initial message | |
| const isValidProfile = !!userProfile && | |
| userProfile?.zip_code?.length && userProfile?.zip_code?.length > 0 && | |
| !!userProfile.age && userProfile.age > 0 && | |
| !!userProfile.gender && userProfile.gender.length > 0 && | |
| !!userProfile.household_size && | |
| !!userProfile.income && | |
| !!userProfile.employment_status && | |
| !!userProfile.citizenship; | |
| if (isValidProfile && !hasSentInitialMessage.current) { | |
| sendChatMessage('START_PROFILE_BUILDING', userProfile); | |
| hasSentInitialMessage.current = true; | |
| } | |
| }, [userProfile]); | |
| const sendChatMessage = async ( | |
| message: string, | |
| profileOverride?: UserProfile | |
| ) => { | |
| setIsLoading(true); | |
| try { | |
| const payload = { | |
| thread_id: threadId, | |
| user_profile: profileOverride ?? userProfile, | |
| message, | |
| is_profile_complete: isProfileComplete ?? false, | |
| conversation_history: chatHistory.map(m => `${m.role}: ${m.content}`) | |
| }; | |
| const response = await fetch(CHAT_ENDPOINT, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(payload) | |
| }); | |
| if (!response.ok) throw new Error('Failed to send message'); | |
| const data: ApiResponse = await response.json(); | |
| // Only append the agent's message to the existing chatHistory | |
| const agentMsgRaw = data.updated_history[data.updated_history.length - 1] || ''; | |
| const agentMsgContent = agentMsgRaw.replace(/^Agent:\s*/, ''); | |
| const agentMessage: ChatMessage = { | |
| role: 'agent', | |
| content: agentMsgContent, | |
| timestamp: Date.now(), | |
| plans: !showPlanRecs && data.plan_recommendations?.recommendations?.length && data.plan_recommendations?.recommendations?.length > 0 ? data.plan_recommendations.recommendations : undefined | |
| }; | |
| setChatHistory(prev => [...prev, agentMessage]); | |
| if (!showPlanRecs && data.plan_recommendations?.recommendations?.length && data.plan_recommendations?.recommendations?.length > 0) { | |
| setShowPlanRecs(true); | |
| } | |
| return data; | |
| } catch (error) { | |
| console.error('Error sending message:', error); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; | |
| const handleSendMessage = async () => { | |
| if (!currentMessage.trim()) return; | |
| // Add user message to chat immediately | |
| const userMessage: ChatMessage = { | |
| role: 'user', | |
| content: currentMessage, | |
| timestamp: Date.now() | |
| }; | |
| setChatHistory(prev => [...prev, userMessage]); | |
| const messageToSend = currentMessage; | |
| setCurrentMessage(''); | |
| await sendChatMessage(messageToSend); | |
| }; | |
| return { | |
| chatHistory, | |
| isLoading, | |
| currentMessage, | |
| setCurrentMessage, | |
| handleSendMessage, | |
| showPlanRecs, | |
| chatEndRef, | |
| inputRef, | |
| sendChatMessage | |
| }; | |
| } | |