MusicVisionAI MUSICVISIONAI·CONCEPT

Tamusique.Tonhistoire.

Transformeunechansonenhistoirecinématographique.

🎭Tonpersonnage

Photoderéférence Taphotosertderéférencevisuellepourlepersonnage principaldesscènes.

🎵Tamusique

Enattentedelamusique...

📝Paroles

🎬Créerlestoryboard
Enattente...

🎞️Storyboard

Wan2.1prêt.
/*===================================================== IMPORTGRADIO =====================================================*/ import{ Client, handle_file }from"https://cdn.jsdelivr.net/npm/@gradio/client/+esm"; /*===================================================== SPACES =====================================================*/ constWHISPER_SPACE= "hf-audio/whisper-large-v3"; constWAN_SPACE= "Wan-AI/Wan2.1"; /*===================================================== ELEMENTS =====================================================*/ constphotoInput= document.getElementById("photo"); constphotoPreview= document.getElementById("photoPreview"); constaudioInput= document.getElementById("audio"); constyoutubeInput= document.getElementById("youtube"); constlyricsInput= document.getElementById("lyrics"); consttranscribeBtn= document.getElementById("transcribeBtn"); consttranscribeStatus= document.getElementById("transcribeStatus"); conststoryboardBtn= document.getElementById("storyboardBtn"); conststoryboardStatus= document.getElementById("storyboardStatus"); conststoryboard= document.getElementById("storyboard"); constscenesContainer= document.getElementById("scenes"); constgenerateSceneBtn= document.getElementById("generateSceneBtn"); constwanStatus= document.getElementById("wanStatus"); constvideoContainer= document.getElementById("videoContainer"); /*===================================================== STATUS =====================================================*/ functionsetStatus( element, text, loading=false ){ element.textContent= text; element.classList.toggle( "loading", loading ); } /*===================================================== PHOTOPREVIEW =====================================================*/ photoInput.addEventListener( "change", ()=>{ constfile= photoInput.files[0]; if(!file){ photoPreview.classList.add( "hidden" ); return; } photoPreview.src= URL.createObjectURL(file); photoPreview.classList.remove( "hidden" ); } ); /*===================================================== TRANSCRIPTION =====================================================*/ functionextractText( value ){ if(!value){ return""; } if( typeofvalue==="string" ){ returnvalue; } if( Array.isArray(value) ){ for( constitemofvalue ){ constresult= extractText(item); if(result){ returnresult; } } } if( typeofvalue==="object" ){ if( typeofvalue.text==="string" ){ returnvalue.text; } if( typeofvalue.value==="string" ){ returnvalue.value; } if( typeofvalue.data==="string" ){ returnvalue.data; } } return""; } transcribeBtn.addEventListener( "click", async()=>{ constaudio= audioInput.files[0]; constyoutube= youtubeInput.value.trim(); if(!audio&&!youtube){ setStatus( transcribeStatus, "⚠️AjouteunfichieraudioouunlienYouTube." ); return; } transcribeBtn.disabled= true; try{ setStatus( transcribeStatus, "🔌ConnexionàWhisper...", true ); constwhisper= awaitClient.connect( WHISPER_SPACE ); letresult; if(audio){ setStatus( transcribeStatus, "🎙️Transcriptiondelamusique...", true ); constfile= awaithandle_file( audio ); result= awaitwhisper.predict( "/transcribe", [ file, "transcribe" ] ); }else{ setStatus( transcribeStatus, "📺TranscriptionYouTube...", true ); result= awaitwhisper.predict( "/yt_transcribe", [ youtube, "transcribe" ] ); } consttext= extractText( result ); if(!text){ thrownewError( "Whispern'aretournéaucuntexte." ); } lyricsInput.value= text; setStatus( transcribeStatus, "✅Transcriptionterminée." ); } catch(error){ console.error( "WHISPERERROR", error ); setStatus( transcribeStatus, "❌ErreurWhisper:\n\n"+ error.message ); } finally{ transcribeBtn.disabled= false; } } ); /*===================================================== STORYBOARD =====================================================*/ storyboardBtn.addEventListener( "click", ()=>{ constlyrics= lyricsInput.value.trim(); if(!lyrics){ setStatus( storyboardStatus, "⚠️Ajouted'abordlesparoles." ); return; } createStoryboard( lyrics ); storyboard.style.display= "block"; setStatus( storyboardStatus, "✅Storyboardcréé." ); } ); functioncreateStoryboard( lyrics ){ scenesContainer.innerHTML= ""; constparts= lyrics .split(/[.!?\n]+/) .map( x=>x.trim() ) .filter(Boolean); if(!parts.length){ addScene( "INTRO", "Introductioncinématographique." ); return; } consttotal= Math.min( parts.length, 6 ); for( leti=0; i ${escapeHTML(title)} ${escapeHTML(description)} `; scenesContainer.appendChild( scene ); } functionescapeHTML( text ){ returnString(text) .replace( /&/g, "&" ) .replace( //g, ">" ) .replace( /"/g, """ ) .replace( /'/g, "'" ); } /*===================================================== WAN:EXTRACTIONTASKID =====================================================*/ /* Leendpointofficielrenvoie: [task_id, status, button, refresh_button, cost_time, waiting_time] Lepremierélémentestdoncceluiquinousintéresse. */ functionextractWanTaskId( message ){ if(!message){ return""; } console.log( "WANMESSAGE:", message ); /* Cas: { type:"data", data:[...] } */ if( message.type==="data"&& Array.isArray(message.data) ){ constdata= message.data; /* Lepremierrésultatdoitêtre leStatei2v_task_id. */ constfirst= data[0]; if( typeoffirst==="string"&& first.trim() ){ returnfirst.trim(); } /* Certainsretourspeuventemballer lavaleur. */ if( first&& typeoffirst==="object" ){ if( first.task_id ){ returnString( first.task_id ); } if( first.value ){ returnString( first.value ); } } } return""; } /*===================================================== WAN:URLVIDÉO =====================================================*/ functionextractVideo( value ){ if(!value){ return""; } if( typeofvalue==="string" ){ if( value.startsWith("http://")|| value.startsWith("https://") ){ returnvalue; } return""; } if( Array.isArray(value) ){ for( constitemofvalue ){ constresult= extractVideo(item); if(result){ returnresult; } } } if( typeofvalue==="object" ){ constcandidates=[ value.url, value.video_url, value.path, value.value, value.data ]; for( constcandidate ofcandidates ){ constresult= extractVideo( candidate ); if(result){ returnresult; } } } return""; } /*===================================================== GÉNÉRATIONWAN =====================================================*/ generateSceneBtn.addEventListener( "click", generateScene ); asyncfunctiongenerateScene(){ constphoto= photoInput.files[0]; if(!photo){ setStatus( wanStatus, "⚠️Ajouted'abordunephoto." ); return; } generateSceneBtn.disabled= true; videoContainer.innerHTML= ""; try{ setStatus( wanStatus, "🔌ConnexionàWan2.1...", true ); constwan= awaitClient.connect( WAN_SPACE ); /* Onrécupèrelesinformations del'APIréelle. */ letapiInfo=null; try{ apiInfo= awaitwan.view_api(); console.log( "WANAPI:", apiInfo ); }catch(e){ console.warn( "Impossibledelireview_api()", e ); } setStatus( wanStatus, "📸Envoidelaphoto...", true ); constimage= awaithandle_file( photo ); /* ==================================================== PROMPTCINÉMATOGRAPHIQUE ==================================================== */ constprompt=` Createarealisticcinematicmusicvideoscene. Theuploadedimageisthevisualidentityreference forthemainmaleprotagonist. IMPORTANT: Theprotagonistisanactorinsidethestory. HeisNOTthesinger. HedoesNOTlip-sync. HedoesNOTperformthesong. Preservehisidentityandfacialappearance. Story: Theprotagonistisaloneatnightafteranemotional separation. Heslowlywalksthroughaquietcitystreet. Helooksthoughtfulandemotionallyaffected. Hetakeshisphonefromhispocketandlooksatit. Hecontinueswalkingalone. Emotion: loneliness,sadness,introspection. Visualstyle: photorealistic, cinematicmusicvideo, realistichumanmovement, naturalbodylanguage, naturalfacialexpression, cinematiccameramovement, realisticnightlighting, detailedenvironment, professionalcinematography. Donotchangetheidentityofthecharacter. Donotcreateanotherperson. Donotdistorttheface. Verticalcinematiccomposition. `.trim(); setStatus( wanStatus, "🎬EnvoidelascèneàWan2.1...", true ); /* ==================================================== APPELDUVRAIENDPOINTASYNC ==================================================== */ constjob= wan.submit( "/i2v_generation_async", [ prompt, image, true, -1 ] ); lettaskId= ""; letfinalMessage= null; /* ==================================================== LECTUREDESÉVÉNEMENTS ==================================================== */ forawait( constmessageofjob ){ console.log( "WANEVENT:", message ); /* ------------------------------- STATUSGRADIO ------------------------------- */ if( message.type==="status" ){ console.log( "WANSTATUS:", message ); if( message.stage==="error" ){ thrownewError( message.message|| "Wan2.1aretournéuneerreur." ); } setStatus( wanStatus, "⏳Wan2.1traitelademande...\n\n"+ ( message.stage|| "processing" ), true ); } /* ------------------------------- DATAGRADIO ------------------------------- */ if( message.type==="data" ){ finalMessage= message; constid= extractWanTaskId( message ); if(id){ taskId= id; break; } } } /* ==================================================== SIPASDETASKID ==================================================== */ if(!taskId){ console.error( "DERNIERMESSAGEWAN:", finalMessage ); /* IMPORTANT: Sileserveuraréellementrefusé latâche,lepremierrésultatestvide. */ thrownewError( "Wan2.1n'apasfournidetask_id.\n\n"+ "LeSpaceaprobablementrefusélatâche"+ "oun'apastransmislasortieState." ); } console.log( "TASKIDWAN:", taskId ); setStatus( wanStatus, "⏳Vidéoengénération...\n\n"+ "TaskID:"+ taskId, true ); /* ==================================================== ATTENTEDURÉSULTAT ==================================================== */ awaitwaitForWanVideo( wan, taskId ); } catch(error){ console.error( "WANERROR:", error ); setStatus( wanStatus, "❌Générationimpossible.\n\n"+ error.message ); } finally{ generateSceneBtn.disabled= false; } } /*===================================================== ATTENTEVIDÉO =====================================================*/ asyncfunctionwaitForWanVideo( wan, taskId ){ constmax= 120; for( letattempt=1; attempt<=max; attempt++ ){ setStatus( wanStatus, "⏳Wan2.1génèrelascène...\n\n"+ "Vérification:"+ attempt+ "/"+ max, true ); letresult= null; try{ /* LecodeofficielduSpaceappelle status_refreshavec: task_id task status */ result= awaitwan.predict( "/status_refresh", [ taskId, "i2v", false ] ); console.log( "WANREFRESH:", result ); constvideo= extractVideo( result ); if(video){ displayVideo( video ); setStatus( wanStatus, "✅Scènegénéréeavecsuccès." ); return; } } catch(error){ console.warn( "STATUSREFRESHERROR", error ); } awaitsleep( 5000 ); } thrownewError( "Lagénérationadépasséledélaid'attente." ); } /*===================================================== AFFICHAGEVIDÉO =====================================================*/ functiondisplayVideo( url ){ videoContainer.innerHTML= ""; consttitle= document.createElement( "div" ); title.style.marginTop= "20px"; title.style.fontWeight= "bold"; title.textContent= "🎥Premièrescènegénérée"; constvideo= document.createElement( "video" ); video.controls= true; video.playsInline= true; video.preload= "metadata"; video.src= url; videoContainer.appendChild( title ); videoContainer.appendChild( video ); } /*===================================================== SLEEP =====================================================*/ functionsleep( milliseconds ){ returnnewPromise( resolve=> setTimeout( resolve, milliseconds ) ); } console.log( "MusicVisionAIchargé—Wan2.1async." );