veo3 / index.html
UltronBasecamp's picture
실제 구동 될수 있도록 전체 소스를 다음어 줘 - Follow Up Deployment
63e67b5 verified
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Veo3 영상 제작 스튜디오</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<script src="https://apis.google.com/js/api.js"></script>
<script>
API_KEY = "AIzaSyBt2gdFwXehWeYlcNetW89f5JHnQVXuhwI";
</script>
<style>
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 5px rgba(59, 130, 246, 0.5); }
50% { box-shadow: 0 0 20px rgba(59, 130, 246, 0.8); }
}
.float-animation {
animation: float 3s ease-in-out infinite;
}
.pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
.glass-effect {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.progress-bar {
transition: width 0.3s ease;
}
.drag-area {
border: 2px dashed rgba(59, 130, 246, 0.5);
transition: all 0.3s ease;
}
.drag-area:hover {
border-color: rgba(59, 130, 246, 1);
background: rgba(59, 130, 246, 0.05);
}
.drag-area.active {
border-color: #10b981;
background: rgba(16, 185, 129, 0.1);
}
.timeline-item {
transition: all 0.3s ease;
}
.timeline-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen">
<!-- 헤더 -->
<header class="glass-effect p-4">
<div class="max-w-7xl mx-auto flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-blue-500 rounded-lg flex items-center justify-center">
<i data-lucide="video" class="w-6 h-6"></i>
</div>
<h1 class="text-2xl font-bold">Veo3 영상 제작 스튜디오</h1>
</div>
<div class="flex items-center space-x-4">
<button class="px-4 py-2 bg-blue-600 rounded-lg hover:bg-blue-700 transition">
<i data-lucide="save" class="w-4 h-4 inline mr-2"></i>저장
</button>
<button class="px-4 py-2 bg-green-600 rounded-lg hover:bg-green-700 transition">
<i data-lucide="play" class="w-4 h-4 inline mr-2"></i>내보내기
</button>
</div>
</div>
</header>
<!-- 메인 콘텐츠 -->
<main class="max-w-7xl mx-auto p-6 grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- 왼쪽 패널 - 프로젝트 설정 -->
<div class="glass-effect rounded-xl p-6">
<h2 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="settings" class="w-5 h-5 mr-2"></i>프로젝트 설정
</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-2">프로젝트 이름</label>
<input type="text" class="w-full px-3 py-2 bg-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="나의 멋진 영상">
</div>
<div>
<label class="block text-sm font-medium mb-2">비디오 제목</label>
<input type="text" class="w-full px-3 py-2 bg-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="AI의 놀라운 미래">
</div>
<div>
<label class="block text-sm font-medium mb-2">영상 스타일</label>
<select class="w-full px-3 py-2 bg-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>영화적(시네마틱)</option>
<option>다큐멘터리</option>
<option>광고(광고홍보)</option>
<option>교육(강의형)</option>
<option>브이로그</option>
<option>리뷰/언박싱</option>
<option>게임 스트리밍</option>
<option>셀프 인터뷰</option>
<option>모션그래픽</option>
<option>3D 애니메이션</option>
<option>2D 카툰/일러스트</option>
<option>브랜드 필름</option>
<option>프로모션 뮤직비디오</option>
<option>스톱모션</option>
<option>타임랩스/하이퍼랩스</option>
</select>
</div>
<div>
<label class="block text-sm font-medium mb-2">길이 (초)</label>
<input type="range" min="15" max="300" value="60" class="w-full">
<span class="text-sm text-gray-400">60초</span>
</div>
<div>
<label class="block text-sm font-medium mb-2">화질</label>
<select class="w-full px-3 py-2 bg-gray-800 rounded-lg">
<option>HD (720p)</option>
<option>FHD (1080p)</option>
<option>4K (2160p)</option>
</select>
</div>
</div>
</div>
<!-- 중앙 패널 - 프롬프트 입력 -->
<div class="glass-effect rounded-xl p-6">
<h2 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="edit-3" class="w-5 h-5 mr-2"></i>영상 프롬프트
</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-2">메인 프롬프트</label>
<textarea class="w-full px-3 py-2 bg-gray-800 rounded-lg h-32 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="예: 미래 도시의 하늘에서 내려다보는 드론 뷰, 네온 불빛이 반짝이는 사이버펑크 세계..."></textarea>
</div>
<div>
<label class="block text-sm font-medium mb-2">장면 설명</label>
<textarea class="w-full px-3 py-2 bg-gray-800 rounded-lg h-24 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="특정 장면이나 순서를 설명하세요..."></textarea>
</div>
<div>
<label class="block text-sm font-medium mb-2">음악 스타일</label>
<select class="w-full px-3 py-2 bg-gray-800 rounded-lg">
<option>에픽 오케스트라</option>
<option>시네마틱 트레일러</option>
<option>로파이 힙합</option>
<option>퓨처 베이스</option>
<option>하우스/테크노</option>
<option>드럼앤베이스</option>
<option>트랩/EDM</option>
<option>재즈 피아노</option>
<option>어쿠스틱 팝</option>
<option>인디록</option>
<option>발라드(감성)</option>
<option>국악 크로스오버</option>
<option>어린이 동요</option>
<option>성악/클래식</option>
<option>카페 재즈</option>
<option>레트로 신스웨이브</option>
<option>8비트 게임음악</option>
<option>뉴에이지 명상</option>
<option>펑크/소울</option>
<option>월드뮤직(아프리카/라틴)</option>
</select>
</div>
<button class="w-full py-3 bg-gradient-to-r from-purple-600 to-blue-600 rounded-lg hover:from-purple-700 hover:to-blue-700 transition font-semibold">
<i data-lucide="wand-2" class="w-5 h-5 inline mr-2"></i>AI로 영상 생성하기
</button>
</div>
</div>
<!-- 오른쪽 패널 - 미리보기 & 타임라인 -->
<div class="glass-effect rounded-xl p-6">
<h2 class="text-xl font-semibold mb-4 flex items-center">
<i data-lucide="eye" class="w-5 h-5 mr-2"></i>미리보기
</h2>
<!-- 비디오 미리보어 -->
<div class="aspect-video bg-gray-800 rounded-lg mb-4 flex items-center justify-center relative">
<div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 to-blue-900/20 rounded-lg"></div>
<div class="text-center z-10">
<i data-lucide="play-circle" class="w-16 h-16 mx-auto mb-2 text-gray-400"></i>
<p class="text-gray-400">미리보기 준비중...</p>
</div>
</div>
<!-- 진행률 -->
<div class="mb-4">
<div class="flex justify-between text-sm mb-1">
<span>생성 진행률</span>
<span id="progressText">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="progressBar" class="bg-blue-500 h-2 rounded-full progress-bar" style="width: 0%"></div>
</div>
</div>
<!-- 타임라인 -->
<div class="space-y-2">
<h3 class="text-sm font-medium">타임라인</h3>
<div class="space-y-2 max-h-64 overflow-y-auto">
<div class="timeline-item bg-gray-800 rounded-lg p-3">
<div class="flex items-center justify-between">
<span class="text-sm">도시의 새벽 장면</span>
<span class="text-xs text-gray-400">0-15초</span>
</div>
</div>
<div class="timeline-item bg-gray-800 rounded-lg p-3">
<div class="flex items-center justify-between">
<span class="text-sm">드론이 날아가는 장면</span>
<span class="text-xs text-gray-400">15-30초</span>
</div>
</div>
<div class="timeline-item bg-gray-800 rounded-lg p-3">
<div class="flex items-center justify-between">
<span class="text-sm">네온 불빛의 교차로</span>
<span class="text-xs text-gray-400">30-45초</span>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- 하단 드래그 앤 드롭 영역 -->
<footer class="max-w-7xl mx-auto px-6 pb-6">
<div class="glass-effect rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i data-lucide="upload-cloud" class="w-5 h-5 mr-2"></i>리소스 업로드
</h3>
<div class="drag-area rounded-lg p-8 text-center">
<i data-lucide="cloud-upload" class="w-12 h-12 mx-auto mb-3 text-gray-400"></i>
<p class="text-gray-400 mb-2">이미지, 비디오, 오디오 파일을 드래그하거나 클릭하여 업로드</p>
<p class="text-sm text-gray-500">지원 형식: JPG, PNG, MP4, MP3</p>
<input type="file" multiple class="hidden" id="fileInput" accept="image/*,video/*,audio/*">
</div>
</div>
</footer>
<!-- 모달 -->
<div id="modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center">
<div class="glass-effect rounded-xl p-6 max-w-md">
<h3 class="text-lg font-semibold mb-4">생성 완료!</h3>
<p class="text-gray-400 mb-4">영상 생성이 완료되었습니다. 다운로드하시겠습니까?</p>
<div class="flex space-x-3">
<button class="flex-1 py-2 bg-blue-600 rounded-lg hover:bg-blue-700">다운로드</button>
<button class="flex-1 py-2 bg-gray-700 rounded-lg hover:bg-gray-600" onclick="closeModal()">닫기</button>
</div>
</div>
</div>
<script>
// Lucide 아이콘 초기화
lucide.createIcons();
// 실제 진행률
let progress = 0;
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
// Veo API로 실제 영상 생성
async function generateVideo(prompt) {
const requestBody = {
instances: [{
prompt: prompt
}],
parameters: {
aspectRatio: "16:9",
durationSeconds: 8
}
};
const res = await fetch(
`https://generativelanguage.googleapis.com/v1beta/videos:generate?key=${API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(requestBody)
}
);
const data = await res.json();
return data.name; // operation name
}
async function getOperationStatus(name) {
const res = await fetch(
`https://generativelanguage.googleapis.com/v1beta/${name}?key=${API_KEY}`
);
return await res.json();
}
async function pollUntilDone(name) {
progress = 0;
const check = setInterval(async () => {
const op = await getOperationStatus(name);
const state = op.done ? 100 : Math.min(op.metadata?.video?.videoProgressPercent || progress + 5, 95);
progress = state;
progressBar.style.width = progress + '%';
progressText.textContent = Math.floor(progress) + '%';
if (op.done) {
clearInterval(check);
progressBar.style.width = '100%';
progressText.textContent = '100%';
const videoUri = op.response?.video?.videoUri;
if (videoUri) {
document.querySelector('.aspect-video').innerHTML =
`<video class="w-full h-full rounded-lg" controls src="${videoUri}"></video>`;
}
setTimeout(() => {
document.getElementById('modal').classList.remove('hidden');
document.getElementById('modal').classList.add('flex');
}, 500);
}
}, 2000);
}
async function handleGenerate() {
const prompt = document.querySelector('textarea').value.trim();
if (!prompt) {
alert('프롬프트를 입력하세요!');
return;
}
try {
const operationName = await generateVideo(prompt);
await pollUntilDone(operationName);
} catch (e) {
alert('영상 생성 실패: ' + e.message);
}
}
// 드래그 앤 드롭
const dragArea = document.querySelector('.drag-area');
const fileInput = document.getElementById('fileInput');
dragArea.addEventListener('click', () => fileInput.click());
dragArea.addEventListener('dragover', (e) => {
e.preventDefault();
dragArea.classList.add('active');
});
dragArea.addEventListener('dragleave', () => {
dragArea.classList.remove('active');
});
dragArea.addEventListener('drop', (e) => {
e.preventDefault();
dragArea.classList.remove('active');
console.log('파일 업로드:', e.dataTransfer.files);
});
// AI 생성 버튼 클릭
document.querySelector('button').addEventListener('click', handleGenerate);
// 모달 닫기
function closeModal() {
document.getElementById('modal').classList.add('hidden');
document.getElementById('modal').classList.remove('flex');
}
// 반응형 메뉴
const rangeInput = document.querySelector('input[type="range"]');
const rangeValue = document.querySelector('.text-sm.text-gray-400');
rangeInput.addEventListener('input', (e) => {
rangeValue.textContent = e.target.value + '초';
});
</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=UltronBasecamp/veo3" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>