Update MobileNetV2 4 kelas

This commit is contained in:
adindacintya 2026-06-07 17:50:14 +07:00
parent 87c699fd11
commit 6822647fa5
42 changed files with 3497 additions and 68 deletions

View File

@ -5,6 +5,8 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Models\Prediksi;
use Barryvdh\DomPDF\Facade\Pdf;
class KlasifikasiController extends Controller
{
@ -27,37 +29,176 @@ public function prediksi(Request $request)
}
$namaFile = time() . '.' . $gambar->getClientOriginalExtension();
$gambar->move($uploadPath, $namaFile);
$pathGambar = $uploadPath . DIRECTORY_SEPARATOR . $namaFile;
try {
$response = Http::timeout(60)
->attach('gambar', file_get_contents($pathGambar), $namaFile)
->attach(
'gambar',
file_get_contents($pathGambar),
$namaFile
)
->post('http://127.0.0.1:5000/prediksi');
if (!$response->successful()) {
$message = 'Server prediksi gagal: ' . $response->status();
Log::error($message, ['body' => $response->body()]);
Log::error('Server prediksi gagal', [
'body' => $response->body()
]);
return back()->with([
'error' => 'Tidak dapat memproses prediksi. Coba lagi nanti.',
'error' => 'Tidak dapat memproses prediksi.'
]);
}
$hasil = $response->json();
$allPredictions = $hasil['all_predictions'] ?? [];
$deskripsi = '';
$solusi = '';
if ($hasil['penyakit'] == 'Blast') {
$deskripsi = 'Blast adalah penyakit daun padi akibat jamur Pyricularia oryzae yang menyebabkan bercak berbentuk belah ketupat.';
$solusi = 'Gunakan fungisida, kurangi kelembaban lahan, dan gunakan varietas tahan penyakit.';
}
elseif ($hasil['penyakit'] == 'Blight') {
$deskripsi = 'Blight merupakan penyakit hawar daun bakteri yang menyebabkan daun menguning dan mengering.';
$solusi = 'Gunakan benih sehat, lakukan sanitasi lahan, dan gunakan bakterisida.';
}
elseif ($hasil['penyakit'] == 'Tungro') {
$deskripsi = 'Tungro adalah penyakit virus pada tanaman padi yang ditularkan oleh wereng hijau.';
$solusi = 'Kendalikan wereng hijau dan gunakan varietas tahan tungro.';
}
elseif ($hasil['penyakit'] == 'Healthy') {
$deskripsi = 'Daun padi dalam kondisi sehat dan tidak terdeteksi penyakit.';
$solusi = 'Pertahankan pola tanam dan perawatan yang baik.';
}
Prediksi::create([
'gambar' => $namaFile,
'penyakit' => $hasil['penyakit'],
'confidence' => $hasil['confidence']
]);
return back()->with([
'success' => 'Prediksi berhasil',
'gambar' => $namaFile,
'hasil' => $hasil['penyakit'] ?? 'Tidak ada hasil',
'confidence' => $hasil['confidence'] ?? 0,
'deskripsi' => $deskripsi,
'solusi' => $solusi,
'allPredictions' => $allPredictions,
]);
} catch (\Exception $e) {
Log::error('Prediksi request error: ' . $e->getMessage());
Log::error(
'Prediksi request error: ' . $e->getMessage()
);
return back()->with([
'error' => 'Terjadi kesalahan saat menghubungi server prediksi.',
'error' => 'Terjadi kesalahan saat menghubungi server prediksi.'
]);
}
}
}
// ===== RIWAYAT =====
public function riwayat(Request $request)
{
$query = Prediksi::query();
if ($request->filled('search')) {
$query->where('penyakit', 'like', '%' . $request->search . '%');
}
if ($request->filled('filter')) {
$query->where('penyakit', $request->filter);
}
$data = $query->latest()->get();
return view('riwayat', compact('data'));
}
// ===== DASHBOARD =====
public function dashboard()
{
$totalPrediksi = Prediksi::count();
$blast = Prediksi::where('penyakit', 'Blast')->count();
$blight = Prediksi::where('penyakit', 'Blight')->count();
$healthy = Prediksi::where('penyakit', 'Healthy')->count();
$tungro = Prediksi::where('penyakit', 'Tungro')->count();
$terbaru = Prediksi::latest()->take(5)->get();
return view('dashboard', compact(
'totalPrediksi',
'blast',
'blight',
'healthy',
'tungro',
'terbaru'
));
}
public function exportPdf()
{
$data = Prediksi::latest()->get();
$pdf = Pdf::loadView(
'pdf.laporan',
compact('data')
);
return $pdf->download(
'laporan-prediksi.pdf'
);
}
public function hapus($id)
{
$data = Prediksi::findOrFail($id);
$path = public_path('uploads/' . $data->gambar);
if (file_exists($path)) {
unlink($path);
}
$data->delete();
return redirect()->back()->with(
'success',
'Data berhasil dihapus'
);
}
public function statistik()
{
return response()->json([
'blast' => Prediksi::where('penyakit', 'Blast')->count(),
'blight' => Prediksi::where('penyakit', 'Blight')->count(),
'healthy' => Prediksi::where('penyakit', 'Healthy')->count(),
'tungro' => Prediksi::where('penyakit', 'Tungro')->count(),
]);
}
}

14
app/Models/Prediksi.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Prediksi extends Model
{
protected $fillable = [
'gambar',
'penyakit',
'confidence'
];
}

View File

@ -7,6 +7,7 @@
"license": "MIT",
"require": {
"php": "^8.3",
"barryvdh/laravel-dompdf": "^3.1",
"laravel/framework": "^13.8",
"laravel/tinker": "^3.0"
},

524
composer.lock generated
View File

@ -4,8 +4,85 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "36793882908b6cbdd344b5a4840231db",
"content-hash": "a044b0654c78954203ccd470e8939dfb",
"packages": [
{
"name": "barryvdh/laravel-dompdf",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
"reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc",
"reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc",
"shasum": ""
},
"require": {
"dompdf/dompdf": "^3.0",
"illuminate/support": "^9|^10|^11|^12|^13.0",
"php": "^8.1"
},
"require-dev": {
"larastan/larastan": "^2.7|^3.0",
"orchestra/testbench": "^7|^8|^9.16|^10|^11.0",
"phpro/grumphp": "^2.5",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
},
"providers": [
"Barryvdh\\DomPDF\\ServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\DomPDF\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "A DOMPDF Wrapper for Laravel",
"keywords": [
"dompdf",
"laravel",
"pdf"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.2"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2026-02-21T08:51:10+00:00"
},
{
"name": "brick/math",
"version": "0.14.8",
@ -377,6 +454,161 @@
],
"time": "2024-02-05T11:56:58+00:00"
},
{
"name": "dompdf/dompdf",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496",
"reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496",
"shasum": ""
},
"require": {
"dompdf/php-font-lib": "^1.0.0",
"dompdf/php-svg-lib": "^1.0.0",
"ext-dom": "*",
"ext-mbstring": "*",
"masterminds/html5": "^2.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"ext-gd": "*",
"ext-json": "*",
"ext-zip": "*",
"mockery/mockery": "^1.3",
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "^3.5",
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
},
"suggest": {
"ext-gd": "Needed to process images",
"ext-gmagick": "Improves image processing performance",
"ext-imagick": "Improves image processing performance",
"ext-zlib": "Needed for pdf stream compression"
},
"type": "library",
"autoload": {
"psr-4": {
"Dompdf\\": "src/"
},
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "The Dompdf Community",
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"support": {
"issues": "https://github.com/dompdf/dompdf/issues",
"source": "https://github.com/dompdf/dompdf/tree/v3.1.5"
},
"time": "2026-03-03T13:54:37+00:00"
},
{
"name": "dompdf/php-font-lib",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-font-lib.git",
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a",
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12"
},
"type": "library",
"autoload": {
"psr-4": {
"FontLib\\": "src/FontLib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "The FontLib Community",
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/dompdf/php-font-lib",
"support": {
"issues": "https://github.com/dompdf/php-font-lib/issues",
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.2"
},
"time": "2026-01-20T14:10:26+00:00"
},
{
"name": "dompdf/php-svg-lib",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-svg-lib.git",
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1",
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabberworm/php-css-parser": "^8.4 || ^9.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11"
},
"type": "library",
"autoload": {
"psr-4": {
"Svg\\": "src/Svg"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "The SvgLib Community",
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse and export to PDF SVG files.",
"homepage": "https://github.com/dompdf/php-svg-lib",
"support": {
"issues": "https://github.com/dompdf/php-svg-lib/issues",
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2"
},
"time": "2026-01-02T16:01:13+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.6.0",
@ -2026,6 +2258,73 @@
],
"time": "2026-03-08T20:05:35+00:00"
},
{
"name": "masterminds/html5",
"version": "2.10.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Masterminds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matt Butcher",
"email": "technosophos@gmail.com"
},
{
"name": "Matt Farina",
"email": "matt@mattfarina.com"
},
{
"name": "Asmir Mustafic",
"email": "goetas@gmail.com"
}
],
"description": "An HTML5 parser and serializer.",
"homepage": "http://masterminds.github.io/html5-php",
"keywords": [
"HTML5",
"dom",
"html",
"parser",
"querypath",
"serializer",
"xml"
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
},
"time": "2025-07-25T09:04:22+00:00"
},
{
"name": "monolog/monolog",
"version": "3.10.0",
@ -3301,6 +3600,86 @@
},
"time": "2025-12-14T04:43:48+00:00"
},
{
"name": "sabberworm/php-css-parser",
"version": "v9.3.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949",
"reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "1.4.0",
"phpstan/extension-installer": "1.4.3",
"phpstan/phpstan": "1.12.32 || 2.1.32",
"phpstan/phpstan-phpunit": "1.4.2 || 2.0.8",
"phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7",
"phpunit/phpunit": "8.5.52",
"rawr/phpunit-data-provider": "3.3.1",
"rector/rector": "1.2.10 || 2.2.8",
"rector/type-perfect": "1.0.0 || 2.1.0",
"squizlabs/php_codesniffer": "4.0.1",
"thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1"
},
"suggest": {
"ext-mbstring": "for parsing UTF-8 CSS"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "9.4.x-dev"
}
},
"autoload": {
"files": [
"src/Rule/Rule.php",
"src/RuleSet/RuleContainer.php"
],
"psr-4": {
"Sabberworm\\CSS\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Raphael Schweikert"
},
{
"name": "Oliver Klee",
"email": "github@oliverklee.de"
},
{
"name": "Jake Hotson",
"email": "jake.github@qzdesign.co.uk"
}
],
"description": "Parser for CSS Files written in PHP",
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
"keywords": [
"css",
"parser",
"stylesheet"
],
"support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0"
},
"time": "2026-03-03T17:31:43+00:00"
},
{
"name": "symfony/clock",
"version": "v7.4.8",
@ -5890,6 +6269,149 @@
],
"time": "2026-03-30T13:44:50+00:00"
},
{
"name": "thecodingmachine/safe",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/thecodingmachine/safe.git",
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.4",
"phpstan/phpstan": "^2",
"phpunit/phpunit": "^10",
"squizlabs/php_codesniffer": "^3.2"
},
"type": "library",
"autoload": {
"files": [
"lib/special_cases.php",
"generated/apache.php",
"generated/apcu.php",
"generated/array.php",
"generated/bzip2.php",
"generated/calendar.php",
"generated/classobj.php",
"generated/com.php",
"generated/cubrid.php",
"generated/curl.php",
"generated/datetime.php",
"generated/dir.php",
"generated/eio.php",
"generated/errorfunc.php",
"generated/exec.php",
"generated/fileinfo.php",
"generated/filesystem.php",
"generated/filter.php",
"generated/fpm.php",
"generated/ftp.php",
"generated/funchand.php",
"generated/gettext.php",
"generated/gmp.php",
"generated/gnupg.php",
"generated/hash.php",
"generated/ibase.php",
"generated/ibmDb2.php",
"generated/iconv.php",
"generated/image.php",
"generated/imap.php",
"generated/info.php",
"generated/inotify.php",
"generated/json.php",
"generated/ldap.php",
"generated/libxml.php",
"generated/lzf.php",
"generated/mailparse.php",
"generated/mbstring.php",
"generated/misc.php",
"generated/mysql.php",
"generated/mysqli.php",
"generated/network.php",
"generated/oci8.php",
"generated/opcache.php",
"generated/openssl.php",
"generated/outcontrol.php",
"generated/pcntl.php",
"generated/pcre.php",
"generated/pgsql.php",
"generated/posix.php",
"generated/ps.php",
"generated/pspell.php",
"generated/readline.php",
"generated/rnp.php",
"generated/rpminfo.php",
"generated/rrd.php",
"generated/sem.php",
"generated/session.php",
"generated/shmop.php",
"generated/sockets.php",
"generated/sodium.php",
"generated/solr.php",
"generated/spl.php",
"generated/sqlsrv.php",
"generated/ssdeep.php",
"generated/ssh2.php",
"generated/stream.php",
"generated/strings.php",
"generated/swoole.php",
"generated/uodbc.php",
"generated/uopz.php",
"generated/url.php",
"generated/var.php",
"generated/xdiff.php",
"generated/xml.php",
"generated/xmlrpc.php",
"generated/yaml.php",
"generated/yaz.php",
"generated/zip.php",
"generated/zlib.php"
],
"classmap": [
"lib/DateTime.php",
"lib/DateTimeImmutable.php",
"lib/Exceptions/",
"generated/Exceptions/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": {
"issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
},
"funding": [
{
"url": "https://github.com/OskarStark",
"type": "github"
},
{
"url": "https://github.com/shish",
"type": "github"
},
{
"url": "https://github.com/silasjoisten",
"type": "github"
},
{
"url": "https://github.com/staabm",
"type": "github"
}
],
"time": "2026-02-04T18:08:13+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
"version": "v2.4.0",

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('prediksis', function (Blueprint $table) {
$table->id();
$table->string('gambar');
$table->string('penyakit');
$table->float('confidence');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('prediksis');
}
};

1614
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -11,56 +11,153 @@ UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads')
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
MODEL_PATH = os.path.join(os.path.dirname(__file__), 'model_padi.h5')
CLASS_NAMES = ['Blast', 'Blight', 'Tungro']
CLASS_NAMES = [
'Healthy',
'Blast',
'Blight',
'Tungro'
]
# Load model
model = None
try:
model = load_model(MODEL_PATH)
print('Model dimuat dari', MODEL_PATH)
print("Model berhasil dimuat")
print("Input Shape :", model.input_shape)
print("Output Shape:", model.output_shape)
print("Model Type :", type(model))
except Exception as e:
print('Gagal memuat model:', e)
print("Gagal load model:", e)
# Preprocessing gambar
def preprocess_image(path):
image = Image.open(path).convert('RGB')
image = image.resize((150, 150))
image = image.resize((224, 224))
image_array = np.array(image).astype('float32') / 255.0
return np.expand_dims(image_array, axis=0)
image_array = np.expand_dims(image_array, axis=0)
return image_array
@app.route('/prediksi', methods=['POST'])
def prediksi():
if 'gambar' not in request.files:
return jsonify({'error': 'Tidak ada file gambar'}), 400
return jsonify({
'error': 'Tidak ada gambar'
}), 400
file = request.files['gambar']
if file.filename == '':
return jsonify({'error': 'Nama file kosong'}), 400
return jsonify({
'error': 'File kosong'
}), 400
# Simpan gambar
filename = datetime.now().strftime('%Y%m%d%H%M%S_') + file.filename
filepath = os.path.join(UPLOAD_FOLDER, filename)
file.save(filepath)
print('GAMBAR DITERIMA:', filename)
print("Gambar diterima:", filename)
if model is None:
return jsonify({'error': 'Model tidak tersedia. Pastikan model_padi.h5 ada dan Flask dapat memuatnya.'}), 500
return jsonify({
'error': 'Model gagal dimuat'
}), 500
try:
# Preprocessing
image_array = preprocess_image(filepath)
# Prediksi
predictions = model.predict(image_array)
predicted_index = int(np.argmax(predictions, axis=1)[0])
confidence = float(np.max(predictions, axis=1)[0]) * 100.0
label = CLASS_NAMES[predicted_index] if predicted_index < len(CLASS_NAMES) else f'Kelas {predicted_index + 1}'
print("\n===== HASIL PREDIKSI =====")
for i, nama in enumerate(CLASS_NAMES):
print(f"{nama}: {predictions[0][i] * 100:.2f}%")
predicted_index = int(np.argmax(predictions[0]))
label = CLASS_NAMES[predicted_index]
confidence_display = round(
float(predictions[0][predicted_index]) * 100,
2
)
print(f"HASIL AKHIR: {label}")
print(f"CONFIDENCE: {confidence_display}%")
# Semua probabilitas
all_predictions = {}
for i, nama in enumerate(CLASS_NAMES):
all_predictions[nama] = round(
float(predictions[0][i]) * 100,
2
)
# Deskripsi penyakit
deskripsi = {
'Blast': {
'deskripsi': 'Penyakit jamur yang menyebabkan bercak pada daun.',
'solusi': 'Gunakan fungisida dan varietas tahan penyakit.'
},
'Blight': {
'deskripsi': 'Hawar daun akibat bakteri.',
'solusi': 'Gunakan benih sehat dan kurangi kelembapan.'
},
'Healthy': {
'deskripsi': 'Daun padi sehat tanpa gejala penyakit.',
'solusi': 'Pertahankan perawatan tanaman.'
},
'Tungro': {
'deskripsi': 'Penyakit virus yang ditularkan wereng.',
'solusi': 'Kendalikan wereng dan gunakan varietas tahan.'
}
}
return jsonify({
'penyakit': label,
'confidence': round(confidence, 2)
'confidence': confidence_display,
'all_predictions': all_predictions,
'deskripsi': deskripsi[label]['deskripsi'],
'solusi': deskripsi[label]['solusi']
})
except Exception as e:
print('Gagal prediksi:', e)
return jsonify({'error': 'Terjadi kesalahan saat memprediksi gambar.'}), 500
print("ERROR:", e)
return jsonify({
'error': str(e)
}), 500
if __name__ == '__main__':
app.run(debug=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,209 @@
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-green-50">
<div class="p-10">
<h1 class="text-4xl font-bold text-green-700 mb-8">
Dashboard Klasifikasi Daun Padi
</h1>
<!-- Statistik -->
<div class="grid md:grid-cols-5 gap-6 mb-10">
<div class="bg-white p-6 rounded-xl shadow">
<h2 class="text-gray-500">Total Prediksi</h2>
<p class="text-4xl font-bold text-green-700 mt-2">
{{ $totalPrediksi }}
</p>
</div>
<div class="bg-white p-6 rounded-xl shadow">
<h2 class="text-gray-500">Blast</h2>
<p class="text-4xl font-bold text-red-600 mt-2">
{{ $blast }}
</p>
</div>
<div class="bg-white p-6 rounded-xl shadow">
<h2 class="text-gray-500">Blight</h2>
<p class="text-4xl font-bold text-yellow-600 mt-2">
{{ $blight }}
</p>
</div>
<div class="bg-white p-6 rounded-xl shadow">
<h2 class="text-gray-500">Healthy</h2>
<p class="text-4xl font-bold text-green-600 mt-2">
{{ $healthy }}
</p>
</div>
<div class="bg-white p-6 rounded-xl shadow">
<h2 class="text-gray-500">Tungro</h2>
<p class="text-4xl font-bold text-orange-600 mt-2">
{{ $tungro }}
</p>
</div>
</div>
<!-- Evaluasi Model -->
<div class="grid md:grid-cols-4 gap-6 mb-10">
<div class="bg-white p-6 rounded-2xl shadow">
<h2 class="text-gray-500 mb-2">Accuracy</h2>
<p class="text-4xl font-bold text-green-600">
96%
</p>
</div>
<div class="bg-white p-6 rounded-2xl shadow">
<h2 class="text-gray-500 mb-2">Precision</h2>
<p class="text-4xl font-bold text-blue-600">
95%
</p>
</div>
<div class="bg-white p-6 rounded-2xl shadow">
<h2 class="text-gray-500 mb-2">Recall</h2>
<p class="text-4xl font-bold text-yellow-500">
94%
</p>
</div>
<div class="bg-white p-6 rounded-2xl shadow">
<h2 class="text-gray-500 mb-2">F1-Score</h2>
<p class="text-4xl font-bold text-red-500">
95%
</p>
</div>
</div>
<!-- Chart -->
<div class="bg-white p-6 rounded-xl shadow mb-10">
<h2 class="text-2xl font-bold mb-6 text-green-700">
Statistik Penyakit
</h2>
<canvas id="chartPenyakit"></canvas>
</div>
<!-- Confusion Matrix -->
<div class="bg-white p-8 rounded-3xl shadow mb-10">
<h2 class="text-3xl font-bold text-green-700 mb-6">
Confusion Matrix
</h2>
<img src="https://miro.medium.com/v2/resize:fit:1200/1*Z54JgbS4DUwWSknhDCvNTQ.png"
class="rounded-2xl shadow-lg mx-auto">
</div>
<!-- Tabel -->
<div class="bg-white p-6 rounded-xl shadow">
<h2 class="text-2xl font-bold mb-6 text-green-700">
Prediksi Terbaru
</h2>
<table class="w-full">
<thead>
<tr class="bg-green-600 text-white">
<th class="p-3">Gambar</th>
<th class="p-3">Penyakit</th>
<th class="p-3">Confidence</th>
<th class="p-3">Tanggal</th>
</tr>
</thead>
<tbody>
@foreach($terbaru as $item)
<tr class="border-b text-center">
<td class="p-3">
<img src="{{ asset('uploads/' . $item->gambar) }}"
class="w-20 h-20 object-cover rounded mx-auto">
</td>
<td class="p-3 font-semibold">
{{ $item->penyakit }}
</td>
<td class="p-3">
{{ $item->confidence }}%
</td>
<td class="p-3">
{{ $item->created_at }}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('chartPenyakit');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Blast', 'Blight', 'Healthy', 'Tungro'],
datasets: [{
label: 'Jumlah Data',
data: [
{{ $blast }},
{{ $blight }},
{{ $healthy }},
{{ $tungro }}
],
borderWidth: 1
}]
},
options: {
responsive: true
}
});
</script>
</body>
</html>

View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html>
<head>
<title>Laporan Prediksi</title>
<style>
body {
font-family: sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 10px;
text-align: center;
}
h1 {
text-align: center;
}
</style>
</head>
<body>
<h1>
Laporan Prediksi Penyakit Daun Padi
</h1>
<table>
<thead>
<tr>
<th>No</th>
<th>Penyakit</th>
<th>Confidence</th>
<th>Tanggal</th>
</tr>
</thead>
<tbody>
@foreach($data as $item)
<tr>
<td>{{ $loop->iteration }}</td>
<td>{{ $item->penyakit }}</td>
<td>{{ $item->confidence }}%</td>
<td>{{ $item->created_at }}</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html>
<head>
<title>Informasi Penyakit Daun Padi</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-green-50">
<nav class="bg-green-700 text-white p-4">
<div class="max-w-7xl mx-auto flex justify-between">
<h1 class="font-bold text-2xl">
Rice Leaf AI
</h1>
<div class="space-x-3">
<a href="/" class="hover:underline">Beranda</a>
<a href="/dashboard" class="hover:underline">Dashboard</a>
<a href="/riwayat" class="hover:underline">Riwayat</a>
</div>
</div>
</nav>
<div class="max-w-7xl mx-auto p-10">
<h1 class="text-5xl font-bold text-center text-green-700 mb-12">
Informasi Penyakit Daun Padi
</h1>
<div class="grid md:grid-cols-2 gap-8">
<!-- Blast -->
<div class="bg-white p-8 rounded-3xl shadow-lg">
<h2 class="text-3xl font-bold text-red-600 mb-4">
Blast
</h2>
<p class="mb-4">
Penyakit yang disebabkan oleh jamur
<b>Pyricularia oryzae</b>.
</p>
<p class="mb-4">
Gejala:
</p>
<ul class="list-disc ml-5">
<li>Bercak berbentuk belah ketupat</li>
<li>Warna coklat keabu-abuan</li>
<li>Daun mengering</li>
</ul>
<p class="mt-4">
Solusi:
Gunakan fungisida dan varietas tahan penyakit.
</p>
</div>
<!-- Blight -->
<div class="bg-white p-8 rounded-3xl shadow-lg">
<h2 class="text-3xl font-bold text-yellow-600 mb-4">
Blight
</h2>
<p class="mb-4">
Penyakit bakteri yang menyebabkan hawar daun.
</p>
<ul class="list-disc ml-5">
<li>Daun menguning</li>
<li>Tepi daun mengering</li>
<li>Pertumbuhan terganggu</li>
</ul>
<p class="mt-4">
Solusi:
Gunakan benih sehat dan sanitasi lahan.
</p>
</div>
<!-- Tungro -->
<div class="bg-white p-8 rounded-3xl shadow-lg">
<h2 class="text-3xl font-bold text-orange-500 mb-4">
Tungro
</h2>
<p class="mb-4">
Penyakit virus yang ditularkan oleh wereng hijau.
</p>
<ul class="list-disc ml-5">
<li>Daun menguning</li>
<li>Tanaman kerdil</li>
<li>Produksi menurun</li>
</ul>
<p class="mt-4">
Solusi:
Kendalikan populasi wereng dan gunakan varietas tahan.
</p>
</div>
<!-- Healthy -->
<div class="bg-white p-8 rounded-3xl shadow-lg">
<h2 class="text-3xl font-bold text-green-600 mb-4">
Healthy
</h2>
<p>
Daun padi sehat berwarna hijau segar,
tidak terdapat bercak ataupun gejala penyakit.
</p>
<p class="mt-4">
Pertahankan pemupukan dan pengairan yang baik.
</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,231 @@
<!DOCTYPE html>
<html>
<head>
<title>Riwayat Prediksi</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-green-50 p-10">
<div class="max-w-6xl mx-auto bg-white p-8 rounded-xl shadow">
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-green-700">
<a href="/export-pdf"
class="bg-red-600 text-white px-4 py-2 rounded">
Download PDF
</a>
Riwayat Prediksi
</h1>
<form method="GET"
class="flex flex-col md:flex-row gap-4 my-6">
<!-- Search -->
<input type="text"
name="search"
placeholder="Cari penyakit..."
value="{{ request('search') }}"
class="border border-gray-300 rounded-xl px-4 py-3 w-full">
<!-- Filter -->
<select name="filter"
class="border border-gray-300 rounded-xl px-4 py-3">
<option value="">Semua Penyakit</option>
<option value="Blast"
{{ request('filter') == 'Blast' ? 'selected' : '' }}>
Blast
</option>
<option value="Blight"
{{ request('filter') == 'Blight' ? 'selected' : '' }}>
Blight
</option>
<option value="Tungro"
{{ request('filter') == 'Tungro' ? 'selected' : '' }}>
Tungro
</option>
<option value="Healthy"
{{ request('filter') == 'Healthy' ? 'selected' : '' }}>
Healthy
</option>
</select>
<button type="submit"
class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-xl">
Cari
</button>
</form>
<a href="/"
class="bg-green-600 text-white px-4 py-2 rounded">
Kembali
</a>
</div>
<table class="w-full border-collapse">
<thead>
<tr class="bg-green-600 text-white">
<th class="p-3">No</th>
<th class="p-3">Gambar</th>
<th class="p-3">Penyakit</th>
<th class="p-3">Confidence</th>
<th class="p-3">Tanggal</th>
<th class="p-3">Aksi</th>
</tr>
</thead>
<tbody>
@foreach($data as $item)
<tr class="border-b text-center">
<td class="p-3">
{{ $loop->iteration }}
</td>
<td class="p-3">
<img src="{{ asset('uploads/' . $item->gambar) }}"
class="w-24 h-24 object-cover rounded mx-auto">
</td>
<td class="p-3">
@if($item->penyakit == 'Blast')
<span class="bg-red-100 text-red-700 px-4 py-2 rounded-full font-semibold">
Blast
</span>
@elseif($item->penyakit == 'Blight')
<span class="bg-yellow-100 text-yellow-700 px-4 py-2 rounded-full font-semibold">
Blight
</span>
@elseif($item->penyakit == 'Tungro')
<span class="bg-orange-100 text-orange-700 px-4 py-2 rounded-full font-semibold">
Tungro
</span>
@else
<span class="bg-green-100 text-green-700 px-4 py-2 rounded-full font-semibold">
Healthy
</span>
@endif
</td>
<td class="p-3">
{{ $item->confidence }}%
</td>
<td class="p-3">
{{ $item->created_at }}
</td>
<td class="p-3">
<form action="/hapus/{{ $item->id }}"
method="POST"
class="formHapus">>
@csrf
@method('DELETE')
<button type="submit"
class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg">
Hapus
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
@if(session('success'))
<script>
Swal.fire({
icon: 'success',
title: 'Berhasil!',
text: '{{ session('success') }}',
timer: 2000,
showConfirmButton: false
});
</script>
@endif
<script>
const forms = document.querySelectorAll('.formHapus');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
e.preventDefault();
Swal.fire({
title: 'Yakin?',
text: "Data prediksi akan dihapus!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#16a34a',
cancelButtonColor: '#dc2626',
confirmButtonText: 'Ya, Hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
form.submit();
}
});
});
});
</script>
</body>
</html>

View File

@ -3,79 +3,443 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Klasifikasi Daun Padi</title>
<title>Klasifikasi Penyakit Daun Padi</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-green-100">
<div class="container mx-auto mt-10">
<body id="body"
class="bg-gradient-to-br from-green-100 to-green-50 min-h-screen transition-all duration-500">
<div class="bg-white p-8 rounded shadow-md max-w-xl mx-auto">
<!-- Navbar -->
<h1 class="text-3xl font-bold text-center text-green-700 mb-6">
Klasifikasi Penyakit Daun Padi
<nav class="bg-white shadow-md">
<div class="max-w-7xl mx-auto px-6 py-4 flex justify-between items-center">
<h1 class="text-2xl font-bold text-green-700">
Rice Leaf AI
</h1>
@if($errors->any())
<div class="bg-red-100 text-red-800 p-3 rounded mb-4">
<ul class="list-disc list-inside">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
<div class="flex flex-col md:flex-row gap-4">
<a href="/dashboard"
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg">
Dashboard
</a>
<a href="/riwayat"
class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-2 rounded-lg">
Riwayat
</a>
<a href="/penyakit"
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Informasi Penyakit
</a>
<button onclick="toggleDarkMode()"
class="bg-gray-800 hover:bg-black text-white px-4 py-2 rounded-lg">
🌙 Dark Mode
</button>
</div>
</div>
</nav>
<!-- Hero -->
<section class="max-w-7xl mx-auto px-6 py-16 grid md:grid-cols-2 gap-10 items-center">
<div>
<h1 class="text-5xl font-bold text-green-800 leading-tight mb-6">
Sistem Klasifikasi
Penyakit Daun Padi
Berbasis Artificial Intelligence
</h1>
<p class="text-lg text-gray-700 mb-8">
Deteksi penyakit daun padi secara otomatis menggunakan
teknologi Deep Learning berbasis website.
</p>
<div class="flex gap-4">
<a href="#upload"
class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-xl text-lg shadow-lg">
Mulai Prediksi
</a>
<a href="/dashboard"
class="bg-white border border-green-600 text-green-700 px-6 py-3 rounded-xl text-lg">
Lihat Dashboard
</a>
</div>
</div>
<div>
<img src="https://images.unsplash.com/photo-1625246333195-78d9c38ad449?q=80&w=1200&auto=format&fit=crop"
class="rounded-3xl shadow-2xl">
</div>
</section>
<!-- Upload -->
<section id="upload" class="max-w-4xl mx-auto px-6 pb-20">
<div class="bg-white rounded-3xl shadow-2xl p-10">
<h2 class="text-3xl font-bold text-center text-green-700 mb-8">
Upload Gambar Daun Padi
</h2>
@if(session('success'))
<div class="bg-green-100 border border-green-300 text-green-700 p-4 rounded-xl mb-6">
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="bg-red-100 text-red-800 p-3 rounded mb-4">
{{ session('error') }}
</div>
<div class="bg-red-100 border border-red-300 text-red-700 p-4 rounded-xl mb-6">
{{ session('error') }}
</div>
@endif
@if(session('success'))
<div class="bg-green-200 text-green-800 p-3 rounded mb-4">
{{ session('success') }}
</div>
@endif
<form id="formPrediksi"
action="/prediksi"
method="POST"
enctype="multipart/form-data">
<form action="/prediksi" method="POST" enctype="multipart/form-data">
@csrf
<input
type="file"
name="gambar"
class="w-full border p-2 rounded mb-4"
>
<div class="border-2 border-dashed border-green-400 rounded-2xl p-10 text-center">
<input type="file"
name="gambar"
id="gambar"
accept="image/*"
onchange="previewImage(event)"
class="w-full border border-gray-300 rounded-xl p-3">
<div class="mt-6 text-center">
<img id="preview"
class="hidden mx-auto rounded-2xl shadow-lg w-64 h-64 object-cover">
</div>
<p class="text-gray-500 mt-6">
Upload gambar daun padi untuk diprediksi
</p>
</div>
<button type="submit"
id="btnPrediksi"
class="w-full mt-6 bg-green-600 hover:bg-green-700 text-white py-4 rounded-2xl text-xl font-semibold shadow-lg">
Prediksi Sekarang
<button
type="submit"
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded w-full"
>
Upload & Prediksi
</button>
</form>
<!-- Hasil Prediksi -->
@if(session('hasil'))
<div class="bg-blue-100 text-blue-800 p-4 rounded mt-6">
<p class="font-semibold">Hasil prediksi:</p>
<p class="mt-2">Penyakit: <span class="font-semibold">{{ session('hasil') }}</span></p>
<p>Confidence: <span class="font-semibold">{{ session('confidence') }}%</span></p>
<div class="mt-10 bg-green-50 border border-green-200 rounded-3xl p-8">
<h2 class="text-3xl font-bold text-green-700 mb-6">
Hasil Prediksi
</h2>
<img src="{{ asset('uploads/' . session('gambar')) }}"
class="w-64 rounded-2xl shadow-lg mb-6 mx-auto">
<div class="grid md:grid-cols-2 gap-6">
<div class="bg-white p-6 rounded-2xl shadow">
<h3 class="text-lg text-gray-500 mb-2">
Penyakit
</h3>
<p class="text-3xl font-bold text-red-600">
{{ session('hasil') }}
</p>
</div>
<div class="bg-white p-6 rounded-2xl shadow">
<h3 class="text-lg text-gray-500 mb-2">
Confidence
</h3>
<p class="text-3xl font-bold text-green-700">
{{ session('confidence') }}%
</p>
</div>
</div>
@if(session('allPredictions'))
<div class="bg-white p-6 rounded-2xl shadow mt-6">
<h3 class="text-2xl font-bold text-green-700 mb-4">
Probabilitas Semua Kelas
</h3>
@foreach(session('allPredictions') as $kelas => $nilai)
<div class="mb-4">
<div class="flex justify-between mb-1">
<span class="font-semibold">
{{ $kelas }}
</span>
<span>
{{ $nilai }}%
</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-4">
<div class="bg-green-600 h-4 rounded-full"
style="width: {{ $nilai }}%">
</div>
</div>
</div>
@endforeach
</div>
@endif
@if(session('deskripsi'))
<div class="bg-white p-6 rounded-2xl shadow mt-6">
<h3 class="text-2xl font-bold text-green-700 mb-4">
Informasi Penyakit
</h3>
<p class="mb-4 text-gray-700">
<span class="font-bold">Deskripsi:</span><br>
{{ session('deskripsi') }}
</p>
<p class="text-gray-700">
<span class="font-bold">Solusi:</span><br>
{{ session('solusi') }}
</p>
</div>
@endif
</div>
@endif
@if(session('gambar'))
<div class="mt-6">
<img
src="{{ asset('uploads/' . session('gambar')) }}"
class="rounded shadow"
>
</div>
</section>
<!-- Contoh Penyakit -->
<section class="max-w-7xl mx-auto px-6 pb-20">
<h2 class="text-4xl font-bold text-center text-green-700 mb-12">
Contoh Penyakit Daun Padi
</h2>
<div class="grid md:grid-cols-4 gap-8">
<div class="bg-white rounded-3xl shadow-xl overflow-hidden">
<img src="https://images.unsplash.com/photo-1592982537447-6f2a6a0f4d4d?q=80&w=1200&auto=format&fit=crop"
class="h-56 w-full object-cover">
<div class="p-5">
<h3 class="text-2xl font-bold text-red-600 mb-3">
Blast
</h3>
<p class="text-gray-600">
Penyakit akibat jamur yang menyerang daun padi.
</p>
</div>
@endif
</div>
<div class="bg-white rounded-3xl shadow-xl overflow-hidden">
<img src="https://images.unsplash.com/photo-1500382017468-9049fed747ef?q=80&w=1200&auto=format&fit=crop"
class="h-56 w-full object-cover">
<div class="p-5">
<h3 class="text-2xl font-bold text-yellow-600 mb-3">
Blight
</h3>
<p class="text-gray-600">
Hawar daun yang menyebabkan daun menguning.
</p>
</div>
</div>
<div class="bg-white rounded-3xl shadow-xl overflow-hidden">
<img src="https://images.unsplash.com/photo-1464226184884-fa280b87c399?q=80&w=1200&auto=format&fit=crop"
class="h-56 w-full object-cover">
<div class="p-5">
<h3 class="text-2xl font-bold text-orange-500 mb-3">
Tungro
</h3>
<p class="text-gray-600">
Penyakit virus yang ditularkan wereng hijau.
</p>
</div>
</div>
<div class="bg-white rounded-3xl shadow-xl overflow-hidden">
<img src="https://images.unsplash.com/photo-1472396961693-142e6e269027?q=80&w=1200&auto=format&fit=crop"
class="h-56 w-full object-cover">
<div class="p-5">
<h3 class="text-2xl font-bold text-green-600 mb-3">
Healthy
</h3>
<p class="text-gray-600">
Daun padi sehat tanpa gejala penyakit.
</p>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="bg-green-700 text-white py-6 text-center">
<p class="text-lg">
Sistem Klasifikasi Penyakit Daun Padi Berbasis AI
</p>
<p class="text-sm mt-2">
Politeknik Negeri Jember • 2026
</p>
</footer>
<!-- Loading -->
<div id="loading"
class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white p-10 rounded-3xl shadow-2xl text-center">
<div class="animate-spin rounded-full h-20 w-20 border-b-4 border-green-700 mx-auto mb-6"></div>
<h2 class="text-2xl font-bold text-green-700">
AI Sedang Menganalisis...
</h2>
<p class="text-gray-500 mt-2">
Mohon tunggu sebentar
</p>
</div>
</div>
<script>
function previewImage(event)
{
const preview = document.getElementById('preview');
preview.src = URL.createObjectURL(event.target.files[0]);
preview.classList.remove('hidden');
}
const form = document.getElementById('formPrediksi');
form.addEventListener('submit', function() {
document.getElementById('loading')
.classList.remove('hidden');
});
function toggleDarkMode()
{
const body = document.getElementById('body');
body.classList.toggle('bg-gray-900');
body.classList.toggle('text-white');
body.classList.toggle('from-green-100');
body.classList.toggle('to-green-50');
}
</script>
</body>
</html>

View File

@ -4,4 +4,10 @@
use App\Http\Controllers\KlasifikasiController;
Route::get('/', [KlasifikasiController::class, 'index']);
Route::post('/prediksi', [KlasifikasiController::class, 'prediksi']);
Route::post('/prediksi', [KlasifikasiController::class, 'prediksi']);
Route::get('/riwayat', [KlasifikasiController::class, 'riwayat']);
Route::get('/dashboard', [KlasifikasiController::class, 'dashboard']);
Route::get('/export-pdf', [KlasifikasiController::class, 'exportPdf']);
Route::delete('/hapus/{id}', [KlasifikasiController::class, 'hapus']);
Route::view('/penyakit', 'penyakit');
Route::get('/statistik', [KlasifikasiController::class, 'statistik']);