odyssey-frontend / src /lib /components /SoraGenerator.svelte
Fraser's picture
Initial backend setup with Gradio
7ac86fa
<script lang="ts">
import { generateSoraVideo } from '$lib/api/openai';
import type { SoraGenerationParams, SoraGenerationResult } from '$lib/types';
export let apiKey: string;
export let params: SoraGenerationParams;
export let onVideoGenerated: ((result: SoraGenerationResult) => void) | undefined = undefined;
export let onProgress: ((progress: number) => void) | undefined = undefined;
export let onError: ((error: string) => void) | undefined = undefined;
let isGenerating = false;
let progress = 0;
let error: string | null = null;
let statusText = '';
export async function generate() {
if (isGenerating) return;
isGenerating = true;
progress = 0;
error = null;
statusText = 'Creating video generation job...';
try {
const result = await generateSoraVideo(
apiKey,
params,
(p) => {
progress = p;
statusText = `Generating video: ${Math.round(p)}%`;
onProgress?.(p);
}
);
statusText = 'Video generated successfully!';
onVideoGenerated?.(result);
} catch (err) {
const errorMsg = err instanceof Error ? err.message : 'Unknown error';
error = errorMsg;
statusText = 'Generation failed';
onError?.(errorMsg);
} finally {
isGenerating = false;
}
}
</script>
{#if isGenerating || error}
<div class="generator-status">
{#if isGenerating}
<div class="status generating">
<div class="spinner"></div>
<p>{statusText}</p>
{#if progress > 0}
<div class="progress-bar">
<div class="progress-fill" style="width: {progress}%"></div>
</div>
{/if}
</div>
{/if}
{#if error}
<div class="status error">
<p>❌ {error}</p>
</div>
{/if}
</div>
{/if}
<style>
.generator-status {
padding: 1.5rem;
margin: 1rem 0;
}
.status {
padding: 1.5rem;
border-radius: 0.5rem;
text-align: center;
}
.status.generating {
background: #e3f2fd;
border: 1px solid #bbdefb;
color: #1565c0;
}
.status.error {
background: #ffebee;
border: 1px solid #ffcdd2;
color: #c62828;
}
.status p {
margin: 0;
font-weight: 500;
font-size: 1rem;
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 1rem;
border: 4px solid #bbdefb;
border-top-color: #1565c0;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.progress-bar {
width: 100%;
max-width: 400px;
height: 8px;
background: #bbdefb;
border-radius: 4px;
margin: 1rem auto 0;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: #1565c0;
transition: width 0.3s ease;
}
</style>