|
|
import React, { createContext, useContext, useReducer } from 'react'; |
|
|
import apiService from '../utils/apiService'; |
|
|
|
|
|
|
|
|
const ChatbotContext = createContext(); |
|
|
|
|
|
|
|
|
const initialState = { |
|
|
messages: [ |
|
|
{ id: 1, text: "Hello! I'm your AI assistant for the Physical AI & Humanoid Robotics book. Ask me anything about the content!", sender: 'bot' } |
|
|
], |
|
|
isLoading: false, |
|
|
error: null, |
|
|
conversationId: null |
|
|
}; |
|
|
|
|
|
|
|
|
const chatbotReducer = (state, action) => { |
|
|
switch (action.type) { |
|
|
case 'SET_LOADING': |
|
|
return { ...state, isLoading: action.payload }; |
|
|
|
|
|
case 'SET_ERROR': |
|
|
return { ...state, error: action.payload }; |
|
|
|
|
|
case 'ADD_MESSAGE': |
|
|
return { |
|
|
...state, |
|
|
messages: [...state.messages, action.payload], |
|
|
error: null |
|
|
}; |
|
|
|
|
|
case 'SET_CONVERSATION_ID': |
|
|
return { ...state, conversationId: action.payload }; |
|
|
|
|
|
case 'RESET_CHAT': |
|
|
return { |
|
|
...initialState, |
|
|
messages: [ |
|
|
{ id: 1, text: "Hello! I'm your AI assistant for the Physical AI & Humanoid Robotics book. Ask me anything about the content!", sender: 'bot' } |
|
|
] |
|
|
}; |
|
|
|
|
|
default: |
|
|
return state; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
export const ChatbotProvider = ({ children }) => { |
|
|
const [state, dispatch] = useReducer(chatbotReducer, initialState); |
|
|
|
|
|
|
|
|
const sendMessage = async (text) => { |
|
|
if (!text.trim()) return; |
|
|
|
|
|
|
|
|
const userMessage = { |
|
|
id: Date.now(), |
|
|
text: text, |
|
|
sender: 'user' |
|
|
}; |
|
|
|
|
|
dispatch({ type: 'ADD_MESSAGE', payload: userMessage }); |
|
|
dispatch({ type: 'SET_LOADING', payload: true }); |
|
|
dispatch({ type: 'SET_ERROR', payload: null }); |
|
|
|
|
|
try { |
|
|
|
|
|
const response = await apiService.chatbot.query({ |
|
|
query: text, |
|
|
conversation_id: state.conversationId || null |
|
|
}); |
|
|
|
|
|
|
|
|
const botMessage = { |
|
|
id: Date.now() + 1, |
|
|
text: response.response, |
|
|
sender: 'bot' |
|
|
}; |
|
|
|
|
|
dispatch({ type: 'ADD_MESSAGE', payload: botMessage }); |
|
|
|
|
|
|
|
|
if (!state.conversationId && response.conversation_id) { |
|
|
dispatch({ type: 'SET_CONVERSATION_ID', payload: response.conversation_id }); |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Error sending message:', error); |
|
|
dispatch({ |
|
|
type: 'SET_ERROR', |
|
|
payload: error.message || 'Failed to get response from chatbot' |
|
|
}); |
|
|
|
|
|
|
|
|
const errorMessage = { |
|
|
id: Date.now() + 1, |
|
|
text: "Sorry, I couldn't process your request at the moment. Please try again.", |
|
|
sender: 'bot' |
|
|
}; |
|
|
dispatch({ type: 'ADD_MESSAGE', payload: errorMessage }); |
|
|
} finally { |
|
|
dispatch({ type: 'SET_LOADING', payload: false }); |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
const resetChat = () => { |
|
|
dispatch({ type: 'RESET_CHAT' }); |
|
|
}; |
|
|
|
|
|
|
|
|
const value = { |
|
|
messages: state.messages, |
|
|
isLoading: state.isLoading, |
|
|
error: state.error, |
|
|
conversationId: state.conversationId, |
|
|
sendMessage, |
|
|
resetChat |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<ChatbotContext.Provider value={value}> |
|
|
{children} |
|
|
</ChatbotContext.Provider> |
|
|
); |
|
|
}; |
|
|
|
|
|
|
|
|
export const useChatbot = () => { |
|
|
const context = useContext(ChatbotContext); |
|
|
if (!context) { |
|
|
throw new Error('useChatbot must be used within a ChatbotProvider'); |
|
|
} |
|
|
return context; |
|
|
}; |