mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import { ChatMessage } from '@/types.ts';
|
|
import { useTranslation } from '@/hooks/useI18n.tsx';
|
|
import { sendChatMessage } from '@/services/chat-api.ts';
|
|
|
|
const CHAT_HISTORY_KEY = 'chat-history';
|
|
|
|
export const useChat = () => {
|
|
const { t } = useTranslation();
|
|
const geminiSystemInstruction = t('gemini.chatSystemInstruction');
|
|
|
|
const initialMessage: ChatMessage = useMemo(
|
|
() => ({
|
|
id: 'init',
|
|
role: 'model',
|
|
text: t('chatbot.initialMessage'),
|
|
}),
|
|
[t]
|
|
);
|
|
|
|
const [messages, setMessages] = useState<ChatMessage[]>(() => {
|
|
try {
|
|
const storedMessages = window.localStorage.getItem(CHAT_HISTORY_KEY);
|
|
if (storedMessages && JSON.parse(storedMessages).length > 0) {
|
|
return JSON.parse(storedMessages);
|
|
}
|
|
return [initialMessage];
|
|
} catch (error) {
|
|
console.error('Failed to load chat history from localStorage', error);
|
|
return [initialMessage];
|
|
}
|
|
});
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
try {
|
|
window.localStorage.setItem(CHAT_HISTORY_KEY, JSON.stringify(messages));
|
|
} catch (error) {
|
|
console.error('Failed to save chat history to localStorage', error);
|
|
}
|
|
}, [messages]);
|
|
|
|
const sendMessage = useCallback(
|
|
async (payload: { text: string; imageUrl?: string }) => {
|
|
if (!payload.text.trim() && !payload.imageUrl) return;
|
|
|
|
const userMessage: ChatMessage = {
|
|
id: `user-${Date.now()}`,
|
|
role: 'user',
|
|
text: payload.text,
|
|
imageUrl: payload.imageUrl,
|
|
};
|
|
|
|
const modelMessageId = `model-${Date.now()}`;
|
|
const placeholderModelMessage: ChatMessage = {
|
|
id: modelMessageId,
|
|
role: 'model',
|
|
text: '',
|
|
isLoading: true,
|
|
};
|
|
setMessages((prev) => [...prev, userMessage, placeholderModelMessage]);
|
|
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
// Build message with image if provided
|
|
const messageText = payload.imageUrl ? `${payload.text}\n[Image attached]` : payload.text;
|
|
|
|
const response = await sendChatMessage({
|
|
message: messageText,
|
|
system_instruction: geminiSystemInstruction,
|
|
});
|
|
|
|
setMessages((prev) =>
|
|
prev.map((msg) => (msg.id === modelMessageId ? { ...msg, text: response } : msg))
|
|
);
|
|
} catch (e) {
|
|
const errorMessage = e instanceof Error ? e.message : 'An unknown error occurred';
|
|
setError(errorMessage);
|
|
const errorResponseMessage: ChatMessage = {
|
|
id: `model-error-${Date.now()}`,
|
|
role: 'model',
|
|
text: t('chatbot.errorMessage'),
|
|
};
|
|
setMessages((prev) => [...prev.slice(0, -1), errorResponseMessage]);
|
|
} finally {
|
|
setIsLoading(false);
|
|
setMessages((prev) =>
|
|
prev.map((msg) => (msg.id === modelMessageId ? { ...msg, isLoading: false } : msg))
|
|
);
|
|
}
|
|
},
|
|
[geminiSystemInstruction, t]
|
|
);
|
|
|
|
const clearChat = useCallback(() => {
|
|
setMessages([initialMessage]);
|
|
}, [initialMessage]);
|
|
|
|
return { messages, isLoading, error, sendMessage, clearChat };
|
|
};
|