feat(FE): AI Implementation Analyzer — readiness score, use-cases, roadmap, ROI via Hermes
This commit is contained in:
parent
a489e614c5
commit
979e41845b
1 changed files with 210 additions and 0 deletions
210
src/app/dashboard/ai-analyzer/page.tsx
Normal file
210
src/app/dashboard/ai-analyzer/page.tsx
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { apiFetch } from '../../../lib/api';
|
||||
import { useSession } from '../../../components/session-provider';
|
||||
|
||||
const DEPARTMENTS = [
|
||||
'Sales & Marketing', 'Customer Success', 'Finance & Accounting',
|
||||
'HR & Recruitment', 'Operations & Logistics', 'Product & Engineering',
|
||||
'Legal & Compliance', 'Executive & Strategy',
|
||||
];
|
||||
|
||||
const COMPANY_SIZES = ['1-10', '11-50', '51-200', '201-1000', '1000+'];
|
||||
|
||||
interface AnalysisResult {
|
||||
readinessScore: number;
|
||||
summary: string;
|
||||
useCases: string;
|
||||
roadmap: string;
|
||||
risks: string;
|
||||
roi: string;
|
||||
}
|
||||
|
||||
export default function AiAnalyzerPage() {
|
||||
const { activeTenant } = useSession();
|
||||
const tenantId = activeTenant?.tenantId ?? '';
|
||||
const [form, setForm] = useState({
|
||||
companyName: '', industry: '', size: '11-50', description: '',
|
||||
currentTools: '', departments: [] as string[], budget: '', timeline: '6',
|
||||
});
|
||||
const [result, setResult] = useState<AnalysisResult | null>(null);
|
||||
|
||||
const analyzeMut = useMutation({
|
||||
mutationFn: () => {
|
||||
const prompt = [
|
||||
`Analizează potențialul de implementare AI pentru această companie și generează un raport detaliat.`,
|
||||
``,
|
||||
`## Date companie`,
|
||||
`Nume: ${form.companyName || 'Nespecificat'}`,
|
||||
`Industrie: ${form.industry}`,
|
||||
`Dimensiune: ${form.size} angajați`,
|
||||
`Descriere: ${form.description}`,
|
||||
`Tool-uri existente: ${form.currentTools || 'Nespecificate'}`,
|
||||
`Departamente prioritare: ${form.departments.join(', ') || 'Toate'}`,
|
||||
`Buget estimat: ${form.budget || 'Nespecificat'} EUR`,
|
||||
`Timeline dorit: ${form.timeline} luni`,
|
||||
``,
|
||||
`Generează un raport structurat cu aceste secțiuni (format JSON valid):`,
|
||||
`{`,
|
||||
` "readinessScore": [0-100, scor de pregătire pentru AI],`,
|
||||
` "summary": "[2-3 fraze: situația actuală și potențialul]",`,
|
||||
` "useCases": "[top 5 use-case-uri specifice industriei, cu impact cuantificat]",`,
|
||||
` "roadmap": "[roadmap implementare 3 faze: Quick wins 0-3 luni, Foundation 3-6 luni, Scale 6-12 luni]",`,
|
||||
` "risks": "[top 3 riscuri și mitigation]",`,
|
||||
` "roi": "[estimare ROI: costuri implementare vs beneficii cuantificate]"`,
|
||||
`}`,
|
||||
`Răspunde DOAR cu JSON valid, fără text extra.`,
|
||||
].join('\n');
|
||||
|
||||
return apiFetch<{ reply: string }>('/v1/ai/ask', {
|
||||
tenantId, method: 'POST',
|
||||
body: {
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
context: JSON.stringify({ context: 'ai_implementation_analysis' }),
|
||||
},
|
||||
});
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
try {
|
||||
const json = JSON.parse(data.reply.match(/\{[\s\S]*\}/)?.[0] ?? data.reply);
|
||||
setResult(json);
|
||||
} catch {
|
||||
setResult({ readinessScore: 0, summary: data.reply, useCases: '', roadmap: '', risks: '', roi: '' });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function toggleDept(d: string) {
|
||||
setForm(f => ({
|
||||
...f,
|
||||
departments: f.departments.includes(d) ? f.departments.filter(x => x !== d) : [...f.departments, d],
|
||||
}));
|
||||
}
|
||||
|
||||
const scoreColor = result
|
||||
? result.readinessScore >= 70 ? 'text-signal-ok' : result.readinessScore >= 40 ? 'text-amber-600' : 'text-signal-danger'
|
||||
: 'text-ink';
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl space-y-6 p-6">
|
||||
<div>
|
||||
<h1 className="font-display text-2xl font-semibold text-ink">AI Implementation Analyzer</h1>
|
||||
<p className="text-sm text-ink-faint mt-1">
|
||||
Analizează potențialul AI pentru orice companie — scor, use-case-uri, roadmap, ROI
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{!result ? (
|
||||
<div className="card p-6 space-y-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Nume companie</label>
|
||||
<input value={form.companyName} onChange={e => setForm(f => ({...f, companyName: e.target.value}))}
|
||||
placeholder="Acme GmbH" className="mt-1 w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Industrie</label>
|
||||
<input value={form.industry} onChange={e => setForm(f => ({...f, industry: e.target.value}))}
|
||||
placeholder="ex: Logistică, SaaS, Healthcare, Retail…" className="mt-1 w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Descriere activitate</label>
|
||||
<textarea value={form.description} onChange={e => setForm(f => ({...f, description: e.target.value}))}
|
||||
rows={3} placeholder="Ce face compania, ce procese principale are, care sunt provocările…"
|
||||
className="mt-1 w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring resize-none" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Dimensiune echipă</label>
|
||||
<div className="mt-1 flex flex-wrap gap-1.5">
|
||||
{COMPANY_SIZES.map(s => (
|
||||
<button key={s} onClick={() => setForm(f => ({...f, size: s}))}
|
||||
className={`rounded-lg border px-3 py-1 text-xs ${form.size === s ? 'bg-primary text-white border-primary' : 'bg-background text-ink-faint border-border'}`}>
|
||||
{s}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Tool-uri existente</label>
|
||||
<input value={form.currentTools} onChange={e => setForm(f => ({...f, currentTools: e.target.value}))}
|
||||
placeholder="CRM, ERP, Office365, Slack…" className="mt-1 w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Departamente prioritare</label>
|
||||
<div className="mt-1 flex flex-wrap gap-1.5">
|
||||
{DEPARTMENTS.map(d => (
|
||||
<button key={d} onClick={() => toggleDept(d)}
|
||||
className={`rounded-lg border px-2.5 py-1 text-xs ${form.departments.includes(d) ? 'bg-indigo-600 text-white border-indigo-600' : 'bg-background text-ink-faint border-border hover:border-indigo-300'}`}>
|
||||
{d}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Buget estimat (EUR)</label>
|
||||
<input value={form.budget} onChange={e => setForm(f => ({...f, budget: e.target.value}))}
|
||||
placeholder="ex: 50000" type="number" className="mt-1 w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-ink-faint">Timeline (luni)</label>
|
||||
<select value={form.timeline} onChange={e => setForm(f => ({...f, timeline: e.target.value}))}
|
||||
className="mt-1 w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring">
|
||||
{['3','6','12','18','24'].map(t => <option key={t} value={t}>{t} luni</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button onClick={() => analyzeMut.mutate()}
|
||||
disabled={!form.industry || !form.description || analyzeMut.isPending}
|
||||
className="w-full rounded-xl bg-primary py-3 text-sm font-semibold text-white disabled:opacity-50">
|
||||
{analyzeMut.isPending ? '✦ Analizez cu Hermes AI…' : '✦ Generează Analiza AI'}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{/* Score */}
|
||||
<div className="card p-6 flex items-center gap-6">
|
||||
<div className="text-center">
|
||||
<p className={`text-6xl font-bold ${scoreColor}`}>{result.readinessScore}</p>
|
||||
<p className="text-xs text-ink-faint">AI Readiness Score</p>
|
||||
<p className="text-xs font-medium mt-1">
|
||||
{result.readinessScore >= 70 ? '🟢 Pregătit' : result.readinessScore >= 40 ? '🟡 Parțial pregătit' : '🔴 Fundament necesar'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm text-ink">{result.summary}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
{[
|
||||
{ title: '🎯 Top Use-Case-uri', content: result.useCases, bg: 'bg-indigo-50 border-indigo-200' },
|
||||
{ title: '🗺️ Roadmap Implementare', content: result.roadmap, bg: 'bg-emerald-50 border-emerald-200' },
|
||||
{ title: '💰 ROI Estimat', content: result.roi, bg: 'bg-amber-50 border-amber-200' },
|
||||
{ title: '⚠️ Riscuri & Mitigare', content: result.risks, bg: 'bg-red-50 border-red-200' },
|
||||
].map(card => (
|
||||
<div key={card.title} className={`card p-5 ${card.bg} space-y-2`}>
|
||||
<p className="text-sm font-semibold text-ink">{card.title}</p>
|
||||
<p className="text-xs text-ink whitespace-pre-line leading-relaxed">{card.content}</p>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<button onClick={() => setResult(null)}
|
||||
className="w-full rounded-xl border py-2.5 text-sm text-ink-faint hover:bg-muted/50">
|
||||
← Analizează altă companie
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue