182 lines
8.1 KiB
TypeScript
182 lines
8.1 KiB
TypeScript
import React, { useState } from 'react';
|
||
import { Badge } from '../../shared/components/Badge';
|
||
import { Button } from '../../shared/components/Button';
|
||
import { Sparkles, Bot, Brain, Send, Cpu, CheckCircle2, Shield, Activity } from 'lucide-react';
|
||
|
||
interface AiAgent {
|
||
id: string;
|
||
name: string;
|
||
role: string;
|
||
description: string;
|
||
tools: string[];
|
||
status: 'active' | 'busy' | 'idle';
|
||
tasksCompleted: number;
|
||
}
|
||
|
||
const AI_AGENTS: AiAgent[] = [
|
||
{
|
||
id: 'orch',
|
||
name: 'Главный Оркестратор',
|
||
role: 'Orchestrator',
|
||
description: 'Декомпозирует глобальные бизнес-цели и распределяет задачи между агентами-специалистами',
|
||
tools: ['Task Delegator', 'Cross-module Context', 'Guardian Policy'],
|
||
status: 'active',
|
||
tasksCompleted: 342,
|
||
},
|
||
{
|
||
id: 'analyst',
|
||
name: 'Бизнес-аналитик',
|
||
role: 'BI & Financial Analyst',
|
||
description: 'Анализирует чеки, food cost, маржинальность, динамику продаж и выявляет аномалии',
|
||
tools: ['SQL Query', 'Revenue Forecast', 'ABC Matrix', 'Shift Audit'],
|
||
status: 'active',
|
||
tasksCompleted: 819,
|
||
},
|
||
{
|
||
id: 'marketer',
|
||
name: 'Бизнес-маркетолог',
|
||
role: 'Growth & Retention',
|
||
description: 'Генерирует контент-планы, офферы для рассылок, анализирует сегменты клиентов в зоне риска',
|
||
tools: ['Promo Engine', 'Telegram Bot Sender', 'Copywriter', 'Cohort Analysis'],
|
||
status: 'active',
|
||
tasksCompleted: 420,
|
||
},
|
||
{
|
||
id: 'warehouse_agent',
|
||
name: 'Складской су-шеф',
|
||
role: 'Supply Chain Agent',
|
||
description: 'Мониторит критические остатки, сроки годности и формирует авто-заказы поставщикам',
|
||
tools: ['Supplier Auto-Order', 'Waste Tracker', 'Inventory Audit'],
|
||
status: 'active',
|
||
tasksCompleted: 612,
|
||
},
|
||
];
|
||
|
||
export const AiCenterModule: React.FC = () => {
|
||
const [activeAgentId, setActiveAgentId] = useState<string>('orch');
|
||
const [chatMessages, setChatMessages] = useState<{ sender: 'user' | 'ai'; text: string; time: string }[]>([
|
||
{
|
||
sender: 'ai',
|
||
text: 'Здравствуйте! Я Главный Оркестратор Кроны. Моя команда специалистов (Аналитик, Маркетолог, Склад) готова помочь вам оптимизировать операционные процессы, снизить списания и поднять средний чек.',
|
||
time: '12:00',
|
||
},
|
||
]);
|
||
const [prompt, setPrompt] = useState('');
|
||
|
||
const handleSend = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (!prompt.trim()) return;
|
||
|
||
const userText = prompt;
|
||
setChatMessages((prev) => [
|
||
...prev,
|
||
{ sender: 'user', text: userText, time: 'Только что' },
|
||
]);
|
||
setPrompt('');
|
||
|
||
setTimeout(() => {
|
||
setChatMessages((prev) => [
|
||
...prev,
|
||
{
|
||
sender: 'ai',
|
||
text: `Агент «${AI_AGENTS.find(a => a.id === activeAgentId)?.name}»: Анализ запроса «${userText}» завершен. Сформирован проект решения в задачах. Выручка и себестоимость учтены в сводном отчете.`,
|
||
time: 'Только что',
|
||
},
|
||
]);
|
||
}, 450);
|
||
};
|
||
|
||
return (
|
||
<div className="space-y-4 animate-fade-in">
|
||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 bg-krona-surface p-3.5 rounded-xl border border-krona-border shadow-krona-soft">
|
||
<div>
|
||
<div className="flex items-center gap-2">
|
||
<h2 className="text-sm font-bold text-krona-primary">
|
||
✦ Krona AI Center & Автономная бизнес-команда
|
||
</h2>
|
||
<Badge variant="gold" size="sm">Крона Модель v1.8 Flash</Badge>
|
||
</div>
|
||
<p className="text-xs text-krona-secondary mt-0.5">
|
||
Специализированные агенты с прямым доступом к инструментам платформы и памяти заведения
|
||
</p>
|
||
</div>
|
||
|
||
<div className="flex items-center gap-2">
|
||
<Badge variant="green" size="md">Токены: 48 200 / 100 000</Badge>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Agents Selection Cards */}
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3.5">
|
||
{AI_AGENTS.map((agent) => (
|
||
<div
|
||
key={agent.id}
|
||
onClick={() => setActiveAgentId(agent.id)}
|
||
className={`p-4 rounded-xl border cursor-pointer transition-all shadow-krona-soft flex flex-col justify-between space-y-2.5 ${
|
||
agent.id === activeAgentId
|
||
? 'border-krona-gold bg-krona-gold/10 ring-2 ring-krona-gold/20'
|
||
: 'border-krona-border bg-krona-surface hover:border-krona-border-strong'
|
||
}`}
|
||
>
|
||
<div>
|
||
<div className="flex items-center justify-between mb-1.5">
|
||
<span className="text-[10px] uppercase font-bold text-krona-secondary">{agent.role}</span>
|
||
<span className="w-2 h-2 rounded-full bg-krona-green animate-pulse"></span>
|
||
</div>
|
||
<h4 className="text-xs font-bold text-krona-primary">{agent.name}</h4>
|
||
<p className="text-[11px] text-krona-secondary line-clamp-2 mt-1">{agent.description}</p>
|
||
</div>
|
||
|
||
<div className="pt-2 border-t border-krona-border/50 text-[10px] text-krona-secondary flex items-center justify-between">
|
||
<span>Инструментов: {agent.tools.length}</span>
|
||
<span className="font-semibold text-krona-primary">{agent.tasksCompleted} задач</span>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Interactive AI Dialog Box */}
|
||
<div className="bg-krona-surface border border-krona-border rounded-xl p-4 shadow-krona-soft space-y-3">
|
||
<div className="flex items-center justify-between pb-2 border-b border-krona-border">
|
||
<div className="flex items-center gap-2">
|
||
<Bot className="w-4 h-4 text-krona-gold" />
|
||
<span className="text-xs font-bold text-krona-primary">
|
||
Диалог с агентом: {AI_AGENTS.find(a => a.id === activeAgentId)?.name}
|
||
</span>
|
||
</div>
|
||
<Badge variant="gold" size="sm">Контекст синхронизирован</Badge>
|
||
</div>
|
||
|
||
<div className="h-64 overflow-y-auto space-y-2.5 p-2 text-xs">
|
||
{chatMessages.map((m, i) => (
|
||
<div
|
||
key={i}
|
||
className={`p-3 rounded-xl max-w-xl ${
|
||
m.sender === 'user'
|
||
? 'ml-auto bg-[#2F684C] text-white rounded-br-none'
|
||
: 'mr-auto bg-krona-workspace border border-krona-border text-krona-primary rounded-bl-none shadow-krona-soft'
|
||
}`}
|
||
>
|
||
<p className="leading-relaxed">{m.text}</p>
|
||
<span className="block text-[9px] mt-1 opacity-70 text-right">{m.time}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<form onSubmit={handleSend} className="flex gap-2 pt-2 border-t border-krona-border">
|
||
<input
|
||
type="text"
|
||
value={prompt}
|
||
onChange={(e) => setPrompt(e.target.value)}
|
||
placeholder="Сформулируйте задачу для агента (например: 'Оптимизируй закупку лосося')..."
|
||
className="flex-1 bg-krona-workspace border border-krona-border rounded-lg px-3 py-2 text-xs text-krona-primary placeholder:text-krona-secondary focus:outline-none focus:border-krona-gold"
|
||
/>
|
||
<Button type="submit" variant="gold" size="sm">
|
||
<Send className="w-3.5 h-3.5 mr-1" />
|
||
Отправить в работу
|
||
</Button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|