299ad7d943
Co-authored-by: Copilot <copilot@github.com>
193 lines
6.3 KiB
HTML
193 lines
6.3 KiB
HTML
{% extends "base.html" %} {% block title %}Video Generation — All You Can GET
|
|
AI{% endblock %} {% block content %}
|
|
<div class="card">
|
|
<h1>Video Generation</h1>
|
|
|
|
<div class="tabs-container">
|
|
<div class="tabs">
|
|
<button class="tab-btn active" data-tab="text-to-video" type="button">
|
|
Text to video
|
|
</button>
|
|
<button class="tab-btn" data-tab="image-to-video" type="button">
|
|
Image to video
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Text-to-video -->
|
|
<div class="tab-panel active" id="tab-text-to-video">
|
|
<form method="post">
|
|
<input type="hidden" name="mode" value="text" />
|
|
|
|
<label for="model-t">Model</label>
|
|
{% if models %}
|
|
<select id="model-t" name="model" required>
|
|
{% for m in models %}
|
|
<option value="{{ m.id }}" {% if request.form.get('model', '') == m.id and request.form.get('mode','text')=='text' %}selected{% endif %}>{{ m.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% else %}
|
|
<input
|
|
id="model-t"
|
|
name="model"
|
|
type="text"
|
|
required
|
|
placeholder="e.g. openai/sora-2-pro"
|
|
value="{{ request.form.get('model', '') if request.form.get('mode','text')=='text' else '' }}"
|
|
/>
|
|
<p class="text-muted mt-1">No models available</p>
|
|
{% endif %}
|
|
|
|
<label for="prompt-t">Prompt</label>
|
|
<textarea
|
|
id="prompt-t"
|
|
name="prompt"
|
|
rows="4"
|
|
required
|
|
placeholder="Describe the video you want…"
|
|
>
|
|
{{ request.form.get('prompt', '') if request.form.get('mode','text')=='text' else '' }}</textarea
|
|
>
|
|
|
|
<label for="aspect-t">Aspect ratio</label>
|
|
<select id="aspect-t" name="aspect_ratio">
|
|
<option value="16:9">16:9 (landscape)</option>
|
|
<option value="9:16">9:16 (portrait)</option>
|
|
<option value="1:1">1:1 (square)</option>
|
|
</select>
|
|
|
|
<label for="res-t">Resolution</label>
|
|
<select id="res-t" name="resolution">
|
|
<option value="">Auto (default)</option>
|
|
<option value="480p">480p</option>
|
|
<option value="720p">720p</option>
|
|
<option value="1080p">1080p</option>
|
|
</select>
|
|
|
|
<label for="duration-t">Duration (seconds)</label>
|
|
<select id="duration-t" name="duration_seconds">
|
|
<option value="4">4s</option>
|
|
<option value="8">8s</option>
|
|
<option value="12" selected>12s</option>
|
|
<option value="16">16s</option>
|
|
<option value="20">20s</option>
|
|
</select>
|
|
|
|
<button type="submit">Generate video</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Image-to-video -->
|
|
<div class="tab-panel" id="tab-image-to-video">
|
|
<form method="post">
|
|
<input type="hidden" name="mode" value="image" />
|
|
|
|
<label for="model-i">Model</label>
|
|
{% if models %}
|
|
<select id="model-i" name="model" required>
|
|
{% for m in models %}
|
|
<option value="{{ m.id }}" {% if request.form.get('model', '') == m.id and request.form.get('mode')=='image' %}selected{% endif %}>{{ m.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% else %}
|
|
<input
|
|
id="model-i"
|
|
name="model"
|
|
type="text"
|
|
required
|
|
placeholder="e.g. openai/sora-2-pro"
|
|
value="{{ request.form.get('model', '') if request.form.get('mode')=='image' else '' }}"
|
|
/>
|
|
<p class="text-muted mt-1">No models available</p>
|
|
{% endif %}
|
|
|
|
<label for="image_url">Source image URL</label>
|
|
<input
|
|
id="image_url"
|
|
name="image_url"
|
|
type="url"
|
|
required
|
|
placeholder="https://example.com/photo.jpg"
|
|
value="{{ request.form.get('image_url', '') }}"
|
|
/>
|
|
|
|
<label for="prompt-i">Motion prompt</label>
|
|
<textarea
|
|
id="prompt-i"
|
|
name="prompt"
|
|
rows="3"
|
|
required
|
|
placeholder="Describe the motion or transformation…"
|
|
>
|
|
{{ request.form.get('prompt', '') if request.form.get('mode')=='image' else '' }}</textarea
|
|
>
|
|
|
|
<label for="aspect-i">Aspect ratio</label>
|
|
<select id="aspect-i" name="aspect_ratio">
|
|
<option value="16:9">16:9 (landscape)</option>
|
|
<option value="9:16">9:16 (portrait)</option>
|
|
<option value="1:1">1:1 (square)</option>
|
|
</select>
|
|
|
|
<label for="res-i">Resolution</label>
|
|
<select id="res-i" name="resolution">
|
|
<option value="">Auto (default)</option>
|
|
<option value="480p">480p</option>
|
|
<option value="720p">720p</option>
|
|
<option value="1080p">1080p</option>
|
|
</select>
|
|
|
|
<label for="duration-i">Duration (seconds)</label>
|
|
<select id="duration-i" name="duration_seconds">
|
|
<option value="4">4s</option>
|
|
<option value="8">8s</option>
|
|
<option value="12" selected>12s</option>
|
|
<option value="16">16s</option>
|
|
<option value="20">20s</option>
|
|
</select>
|
|
|
|
<button type="submit">Generate video from image</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
{% if error %}
|
|
<div class="alert alert-error mt-2">{{ error }}</div>
|
|
{% endif %} {% if result %}
|
|
<div class="result">
|
|
<h2>Video job</h2>
|
|
<p>Job ID: <code>{{ result.db_id or result.id }}</code></p>
|
|
{% if result.status in ('queued', 'processing') and result.db_id %}
|
|
<div id="video-poll-status" data-video-id="{{ result.db_id }}">
|
|
<p>
|
|
<span id="poll-status-text"
|
|
>Status: <strong>{{ result.status }}</strong></span
|
|
>
|
|
— checking for updates every 5 s…
|
|
</p>
|
|
<div id="poll-video-container"></div>
|
|
<button
|
|
id="cancel-video-btn"
|
|
class="mt-2 px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-md text-sm"
|
|
>
|
|
Cancel Job
|
|
</button>
|
|
<p id="cancel-msg" class="text-sm mt-2 hidden"></p>
|
|
</div>
|
|
{% elif result.video_url %}
|
|
<video
|
|
src="{{ result.video_url }}"
|
|
controls
|
|
class="generated-video"
|
|
></video>
|
|
{% elif result.status == 'failed' %}
|
|
<div class="alert alert-error">
|
|
Generation failed: {{ result.error or 'Unknown error' }}
|
|
</div>
|
|
{% else %}
|
|
<p>Status: <strong>{{ result.status }}</strong></p>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|