machinelearning / index.html
Denizfe's picture
tahmin et butonunu resim yükle butonunun aşağısına al ve kedi,aslan ve kaplan tahmin tablosunun yana sayfa kaydırılmadan okunucak şekilde tasarla - Follow Up Deployment
2224f32 verified
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Teachable Machine Görüntü Modeli</title>
<style>
.notification {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #3498db;
color: white;
padding: 25px 35px;
border-radius: 16px;
box-shadow: 0 15px 30px rgba(0,0,0,0.3);
z-index: 1000;
font-size: 1.5em;
text-align: center;
min-width: 300px;
animation: fadeIn 0.3s;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
}
.notification-close {
background: none;
border: none;
color: white;
font-size: 1.2em;
cursor: pointer;
margin-left: 20px;
padding: 5px;
}
@keyframes fadeIn {
from { opacity: 0; transform: translate(-50%, -70%); }
to { opacity: 1; transform: translate(-50%, -50%); }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
padding: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
color: #333;
}
.container {
background-color: white;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
padding: 40px;
max-width: 900px;
width: 100%;
margin: 20px auto;
transition: all 0.3s ease;
}
.container:hover {
box-shadow: 0 15px 35px rgba(0,0,0,0.15);
}
h1 {
color: #2c3e50;
margin-bottom: 15px;
font-size: 2.2rem;
text-align: center;
position: relative;
padding-bottom: 15px;
}
h1:after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 3px;
background: linear-gradient(to right, #3498db, #9b59b6);
border-radius: 3px;
}
p {
color: #7f8c8d;
margin-bottom: 20px;
}
#webcam-container {
margin: 25px 0;
border: 3px solid #3498db;
border-radius: 12px;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
min-height: 300px;
background: linear-gradient(45deg, #f8f9fa, #e9ecef);
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
position: relative;
transition: all 0.3s;
}
#webcam-container:hover {
box-shadow: 0 12px 25px rgba(0,0,0,0.15);
}
#webcam-container:before {
content: "Kamera yükleniyor...";
position: absolute;
color: #7f8c8d;
font-size: 1em;
font-weight: 500;
}
#webcam-container video,
#webcam-container canvas {
display: block;
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
#label-container {
margin: 25px 0;
font-size: 1.2em;
font-weight: bold;
background: linear-gradient(45deg, #f8f9fa, #e9ecef);
padding: 20px;
border-radius: 12px;
width: 100%;
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
max-height: 300px;
overflow-y: auto;
}
#label-container div {
transition: all 0.3s;
}
#label-container div:hover {
transform: translateX(5px);
background-color: rgba(52, 152, 219, 0.2) !important;
}
.button-group {
display: flex;
gap: 10px;
margin: 15px 0;
flex-wrap: wrap;
justify-content: center;
}
button {
padding: 14px 28px;
font-size: 1em;
cursor: pointer;
background: linear-gradient(to right, #3498db, #2980b9);
color: white;
border: none;
border-radius: 50px;
transition: all 0.3s;
font-weight: 600;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
position: relative;
overflow: hidden;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 10px rgba(0,0,0,0.15);
}
button:active {
transform: translateY(1px);
}
button:before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: 0.5s;
}
button:hover:before {
left: 100%;
}
button.secondary {
background: linear-gradient(to right, #95a5a6, #7f8c8d);
}
#imagePreview {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
border: 2px dashed #bdc3c7;
border-radius: 12px;
padding: 20px;
margin: 20px 0;
background-color: white;
transition: all 0.3s;
position: relative;
overflow: hidden;
}
#imagePreview:hover {
border-color: #3498db;
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
}
.upload-section {
margin: 30px 0;
padding: 25px;
background: linear-gradient(45deg, #f8f9fa, #e9ecef);
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
transition: all 0.3s;
}
.upload-section:hover {
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
}
#fileError {
color: #e74c3c;
margin-top: 10px;
font-size: 0.9em;
}
</style>
</head>
<body>
<div class="container">
<h1>Teachable Machine Görüntü Modeli</h1>
<p>Modeli ve kamerayı başlatmak için butona tıklayın.</p>
<div class="button-group">
<button type="button" onclick="toggleCamera()" id="cameraBtn">Kamerayı Aç</button>
</div>
<div id="webcam-container"></div>
<div class="upload-section">
<h2>Veya Resim Yükle</h2>
<div class="button-group">
<input type="file" id="fileUpload" accept="image/*" style="display: none;">
<button type="button" onclick="document.getElementById('fileUpload').click()" class="secondary">Resim Seç</button>
</div>
<div id="fileError"></div>
<div id="imagePreview"></div>
</div>
<div class="button-group" style="margin-top: 20px;">
<button type="button" onclick="predict()" id="predictBtn" disabled>Tahmin Et</button>
</div>
<div id="label-container" style="max-height: 300px; overflow-y: auto; width: 100%; padding: 10px; background: white; border-radius: 12px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@latest/dist/teachablemachine-image.min.js"></script>
<script type="text/javascript">
// Notification function - shows only once on page load
function showNotification(message) {
// Check if notification was already shown
if (sessionStorage.getItem('notificationShown')) return;
const notification = document.createElement('div');
notification.className = 'notification';
notification.innerHTML = `
<span>${message}</span>
<button class="notification-close">&times;</button>
`;
notification.querySelector('.notification-close').onclick = () => {
notification.remove();
};
document.body.appendChild(notification);
sessionStorage.setItem('notificationShown', 'true');
}
// Show welcome notification on page load
window.onload = function() {
init(); // Original init call
showNotification('Hoş geldiniz!');
};
// Daha fazla API fonksiyonu burada bulunabilir:
// https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/image
// Teachable Machine dışa aktarma panelinden sağlanan modelinizin bağlantısı
const URL = "https://teachablemachine.withgoogle.com/models/72Gu94mWN1/";
let model, webcam, labelContainer, maxPredictions;
let cameraActive = false;
// Kamerayı aç/kapat
async function toggleCamera() {
if (!model) {
// Model yüklenmemişse önce yükle
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
}
if (!cameraActive) {
// Kamerayı başlat
const flip = true;
webcam = new tmImage.Webcam(400, 400, flip);
await webcam.setup();
await webcam.play();
document.getElementById("webcam-container").innerHTML = '';
document.getElementById("webcam-container").appendChild(webcam.canvas);
document.getElementById('cameraBtn').textContent = 'Kamerayı Kapat';
document.getElementById('predictBtn').disabled = false;
cameraActive = true;
// Optimize for smoother video
let lastTime = 0;
const fps = 30;
const interval = 1000 / fps;
const optimizedLoop = async (timestamp) => {
if (!cameraActive) return;
if (timestamp - lastTime >= interval) {
webcam.update(); // web kamerası çerçevesini güncelle
lastTime = timestamp;
}
requestAnimationFrame(optimizedLoop);
};
requestAnimationFrame(optimizedLoop);
// Optimized prediction loop for webcam
const predictWebcam = async () => {
if (!cameraActive) return;
// Predict the current webcam frame
const prediction = await model.predict(webcam.canvas);
// Sort predictions by probability (highest first)
prediction.sort((a, b) => b.probability - a.probability);
// Update label container
const labelContainer = document.getElementById('label-container');
labelContainer.innerHTML = '';
for (let i = 0; i < maxPredictions; i++) {
const probabilityPercent = (prediction[i].probability * 100).toFixed(2);
// Show notification if probability > 80%
if (prediction[i].probability > 0.8) {
showNotification(`Bu bir ${prediction[i].className}`);
}
const classPrediction = `
<div style="margin: 8px 0; padding: 8px; background-color: rgba(52, 152, 219, 0.1); border-radius: 4px;">
<strong>${prediction[i].className}:</strong> ${probabilityPercent}%
<div style="height: 5px; background-color: #ecf0f1; margin-top: 5px; border-radius: 3px;">
<div style="width: ${probabilityPercent}%; height: 100%; background-color: #3498db; border-radius: 3px;"></div>
</div>
</div>`;
labelContainer.innerHTML += classPrediction;
}
// Call this function again on the next animation frame
requestAnimationFrame(predictWebcam);
};
// Start the prediction loop
predictWebcam();
} else {
// Kamerayı kapat
if (webcam) {
webcam.stop();
}
document.getElementById('cameraBtn').textContent = 'Kamerayı Aç';
document.getElementById("webcam-container").innerHTML = '';
cameraActive = false;
}
}
// Modeli yükle (başlangıçta)
async function init() {
if (!model) {
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
document.getElementById('predictBtn').disabled = false;
}
}
// Sayfa yüklendiğinde modeli yükle
window.onload = init;
// Web kamerası görüntüsünü görüntü modelinden geçir
// Maximum file size in bytes (2MB)
const MAX_FILE_SIZE = 2 * 1024 * 1024;
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
// Handle file upload
document.getElementById('fileUpload').addEventListener('change', function(e) {
const file = e.target.files[0];
const errorElement = document.getElementById('fileError');
const previewElement = document.getElementById('imagePreview');
// Reset previous state
errorElement.textContent = '';
previewElement.innerHTML = '';
if (!file) return;
// Validate file type
if (!ALLOWED_TYPES.includes(file.type)) {
errorElement.textContent = 'Geçersiz dosya türü. Sadece JPG, PNG, GIF veya WEBP yükleyebilirsiniz.';
return;
}
// Validate file size
if (file.size > MAX_FILE_SIZE) {
errorElement.textContent = 'Dosya boyutu çok büyük. Maksimum 2MB boyutunda dosya yükleyebilirsiniz.';
return;
}
// Create preview
const reader = new FileReader();
reader.onload = function(e) {
const img = document.createElement('img');
img.src = e.target.result;
img.style.maxWidth = '200px';
img.style.maxHeight = '200px';
previewElement.appendChild(img);
// Predict on the uploaded image
predictImage(img);
};
reader.readAsDataURL(file);
});
let lastDetectedClass = null;
let lastNotificationTime = 0;
// Predict on uploaded image (with live updates)
async function predictImage(imageElement) {
if (!model) {
await init();
}
// Clear previous results
const labelContainer = document.getElementById('label-container');
labelContainer.innerHTML = '';
// Start continuous prediction
const predictLoop = async () => {
if (!imageElement.parentNode) return; // Stop if image was removed
const prediction = await model.predict(imageElement);
// Sort predictions by probability (highest first)
prediction.sort((a, b) => b.probability - a.probability);
labelContainer.innerHTML = '';
for (let i = 0; i < maxPredictions; i++) {
const probabilityPercent = (prediction[i].probability * 100).toFixed(2);
// Show notification if probability > 80% and class changed or 5 seconds passed
const currentTime = Date.now();
if (prediction[i].probability > 0.8 &&
(prediction[i].className !== lastDetectedClass || currentTime - lastNotificationTime > 5000)) {
showNotification(`Bu bir ${prediction[i].className}`);
lastDetectedClass = prediction[i].className;
lastNotificationTime = currentTime;
}
const classPrediction = `
<div style="margin: 8px 0; padding: 8px; background-color: rgba(52, 152, 219, 0.1); border-radius: 4px;">
<strong>${prediction[i].className}:</strong> ${probabilityPercent}%
<div style="height: 5px; background-color: #ecf0f1; margin-top: 5px; border-radius: 3px;">
<div style="width: ${probabilityPercent}%; height: 100%; background-color: #3498db; border-radius: 3px;"></div>
</div>
</div>`;
labelContainer.innerHTML += classPrediction;
}
requestAnimationFrame(predictLoop);
};
predictLoop();
}
async function predict() {
if (!model) {
alert('Lütfen önce modeli başlatın!');
return;
}
try {
// Only predict if we have an active source
if (!webcam?.canvas && !document.querySelector('#imagePreview img')) return;
// predict fonksiyonu bir resim, video veya canvas html öğesi alabilir
const prediction = await model.predict(webcam?.canvas || document.querySelector('#imagePreview img'), { flipHorizontal: false });
// Clear previous results
labelContainer.innerHTML = '';
// Sort predictions by probability (highest first)
prediction.sort((a, b) => b.probability - a.probability);
for (let i = 0; i < maxPredictions; i++) {
const probabilityPercent = (prediction[i].probability * 100).toFixed(2);
const classPrediction = `
<div style="margin: 8px 0; padding: 8px; background-color: rgba(52, 152, 219, 0.1); border-radius: 4px;">
<strong>${prediction[i].className}:</strong> ${probabilityPercent}%
<div style="height: 5px; background-color: #ecf0f1; margin-top: 5px; border-radius: 3px;">
<div style="width: ${probabilityPercent}%; height: 100%; background-color: #3498db; border-radius: 3px;"></div>
</div>
</div>`;
labelContainer.innerHTML += classPrediction;
}
} catch (error) {
console.error('Prediction error:', error);
labelContainer.innerHTML = '<div style="color: #e74c3c;">Tahmin yapılırken bir hata oluştu. Lütfen kamera veya resim yüklediğinizden emin olun.</div>';
}
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Denizfe/machinelearning" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>