Spaces:
Running
Running
File size: 2,387 Bytes
a63c2c0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import {readJobStream} from '@/lib/stream';
import type {Download} from '@/lib/types';
import {encodeWav} from './audio';
/** Raised when the session has lapsed, so the studio can show sign-in without losing the project. */
export class SignedOut extends Error{}
type Call={signal:AbortSignal;status:(text:string)=>void};
/** Call a generation route and follow its progress stream to the result. */
export async function callEngine<T>(url:string,body:FormData|object,{signal,status}:Call):Promise<T>{
const init:RequestInit=body instanceof FormData
?{method:'POST',body,signal}
:{method:'POST',body:JSON.stringify(body),headers:{'Content-Type':'application/json'},signal};
const response=await fetch(url,init);
if(!response.ok){
const data=await response.json().catch(()=>({}));
if(response.status===401)throw new SignedOut(data.error||'Sign in again to continue.');
throw new Error(data.error||'That could not start.');
}
if(!response.body)throw new Error('The connection closed. Please try again.');
const result=await readJobStream(response.body,{status});
if(!result)throw new Error('The engine returned nothing. Please try again.');
return result as T;
}
/**
* Fetch an engine result through the app, which relays it with the user's
* token. Hugging Face's gateway drops some requests with a 5xx (sometimes an
* HTML error page), so those are retried; the finished job is not lost.
*/
export async function fetchResult(file:Download,signal:AbortSignal){
let last='';
for(let attempt=0;attempt<5;attempt++){
if(attempt)await new Promise(done=>setTimeout(done,2000*attempt));
signal.throwIfAborted();
const response=await fetch('/api/audio?url='+encodeURIComponent(file.url),{signal}).catch(error=>{
if(signal.aborted)throw error;
return null;
});
if(response?.ok)return response.arrayBuffer();
const text=response?await response.text().catch(()=>''):'';
// The relay's own messages are plain sentences; anything else is a gateway page.
last=text&&!/<html|<!doctype/i.test(text)&&text.length<300?text:'';
if(response&&response.status<500&&response.status!==429)break;
}
throw new Error(last||'Hugging Face’s servers had a hiccup while sending the result. Run it again; your project is safe.');
}
export function wavFile(buffer:AudioBuffer,name='selection.wav'){
return new File([encodeWav(buffer)],name,{type:'audio/wav'});
}
|