File size: 4,099 Bytes
66f3298
 
 
 
 
 
 
 
 
 
ffa2991
66f3298
 
 
 
 
ffa2991
 
 
 
66f3298
 
ffa2991
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66f3298
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ffa2991
 
 
 
66f3298
ffa2991
66f3298
 
ffa2991
 
66f3298
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ffa2991
66f3298
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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
  };
}