import React, { useState, useRef, useEffect } from 'react'; import { MdSend, MdRefresh, MdConstruction } from 'react-icons/md'; import { FiUser, FiCpu, FiAlertTriangle, FiInfo } from 'react-icons/fi'; import { v4 as uuidv4 } from 'uuid'; import { toast } from "react-toastify"; import classNames from "classnames"; import ChatMessageComponent, { ChatMessage, MessageType } from './ChatMessage'; import { defaultHTML } from "../../utils/consts"; interface ChatInterfaceProps { agentId: string; html: string; setHtml: (h: string) => void; isAiWorking: boolean; setisAiWorking: (b: boolean) => void; onNewPrompt: (p: string) => void; onScrollToBottom: () => void; geminiKey: string | undefined; chatgptKey: string | undefined; hfToken: string | undefined; } const ChatInterface: React.FC = ({ agentId, html, setHtml, isAiWorking, setisAiWorking, onNewPrompt, onScrollToBottom, geminiKey, chatgptKey, hfToken }) => { const [prompt, setPrompt] = useState(""); const [messages, setMessages] = useState([]); const chatEndRef = useRef(null); const [latestHtml, setLatestHtml] = useState(html); const [isTyping, setIsTyping] = useState(false); // Efeito para rolar para o final quando novas mensagens chegarem useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); // Função principal para enviar mensagem const send = async () => { if (!prompt.trim() || isAiWorking) return; setisAiWorking(true); onNewPrompt(prompt); // Adiciona mensagem do usuário ao histórico const userMessage: ChatMessage = { id: uuidv4(), type: 'user', content: prompt, timestamp: new Date() }; setMessages(prev => [...prev, userMessage]); try { // Registra o contexto atual para o agente orquestrador (opcional) const context = { currentHtml: html !== defaultHTML ? html : "Sem HTML ainda", previousMessages: messages.slice(-5), // Últimas 5 mensagens agentId }; const resp = await fetch(`/api/agent/${agentId}/message`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt, html: html === defaultHTML ? undefined : html, gemini_api_key: geminiKey, chatgpt_api_key: chatgptKey, hf_token: hfToken, provider: "auto", context: JSON.stringify(context) // Enviando contexto para o servidor }), }); const reader = resp.body?.getReader(); const dec = new TextDecoder("utf-8"); let partial = ""; let agentReply: ChatMessage = { id: uuidv4(), type: 'agent', content: '', agentId, timestamp: new Date() }; // Adiciona a mensagem vazia inicial do agente setMessages(prev => [...prev, agentReply]); while (true) { const { done, value } = await reader!.read(); if (done) break; const chunk = dec.decode(value); // Processa os logs separadamente const lines = chunk.split('\n'); for (const line of lines) { if (line.trim().startsWith('[LOG]')) { // Adiciona logs como mensagens de tipo log const logMessage: ChatMessage = { id: uuidv4(), type: 'log', content: line.replace('[LOG] ', ''), timestamp: new Date() }; setMessages(prev => [...prev, logMessage]); } else if (line.trim().startsWith('❌')) { // Adiciona erros como mensagens de tipo error const errorMessage: ChatMessage = { id: uuidv4(), type: 'error', content: line, timestamp: new Date() }; // Se for erro de quota if (line.includes("quota") || line.includes("Quota")) { // Marca o erro de quota no localStorage localStorage.setItem("openai_quota_error", "true"); // Adiciona uma mensagem informativa const infoMessage: ChatMessage = { id: uuidv4(), type: 'info', content: "A API do ChatGPT está com problema de quota. Recomendações:\n1. Tente usar outro agente\n2. Configure uma nova chave API na seção de Configurações\n3. Espere até o próximo mês quando sua quota for renovada", timestamp: new Date() }; setMessages(prev => [...prev, errorMessage, infoMessage]); // Exibe um toast para ajudar o usuário toast.warn("Problema de quota na API. Consulte as recomendações no chat.", { autoClose: 8000 }); } else { setMessages(prev => [...prev, errorMessage]); } } else if (line.trim()) { // Atualiza o conteúdo da resposta do agente partial += line; setMessages(prev => prev.map(msg => msg.id === agentReply.id ? { ...msg, content: partial } : msg ) ); } } if (partial.length > 200) onScrollToBottom(); // Se é um HTML válido, atualiza o editor if (partial.includes("")) { setLatestHtml(partial); setHtml(partial); } } } catch (e: any) { toast.error(e.message); // Adiciona erro como mensagem const errorMessage: ChatMessage = { id: uuidv4(), type: 'error', content: e.message, timestamp: new Date() }; setMessages(prev => [...prev, errorMessage]); } finally { setisAiWorking(false); setPrompt(""); } }; // Função para limpar o chat const clearChat = () => { if (window.confirm("Tem certeza que deseja limpar todas as mensagens?")) { setMessages([]); toast.info("Chat limpo com sucesso"); } }; return (
{/* Status bar */}
{isAiWorking ? 'Processando...' : 'Pronto'}
{/* Área de mensagens com scroll */}
{messages.length === 0 ? (

Inicie uma conversa com o agente {agentId}

setPrompt("Crie um componente de botão com hover effect")} text="Criar botão com hover" /> setPrompt("Crie um formulário de contato responsivo")} text="Formulário de contato" /> setPrompt("Adicione um cabeçalho com menu de navegação")} text="Cabeçalho com menu" /> setPrompt("Implemente um dark mode toggle")} text="Dark mode toggle" />
) : ( messages.map(message => ( )) )}
{/* Área de entrada */}