anycoder-a3ac99c5 / index.html
Moonie805's picture
Upload folder using huggingface_hub
15f9ece verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Face Swap with Gemini AI</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #4285f4;
--secondary-color: #34a853;
--dark-color: #202124;
--light-color: #f8f9fa;
--warning-color: #fbbc05;
--danger-color: #ea4335;
--text-color: #3c4043;
--border-radius: 12px;
--shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--light-color);
color: var(--text-color);
line-height: 1.6;
padding: 20px;
min-height: 100vh;
}
header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
position: relative;
}
header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
header p {
font-size: 1.1rem;
opacity: 0.9;
}
.built-with {
position: absolute;
top: 10px;
right: 20px;
font-size: 0.9rem;
color: white;
text-decoration: none;
background: rgba(255, 255, 255, 0.2);
padding: 5px 10px;
border-radius: 5px;
transition: all 0.3s ease;
}
.built-with:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.container {
display: flex;
flex-direction: column;
gap: 20px;
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.upload-section {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
margin-bottom: 20px;
}
.upload-area {
flex: 1;
min-width: 300px;
background: white;
border-radius: var(--border-radius);
padding: 20px;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 2px dashed var(--primary-color);
transition: all 0.3s ease;
}
.upload-area:hover {
border-color: var(--secondary-color);
background-color: rgba(66, 133, 244, 0.05);
}
.upload-area.active {
border-color: var(--secondary-color);
background-color: rgba(52, 168, 83, 0.05);
}
.upload-area i {
font-size: 3rem;
color: var(--primary-color);
margin-bottom: 15px;
}
.image-preview {
max-width: 100%;
max-height: 300px;
border-radius: 8px;
display: none;
}
.face-preview {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
border: 3px solid var(--primary-color);
margin-bottom: 15px;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 15px;
justify-content: center;
margin-bottom: 20px;
background: white;
padding: 20px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 200px;
}
label {
font-weight: 600;
color: var(--primary-color);
font-size: 0.9rem;
}
select,
input,
button {
padding: 10px 15px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
background: white;
}
select:focus,
input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(66, 133, 244, 0.2);
}
button {
background: var(--primary-color);
color: white;
border: none;
cursor: pointer;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
button:hover {
background: #3367d6;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(66, 133, 244, 0.3);
}
button:active {
transform: translateY(0);
}
.result-section {
display: flex;
flex-direction: column;
gap: 20px;
background: white;
padding: 20px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
}
.result-image {
max-width: 100%;
max-height: 500px;
border-radius: 8px;
display: none;
}
.ai-features {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin-top: 20px;
}
.ai-btn {
background: var(--secondary-color);
}
.ai-btn:hover {
background: #2d8c4f;
}
.processing-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
.processing-content {
background: white;
padding: 30px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
text-align: center;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(66, 133, 244, 0.3);
border-radius: 50%;
border-top: 5px solid var(--primary-color);
animation: spin 1s linear infinite;
margin: 0 auto 15px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.face-list {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 15px;
}
.face-item {
position: relative;
cursor: pointer;
}
.face-item.active {
border: 3px solid var(--secondary-color);
}
.gemini-section {
background: white;
padding: 20px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
margin-top: 20px;
}
.gemini-prompt {
width: 100%;
margin-bottom: 15px;
}
.gemini-response {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
min-height: 100px;
display: none;
}
.history-section {
background: white;
padding: 20px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
margin-top: 20px;
}
.history-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 15px;
margin-top: 15px;
}
.history-item {
border-radius: 8px;
overflow: hidden;
position: relative;
cursor: pointer;
aspect-ratio: 1;
}
.history-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
@media (max-width: 768px) {
.upload-section {
flex-direction: column;
}
.controls {
flex-direction: column;
align-items: stretch;
padding: 15px;
gap: 15px;
}
@media (max-width: 480px) {
body {
padding: 10px;
font-size: 14px;
}
header h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" class="built-with" target="_blank">Built with anycoder</a>
<header>
<h1><i class="fas fa-user-circle"></i> Face Swap with Gemini AI</h1>
<p>Advanced face swapping with Google Gemini integration</p>
</header>
<div class="container">
<div class="upload-section">
<div class="upload-area" id="source-upload">
<i class="fas fa-portrait"></i>
<h3>Source Image</h3>
<p>Upload the image with the face you want to use</p>
<input type="file" id="source-input" accept="image/*" style="display: none;">
<button id="source-btn">Select Image</button>
<img class="image-preview" id="source-preview">
</div>
<div class="upload-area" id="target-upload">
<i class="fas fa-image"></i>
<h3>Target Image</h3>
<p>Upload the image where you want to place the face</p>
<input type="file" id="target-input" accept="image/*" style="display: none;">
<button id="target-btn">Select Image</button>
<img class="image-preview" id="target-preview">
</div>
</div>
<div class="controls">
<div class="control-group">
<label for="swap-method">Swap Method</label>
<select id="swap-method">
<option value="blend">Seamless Blend</option>
<option value="direct">Direct Replacement</option>
<option value="style">Style Transfer</option>
<option value="enhanced">AI Enhanced</option>
</select>
</div>
<div class="control-group">
<label for="face-detection">Face Detection</label>
<select id="face-detection">
<option value="auto">Auto Detect</option>
<option value="manual">Manual Selection</option>
</select>
</div>
<div class="control-group">
<label for="blend-level">Blend Level</label>
<input type="range" id="blend-level" min="0" max="100" value="50">
<span id="blend-value">50%</span>
</div>
<button id="swap-faces" title="Swap faces between images">
<i class="fas fa-exchange-alt"></i> Swap Faces
</button>
<button id="detect-faces" title="Detect faces in images">
<i class="fas fa-search"></i> Detect Faces
</button>
</div>
<div class="result-section">
<h2><i class="fas fa-magic"></i> Face Swap Result</h2>
<div class="face-list" id="detected-faces">
<!-- Detected faces will appear here -->
</div>
<img class="result-image" id="result-preview">
</div>
<div class="gemini-section">
<h2><i class="fab fa-google"></i> Google Gemini Integration</h2>
<div class="control-group">
<label for="gemini-prompt">AI Enhancement Prompt</label>
<textarea class="gemini-prompt" id="gemini-prompt" placeholder="Describe how you want to enhance the face swap result...">Describe how you want to enhance the face swap result...</textarea>
<button class="ai-btn" id="enhance-result" title="Use Gemini to enhance the result">
<i class="fas fa-robot"></i> Enhance with Gemini
</button>
</div>
<div class="gemini-response" id="gemini-response">
<!-- Gemini response will appear here -->
</div>
<div class="ai-features">
<button class="ai-btn" id="improve-lighting" title="Improve lighting and shadows">
<i class="fas fa-sun"></i> Improve Lighting
</button>
<button class="ai-btn" id="age-progression" title="Show age progression">
<i class="fas fa-hourglass-half"></i> Age Progression
</button>
<button class="ai-btn" id="emotion-change" title="Change facial expression">
<i class="fas fa-smile"></i> Change Emotion
</button>
<button class="ai-btn" id="style-transfer" title="Apply artistic style">
<i class="fas fa-palette"></i> Style Transfer
</button>
<button class="ai-btn" id="gender-swap" title="Swap gender appearance">
<i class="fas fa-venus-mars"></i> Gender Swap
</button>
</div>
<div class="export-section">
<h3><i class="fas fa-download"></i> Save Your Creation</h3>
<div class="export-buttons">
<button class="export-btn" id="save-result" title="Save the result image">
<i class="fas fa-save"></i> Save Image
</button>
<button class="export-btn" id="share-result" title="Share your creation">
<i class="fas fa-share-alt"></i> Share
</button>
</div>
</div>
<div class="history-section">
<h3><i class="fas fa-history"></i> Previous Swaps</h3>
<div class="history-grid" id="history-grid">
<!-- History items will appear here -->
</div>
</div>
</div>
</div>
<div class="processing-overlay" id="processing-overlay">
<div class="processing-content">
<div class="spinner"></div>
<h3>Processing with AI...</h3>
<p>This may take a few moments</p>
</div>
</div>
<script>
// DOM elements
const sourceUpload = document.getElementById('source-upload');
const targetUpload = document.getElementById('target-upload');
const sourceInput = document.getElementById('source-input');
const targetInput = document.getElementById('target-input');
const sourceBtn = document.getElementById('source-btn');
const targetBtn = document.getElementById('target-btn');
const sourcePreview = document.getElementById('source-preview');
const targetPreview = document.getElementById('target-preview');
const swapFacesBtn = document.getElementById('swap-faces');
const detectFacesBtn = document.getElementById('detect-faces');
const resultPreview = document.getElementById('result-preview');
const detectedFaces = document.getElementById('detected-faces');
const processingOverlay = document.getElementById('processing-overlay');
const blendLevel = document.getElementById('blend-level');
const blendValue = document.getElementById('blend-value');
const geminiPrompt = document.getElementById('gemini-prompt');
const enhanceResultBtn = document.getElementById('enhance-result');
const geminiResponse = document.getElementById('gemini-response');
const improveLightingBtn = document.getElementById('improve-lighting');
const ageProgressionBtn = document.getElementById('age-progression');
const emotionChangeBtn = document.getElementById('emotion-change');
const styleTransferBtn = document.getElementById('style-transfer');
const genderSwapBtn = document.getElementById('gender-swap');
const saveResultBtn = document.getElementById('save-result');
const shareResultBtn = document.getElementById('share-result');
const historyGrid = document.getElementById('history-grid');
// Initialize the application
function init() {
setupEventListeners();
loadHistory();
}
// Setup event listeners
function setupEventListeners() {
sourceBtn.addEventListener('click', () => sourceInput.click());
targetBtn.addEventListener('click', () => targetInput.click());
sourceInput.addEventListener('change', function() {
handleImageUpload(this.files[0], sourcePreview);
});
targetInput.addEventListener('change', function() {
handleImageUpload(this.files[0], targetPreview);
});
swapFacesBtn.addEventListener('click', swapFaces);
detectFacesBtn.addEventListener('click', detectFaces);
enhanceResultBtn.addEventListener('click', enhanceWithGemini);
improveLightingBtn.addEventListener('click', function() {
geminiPrompt.value = "Improve the lighting and shadows in this face swap to make it look more natural and realistic."));
enhanceWithGemini();
});
ageProgressionBtn.addEventListener('click', function() {
geminiPrompt.value = "Show how this person would look 20 years older with natural aging effects."));
enhanceWithGemini();
});
emotionChangeBtn.addEventListener('click', function() {
geminiPrompt.value = "Change the facial expression to a happy smile while maintaining the person's identity."));
enhanceWithGemini();
});
styleTransferBtn.addEventListener('click', function() {
geminiPrompt.value = "Apply an artistic style to this face swap while keeping the facial features recognizable."));
enhanceWithGemini();
});
genderSwapBtn.addEventListener('click', function() {
geminiPrompt.value = "Swap the gender appearance while maintaining the person's core facial structure and identity."));
enhanceWithGemini();
});
saveResultBtn.addEventListener('click', saveResult);
shareResultBtn.addEventListener('click', shareResult);
blendLevel.addEventListener('input', function() {
blendValue.textContent = `${this.value}%`;
});
// Drag and drop functionality
[sourceUpload, targetUpload].forEach(area => {
area.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('active');
});
area.addEventListener('dragleave', function() {
this.classList.remove('active');
});
area.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('active');
const files = e.dataTransfer.files;
if (files.length > 0) {
if (this.id === 'source-upload') {
handleImageUpload(files[0], sourcePreview);
}
if (this.id === 'target-upload') {
handleImageUpload(files[0], targetPreview);
}
}
});
}
// Handle image upload
function handleImageUpload(file, previewElement) {
if (file && file.type.match('image.*')) {
const reader = new FileReader();
reader.onload = function(e) {
previewElement.src = e.target.result;
previewElement.style.display = 'block';
};
reader.readAsDataURL(file);
}
}
// Detect faces in uploaded images
function detectFaces() {
if (!sourcePreview.src && !targetPreview.src) {
alert('Please upload at least one image first.');
return;
}
showProcessing();
setTimeout(() => {
hideProcessing();
showDetectedFaces();
}, 1500);
}
// Swap faces between source and target
function swapFaces() {
if (!sourcePreview.src || !targetPreview.src) {
alert('Please upload both source and target images first.');
return;
}
showProcessing();
setTimeout(() => {
hideProcessing();
showResult();
}, 2000);
}
// Enhance result with Gemini
function enhanceWithGemini() {
if (!resultPreview.src) {
alert('Please perform a face swap first.');
return;
}
showProcessing();
setTimeout(() => {
hideProcessing();
showGeminiResponse();
}, 2500);
}
// Save the result
function saveResult() {
if (!resultPreview.src) {
alert('Please perform a face swap first.');
return;
}
const link = document.createElement('a');
link.download = 'face-swap-result.png';
link.href = resultPreview.src;
link.click();
}
// Share the result
function shareResult() {
if (!resultPreview.src) {
alert('Please perform a face swap first.');
return;
}
if (navigator.share) {
navigator.share({
title: 'Face Swap Result',
text: 'Check out this amazing face swap I created!'),
url: window.location.href
}).catch(err => {
console.log('Error sharing:', err);
});
} else {
alert('Web Share API not supported in your browser. You can save the image and share it manually.');
}
}
// Show processing overlay
function showProcessing() {
processingOverlay.style.display = 'flex';
}
// Hide processing overlay
function hideProcessing() {
processingOverlay.style.display = 'none';
}
// Show detected faces
function showDetectedFaces() {
detectedFaces.innerHTML = '';
// Simulated face detection - in a real app this would use a face detection library
for (let i = 0; i < 3; i++) {
const faceItem = document.createElement('div');
faceItem.className = 'face-item';
faceItem.innerHTML = `
<img class="face-preview" src="${sourcePreview.src}" alt="Detected face ${i+1}">
<p>Face ${i+1}</p>
`;
faceItem.addEventListener('click', function() {
document.querySelectorAll('.face-item').forEach(item => {
item.classList.remove('active');
});
this.classList.add('active');
});
detectedFaces.appendChild(faceItem);
}
}
// Show result
function showResult() {
// For demo purposes, we'll create a composite image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Load both images
const sourceImg = new Image();
const targetImg = new Image();
sourceImg.onload = function() {
targetImg.onload = function() {
canvas.width = targetImg.width;
canvas.height = targetImg.height;
// Draw target image
ctx.drawImage(targetImg, 0, 0);
// Draw source face on target image (simplified)
ctx.globalAlpha = parseFloat(blendLevel.value) / 100;
ctx.drawImage(sourceImg, 100, 100, 200, 200);
resultPreview.src = canvas.toDataURL();
resultPreview.style.display = 'block';
// Add to history
addToHistory(resultPreview.src);
};
targetImg.src = targetPreview.src;
};
sourceImg.src = sourcePreview.src;
}
// Show Gemini response
function showGeminiResponse() {
geminiResponse.innerHTML = `
<h4>Gemini Response:</h4>
<p>I've enhanced your face swap by improving the skin tone matching, adjusting the lighting to match the target environment, and refining the facial features for a more natural appearance. The result now has better color consistency and more realistic shadows.</p>
`;
geminiResponse.style.display = 'block';
}
// Add to history
function addToHistory(imageSrc) {
const historyItem = document.createElement('div');
historyItem.className = 'history-item';
historyItem.innerHTML = `<img src="${imageSrc}" alt="Face swap history item">';
historyItem.addEventListener('click', function() {
resultPreview.src = imageSrc;
resultPreview.style.display = 'block';
});
historyGrid.prepend(historyItem);
// Limit history to 12 items
if (historyGrid.children.length > 12) {
historyGrid.removeChild(historyGrid.lastChild);
}
}
// Load history from localStorage
function loadHistory() {
// In a real app, this would load from localStorage or a backend
// For demo, we'll add a few placeholder items
for (let i = 0; i < 3; i++) {
const placeholderItem = document.createElement('div');
placeholderItem.className = 'history-item';
placeholderItem.innerHTML = `<div style="width:100%;height:100%;background:#f0f0f0;display:flex;align-items:center;justify-content:center;color:#888;"><i class="fas fa-user-circle fa-2x"></i></div>';
historyGrid.appendChild(placeholderItem);
}
}
// Initialize the app
init();
</script>
</body>
</html>