File size: 5,355 Bytes
20ec4ad
 
 
 
 
 
 
 
969b550
20ec4ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
969b550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20ec4ad
 
969b550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20ec4ad
969b550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20ec4ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* 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>
  );
}