import { useState, useEffect } from "react"; import { ChatHeader } from "@/components/ChatHeader"; import { ChatMessage } from "./ChatMessage"; import { ChatInput } from "./ChatInput"; import { ChatSidebar } from "./ChatSidebar"; import { ChatWelcome } from "./ChatWelcome"; import { createWelcomeMessage, isWelcomeMessage, withoutWelcomeMessages, } from "./welcome-message"; import type { Message } from "./ChatView.types"; import { ScrollArea } from "@/components/ui/scroll-area"; import { chatService, ChatRecord, MessageRecord } from "@/services/chat"; import { useToast } from "@/hooks/use-toast"; import { getModelId } from "@/config/models"; // Texto padrão da personalidade (usado para novos chats) const DEFAULT_SYSTEM_PROMPT = "Você é um assistente útil e prestativo."; export const ChatView = () => { const { toast } = useToast(); const [isChatSidebarCollapsed, setIsChatSidebarCollapsed] = useState(false); const [selectedModel, setSelectedModel] = useState("GPT-4o"); // Inicia com "0" - será atualizado com o chat_id real após primeira resposta da API const [currentChatId, setCurrentChatId] = useState("0"); // Inicia com texto padrão - será atualizado ao carregar chat existente const [systemPrompt, setSystemPrompt] = useState(DEFAULT_SYSTEM_PROMPT); const [messages, setMessages] = useState([createWelcomeMessage()]); const [isLoading, setIsLoading] = useState(false); const [inputDraft, setInputDraft] = useState<{ text: string; at: number; } | null>(null); const handleSelectSuggestion = (prompt: string) => { setInputDraft({ text: prompt, at: Date.now() }); }; // NOTA: Salvamento automático desabilitado - mensagens já são salvas na API // quando enviadas via handleSendMessage // useEffect(() => { // if (messages.length > 1) { // saveCurrentChat(); // window.dispatchEvent(new Event('chatUpdated')); // } // }, [messages]); // NOTA: Função de salvamento localStorage desabilitada - migrado para banco de dados // const saveCurrentChat = () => { // try { // const chatTitle = chatService.generateChatTitle( // messages.find(m => m.role === 'user')?.content || 'Nova Conversa' // ); // const storedChat: StoredChat = { // id: currentChatId, // title: chatTitle, // createdAt: new Date(), // updatedAt: new Date(), // model: selectedModel, // systemPrompt: systemPrompt, // messages: messages.map(msg => ({ // ...msg, // timestamp: new Date(), // })), // }; // chatService.saveChat(storedChat); // } catch (error) { // console.error('Erro ao salvar chat:', error); // } // }; const handleNewChat = () => { // Reseta para "0" - novo chat sempre começa com chat_id "0" setCurrentChatId("0"); // Reseta a personalidade para o texto padrão setSystemPrompt(DEFAULT_SYSTEM_PROMPT); setMessages([createWelcomeMessage()]); // Dispara evento para atualizar a sidebar window.dispatchEvent(new Event('chatUpdated')); }; const handleLoadChat = async (chat: ChatRecord) => { // Carrega um chat existente do banco de dados setCurrentChatId(chat.id); // Atualiza a personalidade com o valor do banco de dados // Se não tiver personalidade salva, usa o texto padrão setSystemPrompt(chat.personalidade || DEFAULT_SYSTEM_PROMPT); // Limpa mensagens enquanto carrega setMessages([]); setIsLoading(true); try { // Busca mensagens do chat na API const messagesFromAPI = await chatService.getChatMessages(chat.id); // Converte MessageRecord para Message const loadedMessages: Message[] = messagesFromAPI.map((msg: MessageRecord) => ({ id: msg.id, role: msg.role, content: msg.content, model: msg.model_name, // Nome do modelo retornado pela API attachments: msg.has_attachments ? [] : undefined, // Não temos detalhes dos anexos no GET })); setMessages(loadedMessages); toast({ title: "Chat carregado", description: `${loadedMessages.length} mensagens carregadas.`, }); } catch (error: any) { console.error('Erro ao carregar mensagens:', error); toast({ title: "Erro ao carregar chat", description: error.message || "Não foi possível carregar as mensagens.", variant: "destructive", }); // Inicia com mensagem padrão em caso de erro setMessages([createWelcomeMessage()]); } finally { setIsLoading(false); } }; const handleSendMessage = async (content: string, files?: File[]) => { // Adiciona mensagem do usuário na interface const newMessage: Message = { id: Date.now().toString(), role: "user", content, attachments: files?.map((file) => ({ name: file.name, type: file.type, size: file.size, })), }; setMessages((prev) => [...withoutWelcomeMessages(prev), newMessage]); setIsLoading(true); try { // Envia mensagem para a API // Converte o nome do modelo para o ID da API const modelId = getModelId(selectedModel); const response = await chatService.sendMessage({ chatId: currentChatId, message: content, modelId: modelId, personalidade: systemPrompt, anexos: files, }); // Adiciona resposta da IA na interface if (response.success) { // IMPORTANTE: Atualiza o chat_id com o valor retornado pela API // Isso mantém o contexto da conversa para as próximas mensagens if (response.chat_id && response.chat_id !== currentChatId) { console.log(`Chat ID atualizado: ${currentChatId} → ${response.chat_id}`); // Se estava com chat_id "0", significa que é a primeira mensagem // e o chat acabou de ser criado no backend const isFirstMessage = currentChatId === "0"; setCurrentChatId(response.chat_id); // Dispara evento para ChatSidebar recarregar e mostrar o novo chat if (isFirstMessage) { console.log('Primeira mensagem - novo chat criado, atualizando sidebar'); window.dispatchEvent(new Event('chatUpdated')); } } const aiResponse: Message = { id: (Date.now() + 1).toString(), role: "assistant", content: response.response, model: selectedModel, }; setMessages((prev) => [...prev, aiResponse]); } else { throw new Error('Resposta inválida da API'); } } catch (error: any) { console.error('Erro ao enviar mensagem:', error); // Mostra toast de erro para o usuário toast({ title: "Erro ao enviar mensagem", description: error.message || "Não foi possível comunicar com a IA. Tente novamente.", variant: "destructive", }); // Adiciona mensagem de erro na interface const errorMessage: Message = { id: (Date.now() + 1).toString(), role: "assistant", content: "Desculpe, ocorreu um erro ao processar sua mensagem. Por favor, tente novamente.", model: selectedModel, }; setMessages((prev) => [...prev, errorMessage]); } finally { setIsLoading(false); } }; return (
{/* Chat Sidebar - Hidden on mobile */}
setIsChatSidebarCollapsed(!isChatSidebarCollapsed)} onNewChat={handleNewChat} onSelectChat={handleLoadChat} currentChatId={currentChatId} />
{/* Main Chat Area */}
{messages.map((message) => isWelcomeMessage(message) ? ( ) : ( ) )} {isLoading && (
)}
setInputDraft(null)} />
); };