|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
{{template "views/partials/head" .}} |
|
|
<script defer src="static/video.js"></script> |
|
|
|
|
|
<body class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] flex flex-col h-screen"> |
|
|
<div class="flex flex-col flex-1 overflow-hidden"> |
|
|
|
|
|
{{template "views/partials/navbar" .}} |
|
|
<div class="flex flex-1 overflow-hidden"> |
|
|
|
|
|
<div class="flex flex-col lg:flex-row flex-1 gap-4 p-4 overflow-hidden"> |
|
|
|
|
|
<div class="flex-shrink-0 lg:w-1/4 flex flex-col min-h-0"> |
|
|
<div class="card p-3 space-y-3 overflow-y-auto flex-1"> |
|
|
|
|
|
<div class="space-y-1.5"> |
|
|
<div class="flex items-center justify-between gap-2"> |
|
|
<label class="text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide flex-shrink-0">Model</label> |
|
|
</div> |
|
|
<select x-data="{ link : '' }" x-model="link" x-init="$watch('link', value => window.location = link)" |
|
|
id="model-select" |
|
|
class="input w-full p-1.5 text-xs" |
|
|
> |
|
|
<option value="" disabled class="text-[var(--color-text-secondary)]">Select a model</option> |
|
|
{{ $model:=.Model}} |
|
|
{{ range .ModelsConfig }} |
|
|
{{ $cfg := . }} |
|
|
{{ range .KnownUsecaseStrings }} |
|
|
{{ if eq . "FLAG_VIDEO" }} |
|
|
<option value="video/{{$cfg.Name}}" {{ if eq $cfg.Name $model }} selected {{end}} class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">{{$cfg.Name}}</option> |
|
|
{{ end }} |
|
|
{{ end }} |
|
|
{{ end }} |
|
|
{{ range .ModelsWithoutConfig }} |
|
|
<option value="video/{{.}}" {{ if eq . $model }} selected {{ end }} class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">{{.}}</option> |
|
|
{{end}} |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
<div class="relative"> |
|
|
<input id="video-model" type="hidden" value="{{.Model}}"> |
|
|
<form id="genvideo" action="video/{{.Model}}" method="get"> |
|
|
|
|
|
<div class="space-y-2"> |
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="input" class="block text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide"> |
|
|
<i class="fas fa-magic mr-1.5 text-[var(--color-primary)]"></i>Prompt |
|
|
</label> |
|
|
<textarea |
|
|
id="input" |
|
|
name="input" |
|
|
placeholder="Describe the video you want to generate..." |
|
|
autocomplete="off" |
|
|
rows="3" |
|
|
class="input w-full p-1.5 text-xs resize-y" |
|
|
required |
|
|
></textarea> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="negative-prompt" class="block text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide"> |
|
|
<i class="fas fa-ban mr-1.5 text-[var(--color-primary)]"></i>Negative Prompt |
|
|
</label> |
|
|
<textarea |
|
|
id="negative-prompt" |
|
|
name="negative-prompt" |
|
|
placeholder="Things to avoid in the video..." |
|
|
rows="2" |
|
|
class="input w-full p-1.5 text-xs resize-y" |
|
|
></textarea> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-size" class="block text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide"> |
|
|
<i class="fas fa-expand-arrows-alt mr-1.5 text-[var(--color-primary)]"></i>Video Size |
|
|
</label> |
|
|
<div class="flex flex-wrap gap-1.5 mb-1.5"> |
|
|
<button type="button" class="size-preset px-2 py-0.5 text-[10px] rounded border border-[var(--color-border)] hover:bg-[var(--color-bg-secondary)]" data-size="256x256">256×256</button> |
|
|
<button type="button" class="size-preset px-2 py-0.5 text-[10px] rounded border border-[var(--color-border)] hover:bg-[var(--color-bg-secondary)]" data-size="512x512">512×512</button> |
|
|
<button type="button" class="size-preset px-2 py-0.5 text-[10px] rounded border border-[var(--color-border)] hover:bg-[var(--color-bg-secondary)]" data-size="768x768">768×768</button> |
|
|
<button type="button" class="size-preset px-2 py-0.5 text-[10px] rounded border border-[var(--color-border)] hover:bg-[var(--color-bg-secondary)]" data-size="1024x1024">1024×1024</button> |
|
|
</div> |
|
|
<input |
|
|
type="text" |
|
|
id="video-size" |
|
|
value="512x512" |
|
|
placeholder="e.g., 256x256, 512x512, 1024x1024" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-seconds" class="block text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide"> |
|
|
<i class="fas fa-clock mr-1.5 text-[var(--color-primary)]"></i>Duration (seconds) |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="video-seconds" |
|
|
name="seconds" |
|
|
min="1" |
|
|
max="60" |
|
|
placeholder="Leave empty for default" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-fps" class="block text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide"> |
|
|
<i class="fas fa-film mr-1.5 text-[var(--color-primary)]"></i>FPS |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="video-fps" |
|
|
name="fps" |
|
|
min="1" |
|
|
max="60" |
|
|
value="16" |
|
|
placeholder="Frames per second" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-frames" class="block text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide"> |
|
|
<i class="fas fa-images mr-1.5 text-[var(--color-primary)]"></i>Number of Frames |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="video-frames" |
|
|
name="num_frames" |
|
|
min="1" |
|
|
max="500" |
|
|
placeholder="Leave empty for default" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-2"> |
|
|
<button type="button" id="advanced-toggle" class="w-full flex items-center justify-between px-2 py-1.5 text-xs rounded text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors"> |
|
|
<span><i class="fa-solid fa-sliders mr-1.5 text-[var(--color-primary)]"></i> Advanced Settings</span> |
|
|
<i class="fas fa-chevron-down text-[10px]" id="advanced-chevron"></i> |
|
|
</button> |
|
|
<div id="advanced-settings" class="hidden p-2 bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded pl-4 border-l-2 border-[var(--color-bg-secondary)] space-y-2"> |
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-steps" class="block text-xs text-[var(--color-text-secondary)]"> |
|
|
<i class="fas fa-step-forward mr-1.5 text-[var(--color-primary)]"></i>Steps |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="video-steps" |
|
|
name="step" |
|
|
min="1" |
|
|
max="100" |
|
|
placeholder="Leave empty for default" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-seed" class="block text-xs text-[var(--color-text-secondary)]"> |
|
|
<i class="fas fa-seedling mr-1.5 text-[var(--color-primary)]"></i>Seed |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="video-seed" |
|
|
name="seed" |
|
|
min="0" |
|
|
placeholder="Leave empty for random" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="video-cfg-scale" class="block text-xs text-[var(--color-text-secondary)]"> |
|
|
<i class="fas fa-sliders-h mr-1.5 text-[var(--color-primary)]"></i>CFG Scale |
|
|
</label> |
|
|
<input |
|
|
type="number" |
|
|
id="video-cfg-scale" |
|
|
name="cfg_scale" |
|
|
min="0" |
|
|
max="20" |
|
|
step="0.1" |
|
|
placeholder="Leave empty for default" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-2"> |
|
|
<button type="button" id="image-inputs-toggle" class="w-full flex items-center justify-between px-2 py-1.5 text-xs rounded text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors"> |
|
|
<span><i class="fa-solid fa-image mr-1.5 text-[var(--color-primary)]"></i> Image Inputs</span> |
|
|
<i class="fas fa-chevron-down text-[10px]" id="image-inputs-chevron"></i> |
|
|
</button> |
|
|
<div id="image-inputs-settings" class="hidden p-2 bg-[var(--color-bg-secondary)] border border-[var(--color-primary-border)]/20 rounded pl-4 border-l-2 border-[var(--color-bg-secondary)] space-y-2"> |
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="start-image" class="block text-xs text-[var(--color-text-secondary)]"> |
|
|
<i class="fas fa-play-circle mr-1.5 text-[var(--color-primary)]"></i>Start Image (img2video) |
|
|
</label> |
|
|
<input |
|
|
type="file" |
|
|
id="start-image" |
|
|
name="start_image" |
|
|
accept="image/*" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-1"> |
|
|
<label for="end-image" class="block text-xs text-[var(--color-text-secondary)]"> |
|
|
<i class="fas fa-stop-circle mr-1.5 text-[var(--color-primary)]"></i>End Image |
|
|
</label> |
|
|
<input |
|
|
type="file" |
|
|
id="end-image" |
|
|
name="end_image" |
|
|
accept="image/*" |
|
|
class="input p-1.5 text-xs w-full" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<button |
|
|
type="submit" |
|
|
id="generate-btn" |
|
|
class="w-full px-2 py-1.5 text-xs rounded text-[var(--color-bg-primary)] bg-[var(--color-primary)] hover:bg-[var(--color-primary)]/90 transition-colors font-medium" |
|
|
> |
|
|
<i class="fas fa-video mr-1.5"></i>Generate Video |
|
|
</button> |
|
|
</div> |
|
|
</form> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="flex-grow lg:w-3/4 flex flex-col min-h-0"> |
|
|
<div class="relative flex-1 min-h-0 overflow-y-auto"> |
|
|
|
|
|
<div id="loader" class="hidden absolute inset-0 flex items-center justify-center bg-[var(--color-bg-primary)]/80 rounded-xl z-10"> |
|
|
<div class="text-center"> |
|
|
<svg class="animate-spin h-10 w-10 text-[var(--color-primary)] mx-auto mb-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> |
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> |
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> |
|
|
</svg> |
|
|
<p class="text-xs text-[var(--color-text-secondary)]">Generating video...</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="result-placeholder" class="min-h-[400px] flex items-center justify-center flex-shrink-0"> |
|
|
<p class="text-xs text-[var(--color-text-secondary)] italic text-center">Your generated videos will appear here</p> |
|
|
</div> |
|
|
|
|
|
<div id="result" class="grid grid-cols-1 gap-4 pb-4"></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
document.getElementById('advanced-toggle').addEventListener('click', function() { |
|
|
const settings = document.getElementById('advanced-settings'); |
|
|
const chevron = document.getElementById('advanced-chevron'); |
|
|
settings.classList.toggle('hidden'); |
|
|
chevron.classList.toggle('fa-chevron-down'); |
|
|
chevron.classList.toggle('fa-chevron-up'); |
|
|
}); |
|
|
|
|
|
document.getElementById('image-inputs-toggle').addEventListener('click', function() { |
|
|
const settings = document.getElementById('image-inputs-settings'); |
|
|
const chevron = document.getElementById('image-inputs-chevron'); |
|
|
settings.classList.toggle('hidden'); |
|
|
chevron.classList.toggle('fa-chevron-down'); |
|
|
chevron.classList.toggle('fa-chevron-up'); |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelectorAll('.size-preset').forEach(button => { |
|
|
button.addEventListener('click', function() { |
|
|
const size = this.getAttribute('data-size'); |
|
|
document.getElementById('video-size').value = size; |
|
|
|
|
|
document.querySelectorAll('.size-preset').forEach(btn => { |
|
|
btn.classList.remove('bg-[var(--color-primary)]', 'text-white'); |
|
|
}); |
|
|
this.classList.add('bg-[var(--color-primary)]', 'text-white'); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelector('.size-preset[data-size="512x512"]').classList.add('bg-[var(--color-primary)]', 'text-white'); |
|
|
</script> |
|
|
|
|
|
</body> |
|
|
</html> |
|
|
|