klawdyoss's picture
salvando
969b550
/* src/components/ask-ai/ask-ai.tsx */
import { useState, useEffect } from "react";
import { useLocalStorage } from "react-use";
import { toast } from "react-toastify";
import ChatInterface from "./ChatInterface";
import { defaultHTML } from "../../utils/consts";
import { v4 as uuidv4 } from "uuid";
import { AgentTask, ExecutionPlan } from "./AgentOrchestrator";
import { FiCpu, FiAlertCircle, FiCheckCircle, FiLoader } from "react-icons/fi";
export type AskAIProps = {
agentId: string;
html: string;
setHtml: (h: string) => void;
isAiWorking: boolean;
setisAiWorking: (b: boolean) => void;
onNewPrompt: (p: string) => void;
onScrollToBottom: () => void;
};
export default function AskAI(props: AskAIProps) {
const {
agentId,
html,
setHtml,
isAiWorking,
setisAiWorking,
onNewPrompt,
onScrollToBottom,
} = props;
/* lê as três chaves do localStorage ---------------------------- */
const [geminiKey] = useLocalStorage<string>("geminiKey", "");
const [chatgptKey] = useLocalStorage<string>("chatgptKey", "");
const [hfToken] = useLocalStorage<string>("hfToken", "");
const [activeTasks, setActiveTasks] = useState<AgentTask[]>([]);
const [currentPlan, setCurrentPlan] = useState<ExecutionPlan | null>(null);
// Funções para o orquestrador
const handleTaskCreated = (task: AgentTask) => {
setActiveTasks(prev => [...prev, task]);
toast.info(`Nova tarefa criada: ${task.description.substring(0, 40)}...`);
};
const handlePlanCreated = (plan: ExecutionPlan) => {
setCurrentPlan(plan);
toast.success(`Plano criado com ${plan.steps.length} passos`);
};
const handleTaskUpdated = (taskId: string, status: AgentTask['status'], result?: string) => {
setActiveTasks(prev =>
prev.map(task =>
task.id === taskId
? {
...task,
status,
result,
completedAt: (status === 'completed' || status === 'failed') ? new Date() : undefined
}
: task
)
);
};
// Limpa tarefas concluídas após 1 hora
useEffect(() => {
const interval = setInterval(() => {
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
setActiveTasks(prev =>
prev.filter(task =>
task.status !== 'completed' ||
!task.completedAt ||
task.completedAt > oneHourAgo
)
);
}, 15 * 60 * 1000); // Checa a cada 15 minutos
return () => clearInterval(interval);
}, []);
// Determina a cor do status baseado no agentId
const getAgentStatusColor = () => {
switch (agentId) {
case 'orchestrator':
return 'bg-purple-600';
case 'mike':
return 'bg-blue-600';
case 'alex':
return 'bg-green-600';
case 'david':
return 'bg-amber-600';
default:
return 'bg-indigo-600';
}
};
return (
<div className="flex flex-col h-full">
<div className="bg-gray-900 text-white py-3 px-4 border-b border-gray-800">
<div className="flex items-center">
<div className={`w-3 h-3 rounded-full mr-2 ${getAgentStatusColor()}`}></div>
<h2 className="text-lg font-medium">
Agente: {agentId}
</h2>
{isAiWorking && (
<div className="ml-2 animate-pulse text-amber-400">
<FiLoader className="animate-spin" />
</div>
)}
</div>
{currentPlan && (
<div className="mt-2 text-sm bg-gray-800 rounded p-2">
<div className="flex items-center text-indigo-400 mb-1">
<FiCpu className="mr-1" /> Plano: {currentPlan.name}
</div>
<div className="text-xs text-gray-400">
{currentPlan.steps.length} passos planejados
</div>
</div>
)}
{activeTasks.length > 0 && (
<div className="mt-2">
<div className="text-xs text-gray-400 mb-1">Tarefas:</div>
<div className="flex flex-wrap gap-2">
{activeTasks
.filter(t => t.status === 'in-progress')
.slice(0, 2)
.map(task => (
<div key={task.id} className="text-xs bg-gray-800 rounded px-2 py-1 flex items-center">
<FiLoader className="animate-spin mr-1 text-amber-400" />
<span className="truncate max-w-[180px]">{task.description}</span>
</div>
))}
{activeTasks.filter(t => t.status === 'completed').length > 0 && (
<div className="text-xs bg-gray-800 rounded px-2 py-1 flex items-center">
<FiCheckCircle className="mr-1 text-green-400" />
<span>{activeTasks.filter(t => t.status === 'completed').length} concluídas</span>
</div>
)}
</div>
</div>
)}
</div>
<ChatInterface
agentId={agentId}
html={html}
setHtml={setHtml}
isAiWorking={isAiWorking}
setisAiWorking={setisAiWorking}
onNewPrompt={onNewPrompt}
onScrollToBottom={onScrollToBottom}
geminiKey={geminiKey}
chatgptKey={chatgptKey}
hfToken={hfToken}
/>
</div>
);
}