112 lines
No EOL
3.3 KiB
TypeScript
112 lines
No EOL
3.3 KiB
TypeScript
"use client";
|
|
import React, { createContext, useContext, useState, useEffect } from 'react';
|
|
import { User, ChatInstance } from '../types';
|
|
|
|
interface ChatContextType {
|
|
line: any;
|
|
user: User;
|
|
instance: ChatInstance | null;
|
|
sendActivity: (activity: any) => Promise<void>;
|
|
selectedVoice: any;
|
|
setVoice: (voice: any) => void;
|
|
}
|
|
|
|
const ChatContext = createContext<ChatContextType | undefined>(undefined);
|
|
|
|
// Unified API caller that works in both environments
|
|
async function apiFetch(endpoint: string, options?: RequestInit) {
|
|
const baseUrl = 'http://localhost:4242/'; //typeof window !== 'undefined' ? window.location.origin : '';
|
|
|
|
if (typeof window !== 'undefined' && '__TAURI__' in window) {
|
|
// Tauri environment - use HTTP module for better security
|
|
const { http } = await import('@tauri-apps/api');
|
|
return http.fetch(`${baseUrl}${endpoint}`, options);
|
|
}
|
|
|
|
// Web environment - standard fetch
|
|
return fetch(`${baseUrl}${endpoint}`, options);
|
|
}
|
|
|
|
export function ChatProvider({ children }: { children: React.ReactNode }) {
|
|
const [line, setLine] = useState<any>(null);
|
|
const [instance, setInstance] = useState<ChatInstance | null>(null);
|
|
const [selectedVoice, setSelectedVoice] = useState(null);
|
|
const [user] = useState<User>({
|
|
id: `user_${Math.random().toString(36).slice(2)}`,
|
|
name: 'You'
|
|
});
|
|
|
|
useEffect(() => {
|
|
const initializeChat = async () => {
|
|
try {
|
|
const botId = 'doula'; // window.location.pathname.split('/')[1] || 'default';
|
|
|
|
// Get instance from REST API
|
|
const response = await apiFetch(`/instances/${botId}`);
|
|
if (!response.ok) throw new Error('Failed to get chat instance');
|
|
const instanceData = await response.json();
|
|
setInstance(instanceData);
|
|
|
|
// Initialize chat service
|
|
const chatService = {
|
|
activity$: { subscribe: () => {} },
|
|
postActivity: (activity: any) => ({
|
|
subscribe: (observer: any) => {
|
|
// Handle real-time updates if needed
|
|
return { unsubscribe: () => {} };
|
|
}
|
|
})
|
|
};
|
|
setLine(chatService);
|
|
} catch (error) {
|
|
console.error('Failed to initialize chat:', error);
|
|
}
|
|
};
|
|
|
|
initializeChat();
|
|
}, []);
|
|
|
|
const sendActivity = async (activity: any) => {
|
|
try {
|
|
const fullActivity = {
|
|
...activity,
|
|
from: user,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
// Send activity via REST API
|
|
const response = await apiFetch('/activities', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(fullActivity)
|
|
});
|
|
|
|
if (!response.ok) throw new Error('Failed to send activity');
|
|
|
|
// Notify local chat service
|
|
line?.postActivity(fullActivity).subscribe();
|
|
} catch (error) {
|
|
console.error('Failed to send activity:', error);
|
|
}
|
|
};
|
|
|
|
const setVoice = (voice: any) => {
|
|
setSelectedVoice(voice);
|
|
};
|
|
|
|
return (
|
|
<ChatContext.Provider value={{ line, user, instance, sendActivity, selectedVoice, setVoice }}>
|
|
{children}
|
|
</ChatContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useChat() {
|
|
const context = useContext(ChatContext);
|
|
if (!context) {
|
|
throw new Error('useChat must be used within ChatProvider');
|
|
}
|
|
return context;
|
|
} |