<script lang="ts"> import { density, composing, style, temperature, notesImage, notesTokens, audioBlob } from '$lib/stores'; import { styles } from './config.json'; const updateMetadata = () => { if ('mediaSession' in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ title: `${styles[$style]} Composition`, artist: 'AI Guru Composer', album: 'Hugging Face', artwork: [ { src: 'static/hugging-face-headphones.png', sizes: '512x512', type: 'image/png', }, ], }); } }; const createTask = async ({ music_style, density, temperature, }: { music_style: string; density: string; temperature: string; }) => { const taskResponse = await fetch('task/create', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ music_style, density, temperature, }), }); if (!taskResponse.ok || !taskResponse.headers.get('content-type')?.includes('application/json')) { throw new Error(`Unable to create composition: [${taskResponse.status}] ${await taskResponse.text()}`); } const task = await taskResponse.json(); return task; }; const pollTask = async (task: Record<string, any>) => { const taskResponse = await fetch(`task/poll?task_id=${task.task_id}`); if (!taskResponse.ok || !taskResponse.headers.get('content-type')?.includes('application/json')) { throw new Error(`Unable to create composition: [${taskResponse.status}] ${await taskResponse.text()}`); } return await taskResponse.json(); }; const longPollTask = async (task: Record<string, any>, interval = 1_000, max = 100): Promise<Record<string, any>> => { task = await pollTask(task); if (task.status === 'completed' || task.status === 'failed' || (max && task.poll_count > max)) { return task; } await new Promise((resolve) => setTimeout(resolve, interval)); return await longPollTask(task, interval, max); }; const compose = async () => { $composing = true; try { const task = await createTask({ music_style: $style, density: $density, temperature: $temperature, }); const completedTask = await longPollTask(task); const { audio, image, tokens } = completedTask.output; $audioBlob = audio; $notesImage = image; $notesTokens = tokens; updateMetadata(); } catch (err) { console.error(err); } finally { $composing = false; } }; </script> <button disabled={$composing} on:click={compose}> {#if $composing} Composing... {:else} Compose <img src="static/wand.svg" alt="Magic wand" /> {/if} </button> <style> button { display: block; font-size: 1.2rem; font-family: 'Lato', sans-serif; font-weight: 700; color: hsl(0 0% 97%); background: transparent; border: 3px solid hsl(0 0% 97%); border-radius: 0.375rem; padding: 0.5rem 1rem; cursor: pointer; margin: 1rem auto 2rem; } button[disabled] { border-color: hsl(0 0% 50%); color: hsl(0 0% 50%); cursor: initial; } img { height: 1.2rem; aspect-ratio: 1 / 1; vertical-align: bottom; } @media (min-width: 900px) { button { margin-top: 0; } } </style>