klasifikasi OK
This commit is contained in:
parent
9eb801a7d5
commit
e66523256c
|
|
@ -0,0 +1,74 @@
|
|||
import os
|
||||
import io
|
||||
import numpy as np
|
||||
import tensorflow as tf
|
||||
from flask import Flask, request, jsonify
|
||||
from flask_cors import CORS
|
||||
from PIL import Image
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app)
|
||||
|
||||
# 1. SETUP PATH MODEL
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
MODEL_PATH = os.path.join(BASE_DIR, 'model_efficientNet.keras')
|
||||
|
||||
# 2. DUMMY PREPROCESS (Agar tidak error saat load Lambda layer)
|
||||
def preprocess_input(x):
|
||||
return x
|
||||
|
||||
print("⏳ Sedang memuat 'Otak AI'...")
|
||||
|
||||
try:
|
||||
# Menggunakan parameter Keras 3 untuk memuat model lama
|
||||
model = tf.keras.models.load_model(
|
||||
MODEL_PATH,
|
||||
custom_objects={'preprocess_input': preprocess_input},
|
||||
compile=False,
|
||||
safe_mode=False # Kunci agar Keras 3 mau menerima config Keras lama
|
||||
)
|
||||
print("✅ BERHASIL: Model AI siap digunakan!")
|
||||
except Exception as e:
|
||||
print(f"❌ GAGAL: {str(e)}")
|
||||
print("--- SOLUSI ---")
|
||||
print("Jika error 'Unrecognized keyword arguments', silakan info ke saya.")
|
||||
|
||||
# Label klasifikasi kopi kamu
|
||||
labels = ['Honey', 'Natural', 'Washed']
|
||||
|
||||
@app.route('/predict', methods=['POST'])
|
||||
def predict():
|
||||
try:
|
||||
file = request.files['image']
|
||||
|
||||
# 1. Load Gambar & Resize ke 224x224
|
||||
img = Image.open(file.stream).convert('RGB')
|
||||
img = img.resize((224, 224))
|
||||
|
||||
# 2. Konversi ke Array
|
||||
img_array = np.array(img).astype('float32')
|
||||
|
||||
# 3. JURUS SAKTI: Gunakan preprocessing asli EfficientNet
|
||||
# Ini akan menangani scaling warna agar sama persis dengan saat training
|
||||
img_array = tf.keras.applications.efficientnet.preprocess_input(img_array)
|
||||
img_array = np.expand_dims(img_array, axis=0)
|
||||
|
||||
# 4. Prediksi
|
||||
preds = model.predict(img_array, verbose=0)
|
||||
class_idx = np.argmax(preds[0])
|
||||
confidence = float(np.max(preds[0]))
|
||||
|
||||
print(f"📥 Prediksi: {labels[class_idx]} ({confidence*100:.2f}%)")
|
||||
|
||||
return jsonify({
|
||||
'label': labels[class_idx],
|
||||
'confidence': f"{confidence * 100:.2f}%",
|
||||
'status': 'success'
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"❌ ERROR PREDIKSI: {str(e)}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Jalankan di port 5001 agar tidak diblokir Windows AirPlay
|
||||
app.run(host='127.0.0.1', port=5001, debug=True)
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,5 @@
|
|||
flask==3.0.2
|
||||
flask-cors==4.0.0
|
||||
tensorflow==2.15.0
|
||||
numpy==1.26.4
|
||||
Pillow==10.2.0
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
<template>
|
||||
<section id="features" class="py-24 px-4">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4 font-display">Keunggulan Sistem Kami</h2>
|
||||
<p class="text-zinc-400 max-w-2xl mx-auto">
|
||||
Didukung oleh teknologi kecerdasan buatan terkini untuk memberikan klasifikasi biji kopi yang cepat, presisi, dan andal.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<!-- Large card - AI Architecture -->
|
||||
<div
|
||||
class="md:col-span-2 group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300 overflow-hidden"
|
||||
>
|
||||
<div class="flex items-start justify-between mb-8">
|
||||
<div>
|
||||
<div class="p-2 rounded-lg bg-emerald-500/10 w-fit mb-4">
|
||||
<Activity class="w-5 h-5 text-emerald-500" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-white mb-2">Arsitektur EfficientNetB0</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
Model klasifikasi kami menggunakan EfficientNetB0, menghadirkan keseimbangan optimal antara akurasi tinggi dan efisiensi komputasi untuk mendeteksi proses pasca-panen (Natural, Honey, Wash).
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
v-for="(active, i) in dots"
|
||||
:key="i"
|
||||
:class="[
|
||||
'w-2 h-2 rounded-full',
|
||||
active ? 'bg-emerald-500 animate-pulse' : 'bg-zinc-700',
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div v-for="(metric, idx) in metrics" :key="metric" class="text-center">
|
||||
<div class="text-2xl font-bold text-white mb-1">{{ metricValues[idx] }}%</div>
|
||||
<div class="text-xs text-zinc-500">{{ metric }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Security -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300">
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<Bean
|
||||
class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors -rotate-15 group-hover:rotate-0 transition-transform duration-500"
|
||||
:stroke-width="1.5"
|
||||
/>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Target Klasifikasi</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">
|
||||
Model ini dilatih khusus untuk membedakan tiga metode pemrosesan pasca-panen utama:
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<span class="px-2 py-1 text-[10px] font-black bg-zinc-800 rounded text-emerald-500 border border-emerald-500/20 tracking-widest uppercase">Natural</span>
|
||||
<span class="px-2 py-1 text-[10px] font-black bg-zinc-800 rounded text-emerald-500 border border-emerald-500/20 tracking-widest uppercase">Honey</span>
|
||||
<span class="px-2 py-1 text-[10px] font-black bg-zinc-800 rounded text-emerald-500 border border-emerald-500/20 tracking-widest uppercase">Wash</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analytics -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<BarChart3 class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Performa Stabil</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">Grafik akurasi klasifikasi berdasarkan dataset pelatihan yang komprehensif.</p>
|
||||
<div class="flex items-end gap-1 h-12">
|
||||
<div class="flex-1 bg-emerald-500/20 h-[80%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-emerald-500/40 h-[60%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-emerald-500 h-[95%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-emerald-500/60 h-[40%] rounded-t-sm"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Performance -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<Zap class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Proses Instan</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">
|
||||
Infrastruktur yang dioptimalkan untuk memberikan hasil prediksi klasifikasi secara instan.
|
||||
</p>
|
||||
<div class="flex items-center gap-2 text-emerald-500 text-sm">
|
||||
<span class="font-mono">~150ms</span>
|
||||
<span class="text-zinc-500 italic">inference time</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Command Palette -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<Command class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Panduan Cepat</h3>
|
||||
<p class="text-zinc-400 text-sm mb-6">Gunakan pintasan keyboard untuk berpindah antarmuka dan memulai analisis dengan cepat.</p>
|
||||
<div class="flex items-center gap-1">
|
||||
<kbd class="px-2 py-1 text-xs bg-zinc-800 border border-zinc-700 rounded text-zinc-300 font-mono italic">
|
||||
Alt + S
|
||||
</kbd>
|
||||
<span class="text-xs text-zinc-600 ml-1">untuk Scan</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { Activity, Command, BarChart3, Zap, Shield } from 'lucide-vue-next'
|
||||
import { Bean, Upload, FolderOpen, X } from 'lucide-vue-next'
|
||||
|
||||
const dots = ref([true, true, true, false, true])
|
||||
const metrics = ['Akurasi', 'Presisi', 'Recall', 'F1-Score']
|
||||
const metricValues = [96, 95, 96, 95]
|
||||
|
||||
let interval: ReturnType<typeof setInterval>
|
||||
|
||||
onMounted(() => {
|
||||
interval = setInterval(() => {
|
||||
dots.value = dots.value.map(() => Math.random() > 0.2)
|
||||
}, 2000)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(interval)
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,20 +1,17 @@
|
|||
<template>
|
||||
<section id="klasifikasi" class="py-24 px-4 bg-black">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
|
||||
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4 font-display">COFFEE SCAN</h2>
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4 font-display ">COFFEE <span class="text-emerald-500">SCANNER</span></h2>
|
||||
<p class="text-zinc-400 max-w-2xl mx-auto">
|
||||
Identifikasi proses pasca-panen biji kopi Anda (Natural, Honey, Wash) menggunakan teknologi Artificial Intelligence.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div
|
||||
class="group relative p-8 rounded-3xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 transition-all duration-500 overflow-hidden"
|
||||
>
|
||||
<div class="group relative p-8 rounded-3xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 transition-all duration-500 overflow-hidden">
|
||||
<div class="flex flex-col md:flex-row items-stretch justify-between gap-8">
|
||||
|
||||
<div class="flex-1 flex flex-col justify-center">
|
||||
<div class="p-3 rounded-xl bg-emerald-500/10 w-fit mb-6">
|
||||
<Upload class="w-6 h-6 text-emerald-500" :stroke-width="2" />
|
||||
|
|
@ -26,8 +23,10 @@
|
|||
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20">
|
||||
<div class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></div>
|
||||
<span class="text-[10px] font-bold text-emerald-500 uppercase tracking-wider">AI Model Ready</span>
|
||||
<div :class="['w-2 h-2 rounded-full bg-emerald-500', isLoading ? 'animate-ping' : 'animate-pulse']"></div>
|
||||
<span class="text-[10px] font-bold text-emerald-500 uppercase tracking-wider">
|
||||
{{ isLoading ? 'Processing...' : 'AI Model Ready' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -68,74 +67,30 @@
|
|||
</label>
|
||||
|
||||
<button
|
||||
:disabled="!imagePreview"
|
||||
class="w-full py-4 rounded-xl font-bold text-base transition-all border-2 border-emerald-600 text-emerald-500 hover:bg-emerald-600/10 active:scale-95 disabled:opacity-50 disabled:border-zinc-700 disabled:text-zinc-500 disabled:hover:bg-transparent disabled:active:scale-100 disabled:cursor-not-allowed flex-none"
|
||||
@click="startClassification"
|
||||
:disabled="!imagePreview || isLoading"
|
||||
class="w-full py-4 rounded-xl font-bold text-base transition-all border-2 border-emerald-600 text-emerald-500 hover:bg-emerald-600 hover:text-white active:scale-95 disabled:opacity-50 disabled:border-zinc-700 disabled:text-zinc-500 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
||||
>
|
||||
Analisis Sekarang
|
||||
<Loader2 v-if="isLoading" class="w-5 h-5 animate-spin" />
|
||||
{{ isLoading ? 'Sedang Menganalisis...' : 'Analisis Sekarang' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-zinc-600 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4">
|
||||
<Command class="w-5 h-5 text-zinc-400" :stroke-width="1.5" />
|
||||
<transition enter-active-class="transition duration-500 ease-out" enter-from-class="transform scale-95 opacity-0" enter-to-class="transform scale-100 opacity-100">
|
||||
<div v-if="predictionResult" class="mt-8 p-8 rounded-3xl bg-emerald-600 shadow-[0_0_50px_-12px_rgba(16,185,129,0.5)] text-center relative overflow-hidden">
|
||||
<div class="relative z-10">
|
||||
<p class="text-xs font-black text-emerald-100 uppercase tracking-[0.3em] mb-2">Hasil Klasifikasi AI</p>
|
||||
<h4 class="text-5xl font-black text-white italic mb-2 tracking-tighter">{{ predictionResult.label }}</h4>
|
||||
<div class="inline-block px-4 py-1.5 bg-black/20 rounded-full backdrop-blur-md">
|
||||
<span class="text-emerald-500 font-bold text-sm uppercase tracking-widest">Confidence: {{ predictionResult.confidence }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Bean class="absolute -right-10 -bottom-10 w-40 h-40 text-white/10 rotate-12" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Panduan Cepat</h3>
|
||||
<p class="text-zinc-400 text-sm mb-6">Gunakan shortcut untuk berpindah antar mode klasifikasi.</p>
|
||||
<div class="flex items-center gap-1">
|
||||
<kbd class="px-2 py-1 text-xs bg-zinc-800 border border-zinc-700 rounded text-zinc-300 font-mono italic">Alt + S</kbd>
|
||||
<span class="text-xs text-zinc-600 ml-1">untuk Scan</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</transition>
|
||||
|
||||
<!-- <div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-zinc-600 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4">
|
||||
<BarChart3 class="w-5 h-5 text-zinc-400" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Akurasi Model</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">Performa klasifikasi berdasarkan dataset saat ini.</p>
|
||||
<div class="flex items-end gap-1 h-12">
|
||||
<div class="flex-1 bg-orange-500/20 h-[80%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-orange-500/40 h-[60%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-orange-500 h-[95%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-orange-500/60 h-[40%] rounded-t-sm"></div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- <div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-zinc-600 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4">
|
||||
<Zap class="w-5 h-5 text-zinc-400" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Proses Cepat</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">
|
||||
Prediksi instan menggunakan akselerasi GPU via TensorFlow.js.
|
||||
</p>
|
||||
<div class="flex items-center gap-2 text-orange-500 text-sm">
|
||||
<span class="font-mono">~150ms</span>
|
||||
<span class="text-zinc-500 italic">inference time</span>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- <div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-zinc-600 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4">
|
||||
<Shield class="w-5 h-5 text-zinc-400" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Privasi Terjamin</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">Foto Anda diproses langsung di browser tanpa disimpan di server kami.</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-2 py-1 text-[10px] font-bold bg-zinc-800 rounded text-zinc-400">CLIENT-SIDE</span>
|
||||
<span class="px-2 py-1 text-[10px] font-bold bg-zinc-800 rounded text-zinc-400">ENCRYPTED</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -143,23 +98,20 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
Upload,
|
||||
Plus,
|
||||
X,
|
||||
Command,
|
||||
BarChart3,
|
||||
Zap,
|
||||
Shield
|
||||
} from 'lucide-vue-next'
|
||||
import { Upload, Plus, X, Loader2, Bean } from 'lucide-vue-next'
|
||||
|
||||
const imagePreview = ref<string | null>(null)
|
||||
const selectedFile = ref<File | null>(null)
|
||||
const predictionResult = ref<{ label: string, confidence: string } | null>(null)
|
||||
const isLoading = ref(false)
|
||||
|
||||
const handleFileChange = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const file = target.files?.[0]
|
||||
|
||||
if (file) {
|
||||
selectedFile.value = file
|
||||
predictionResult.value = null // Reset hasil jika ganti gambar
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
imagePreview.value = e.target?.result as string
|
||||
|
|
@ -168,7 +120,38 @@ const handleFileChange = (event: Event) => {
|
|||
}
|
||||
}
|
||||
|
||||
const startClassification = async () => {
|
||||
if (!selectedFile.value) return
|
||||
|
||||
isLoading.value = true
|
||||
const formData = new FormData()
|
||||
formData.append('image', selectedFile.value)
|
||||
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:5001/predict', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (!response.ok) throw new Error("Gagal terhubung ke AI server")
|
||||
|
||||
const data = await response.json()
|
||||
// Pastikan data yang dikirim Flask sesuai (label & confidence)
|
||||
predictionResult.value = {
|
||||
label: data.label,
|
||||
confidence: data.confidence
|
||||
}
|
||||
} catch (error) {
|
||||
alert("Error: Pastikan backend-ai sudah dijalankan (python app.py)")
|
||||
console.error(error)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const clearImage = () => {
|
||||
imagePreview.value = null
|
||||
selectedFile.value = null
|
||||
predictionResult.value = null
|
||||
}
|
||||
</script>
|
||||
|
|
@ -54,7 +54,7 @@ import { Check } from 'lucide-vue-next'
|
|||
const technologies = [
|
||||
{
|
||||
name: 'Convolutional Neural Network',
|
||||
badge: 'Algoritma AI',
|
||||
badge: 'Algoritma',
|
||||
description: 'Metode Deep Learning mutakhir yang secara khusus dirancang untuk memproses dan menganalisis data visual dengan meniru cara kerja korteks visual manusia.',
|
||||
features: [
|
||||
'Mampu mengenali pola spasial pada tekstur dan warna biji kopi',
|
||||
|
|
@ -77,16 +77,16 @@ const technologies = [
|
|||
highlighted: true,
|
||||
},
|
||||
{
|
||||
name: 'Klasifikasi Pasca-Panen',
|
||||
badge: 'AI Recognition',
|
||||
description: 'Implementasi model CNN yang dilatih secara khusus untuk membedakan karakteristik morfologi dan visual pada tiga metode pemrosesan kopi utama.',
|
||||
name: 'TensorFlow.js & WebGL',
|
||||
badge: 'Deployment',
|
||||
description: 'Infrastruktur runtime yang memungkinkan model AI dijalankan secara native di sisi klien menggunakan akselerasi perangkat keras tanpa bergantung pada server backend.',
|
||||
features: [
|
||||
'Identifikasi akurat untuk proses Natural, Honey, dan Wash',
|
||||
'Analisis tekstur dan gradasi warna biji kopi secara mendalam',
|
||||
'Inference real-time dengan latensi rendah di browser',
|
||||
'Optimasi akurasi berdasarkan varietas Arabika Bondowoso'
|
||||
'Komputasi paralel menggunakan WebGL (GPU Acceleration)',
|
||||
'Zero-latency inference (Prediksi instan tanpa jeda jaringan)',
|
||||
'Data Privacy: Pemrosesan foto dilakukan 100% lokal di browser',
|
||||
'Konversi model format .keras ke format JSON teroptimasi'
|
||||
],
|
||||
highlighted: false,
|
||||
highlighted: false,
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
<template>
|
||||
<section id="features" class="py-24 px-4">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4 font-display">Keunggulan Sistem Kami</h2>
|
||||
<p class="text-zinc-400 max-w-2xl mx-auto">
|
||||
Didukung oleh teknologi kecerdasan buatan terkini untuk memberikan klasifikasi biji kopi yang cepat, presisi, dan andal.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<!-- Large card - AI Architecture -->
|
||||
<div
|
||||
class="md:col-span-2 group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300 overflow-hidden"
|
||||
>
|
||||
<div class="flex items-start justify-between mb-8">
|
||||
<div>
|
||||
<div class="p-2 rounded-lg bg-emerald-500/10 w-fit mb-4">
|
||||
<Activity class="w-5 h-5 text-emerald-500" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-white mb-2">Arsitektur EfficientNetB0</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
Model klasifikasi kami menggunakan EfficientNetB0, menghadirkan keseimbangan optimal antara akurasi tinggi dan efisiensi komputasi untuk mendeteksi proses pasca-panen (Natural, Honey, Wash).
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
v-for="(active, i) in dots"
|
||||
:key="i"
|
||||
:class="[
|
||||
'w-2 h-2 rounded-full',
|
||||
active ? 'bg-emerald-500 animate-pulse' : 'bg-zinc-700',
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div v-for="(metric, idx) in metrics" :key="metric" class="text-center">
|
||||
<div class="text-2xl font-bold text-white mb-1">{{ metricValues[idx] }}%</div>
|
||||
<div class="text-xs text-zinc-500">{{ metric }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Command Palette -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<Command class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Panduan Cepat</h3>
|
||||
<p class="text-zinc-400 text-sm mb-6">Gunakan pintasan keyboard untuk berpindah antarmuka dan memulai analisis dengan cepat.</p>
|
||||
<div class="flex items-center gap-1">
|
||||
<kbd class="px-2 py-1 text-xs bg-zinc-800 border border-zinc-700 rounded text-zinc-300 font-mono italic">
|
||||
Alt + S
|
||||
</kbd>
|
||||
<span class="text-xs text-zinc-600 ml-1">untuk Scan</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analytics -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<BarChart3 class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Performa Stabil</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">Grafik akurasi klasifikasi berdasarkan dataset pelatihan yang komprehensif.</p>
|
||||
<div class="flex items-end gap-1 h-12">
|
||||
<div class="flex-1 bg-emerald-500/20 h-[80%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-emerald-500/40 h-[60%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-emerald-500 h-[95%] rounded-t-sm"></div>
|
||||
<div class="flex-1 bg-emerald-500/60 h-[40%] rounded-t-sm"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Performance -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<Zap class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Proses Instan</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">
|
||||
Infrastruktur yang dioptimalkan untuk memberikan hasil prediksi klasifikasi secara instan.
|
||||
</p>
|
||||
<div class="flex items-center gap-2 text-emerald-500 text-sm">
|
||||
<span class="font-mono">~150ms</span>
|
||||
<span class="text-zinc-500 italic">inference time</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Security -->
|
||||
<div
|
||||
class="group relative p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/50 hover:scale-[1.02] transition-all duration-300"
|
||||
>
|
||||
<div class="p-2 rounded-lg bg-zinc-800 w-fit mb-4 group-hover:bg-emerald-500/10 transition-colors">
|
||||
<Shield class="w-5 h-5 text-zinc-400 group-hover:text-emerald-500 transition-colors" :stroke-width="1.5" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">Privasi Terjamin</h3>
|
||||
<p class="text-zinc-400 text-sm mb-4">Foto Anda dapat diproses dengan aman tanpa harus khawatir disalahgunakan.</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-2 py-1 text-[10px] font-bold bg-zinc-800 rounded text-zinc-400 tracking-wider">CLIENT-SIDE</span>
|
||||
<span class="px-2 py-1 text-[10px] font-bold bg-zinc-800 rounded text-zinc-400 tracking-wider">ENCRYPTED</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { Activity, Command, BarChart3, Zap, Shield } from 'lucide-vue-next'
|
||||
|
||||
const dots = ref([true, true, true, false, true])
|
||||
const metrics = ['Akurasi', 'Presisi', 'Recall', 'F1-Score']
|
||||
const metricValues = [96, 95, 96, 95]
|
||||
|
||||
let interval: ReturnType<typeof setInterval>
|
||||
|
||||
onMounted(() => {
|
||||
interval = setInterval(() => {
|
||||
dots.value = dots.value.map(() => Math.random() > 0.2)
|
||||
}, 2000)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(interval)
|
||||
})
|
||||
</script>
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
<div class="bg-background text-foreground min-h-screen">
|
||||
<Navbar />
|
||||
<Hero />
|
||||
<LogoMarquee />
|
||||
<BentoGrid />
|
||||
<Kelebihan />
|
||||
<Pricing />
|
||||
<Logo />
|
||||
<Scanner />
|
||||
<Keunggulan />
|
||||
<Teknologi />
|
||||
<FAQ />
|
||||
<FinalCta />
|
||||
<Footer/>
|
||||
|
|
@ -15,10 +15,10 @@
|
|||
<script setup lang="ts">
|
||||
import Navbar from '@/components/public/Navbar.vue'
|
||||
import Hero from '@/components/public/Hero.vue'
|
||||
import LogoMarquee from '@/components/public/LogoMarquee.vue'
|
||||
import Kelebihan from '@/components/public/kelebihan.vue'
|
||||
import BentoGrid from '@/components/public/BentoGrid.vue'
|
||||
import Pricing from '@/components/public/Pricing.vue'
|
||||
import Logo from '@/components/public/Logo.vue'
|
||||
import Keunggulan from '@/components/public/Keunggulan.vue'
|
||||
import Scanner from '@/components/public/Scanner.vue'
|
||||
import Teknologi from '@/components/public/Teknologi.vue'
|
||||
import FAQ from '@/components/public/FAQ.vue'
|
||||
import FinalCta from '@/components/public/FinalCta.vue'
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue