95 lines
3.5 KiB
TypeScript
95 lines
3.5 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { apiClient } from '../services/apiService.ts';
|
|
import { CpuIcon } from './icons/Icons.tsx';
|
|
|
|
interface AiSummaryModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
dashboardData: string;
|
|
}
|
|
|
|
const AiSummaryModal: React.FC<AiSummaryModalProps> = ({ isOpen, onClose, dashboardData }) => {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [summary, setSummary] = useState('');
|
|
const [error, setError] = useState('');
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
setIsLoading(true);
|
|
setSummary('');
|
|
setError('');
|
|
|
|
const systemPrompt =
|
|
'Anda adalah analis peternakan ayam broiler CP 707. Buat ringkasan singkat dan profesional dalam Bahasa Indonesia berdasarkan data berikut. Gunakan standar buku Manajemen Broiler CP 707.';
|
|
apiClient
|
|
.proxyLmStudio(dashboardData, systemPrompt, 0.2)
|
|
.then((res) => setSummary(res.response || ''))
|
|
.catch((err: Error) => setError(err.message || 'Terjadi kesalahan tidak diketahui.'))
|
|
.finally(() => setIsLoading(false));
|
|
}
|
|
}, [isOpen, dashboardData]);
|
|
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50 p-4">
|
|
<div className="bg-white rounded-xl shadow-2xl w-full max-w-2xl transform transition-all">
|
|
<div className="p-6">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="text-2xl font-bold text-gray-800 flex items-center">
|
|
<CpuIcon className="mr-3" /> Ringkasan Laporan AI
|
|
</h2>
|
|
<button onClick={onClose} className="text-gray-400 hover:text-gray-600">
|
|
×
|
|
</button>
|
|
</div>
|
|
<div className="bg-gray-50 p-4 rounded-lg max-h-[60vh] overflow-y-auto">
|
|
{isLoading && (
|
|
<div className="flex flex-col items-center justify-center h-48">
|
|
<svg
|
|
className="animate-spin h-10 w-10 text-red-600"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<circle
|
|
className="opacity-25"
|
|
cx="12"
|
|
cy="12"
|
|
r="10"
|
|
stroke="currentColor"
|
|
strokeWidth="4"
|
|
></circle>
|
|
<path
|
|
className="opacity-75"
|
|
fill="currentColor"
|
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
></path>
|
|
</svg>
|
|
<p className="mt-4 text-gray-600">AI sedang menganalisis data...</p>
|
|
</div>
|
|
)}
|
|
{error && <p className="text-red-500">{error}</p>}
|
|
{summary && (
|
|
<div
|
|
className="prose prose-sm max-w-none"
|
|
dangerouslySetInnerHTML={{ __html: summary.replace(/\n/g, '<br />') }}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="bg-gray-100 px-6 py-3 rounded-b-xl text-right">
|
|
<button
|
|
onClick={onClose}
|
|
className="bg-gray-600 text-white px-4 py-2 rounded-lg hover:bg-gray-700 transition duration-300"
|
|
>
|
|
Tutup
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AiSummaryModal;
|