5
This commit is contained in:
parent
4220a7a231
commit
6c4fe526f8
@ -154,7 +154,10 @@ async function awaitResponse(aiRequestId, options = {}) {
|
|||||||
const interval = Math.max(Number(options.interval ?? 5), 1);
|
const interval = Math.max(Number(options.interval ?? 5), 1);
|
||||||
const deadline = Date.now() + Math.max(timeout, interval) * 1000;
|
const deadline = Date.now() + Math.max(timeout, interval) * 1000;
|
||||||
|
|
||||||
while (true) {
|
let isComplete = false;
|
||||||
|
let finalResponse = null;
|
||||||
|
|
||||||
|
while (!isComplete && Date.now() < deadline) {
|
||||||
const statusResp = await fetchStatus(aiRequestId, {
|
const statusResp = await fetchStatus(aiRequestId, {
|
||||||
headers: options.headers,
|
headers: options.headers,
|
||||||
timeout: options.timeout_per_call,
|
timeout: options.timeout_per_call,
|
||||||
@ -165,14 +168,15 @@ async function awaitResponse(aiRequestId, options = {}) {
|
|||||||
const data = statusResp.data || {};
|
const data = statusResp.data || {};
|
||||||
if (data && typeof data === "object") {
|
if (data && typeof data === "object") {
|
||||||
if (data.status === "success") {
|
if (data.status === "success") {
|
||||||
return {
|
isComplete = true;
|
||||||
|
finalResponse = {
|
||||||
success: true,
|
success: true,
|
||||||
status: 200,
|
status: 200,
|
||||||
data: data.response || data,
|
data: data.response || data,
|
||||||
};
|
};
|
||||||
}
|
} else if (data.status === "failed") {
|
||||||
if (data.status === "failed") {
|
isComplete = true;
|
||||||
return {
|
finalResponse = {
|
||||||
success: false,
|
success: false,
|
||||||
status: 500,
|
status: 500,
|
||||||
error: String(data.error || "AI request failed"),
|
error: String(data.error || "AI request failed"),
|
||||||
@ -181,19 +185,24 @@ async function awaitResponse(aiRequestId, options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return statusResp;
|
isComplete = true;
|
||||||
|
finalResponse = statusResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Date.now() >= deadline) {
|
if (!isComplete) {
|
||||||
return {
|
await sleep(interval * 1000);
|
||||||
success: false,
|
|
||||||
error: "timeout",
|
|
||||||
message: "Timed out waiting for AI response.",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await sleep(interval * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!finalResponse) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "timeout",
|
||||||
|
message: "Timed out waiting for AI response.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractText(response) {
|
function extractText(response) {
|
||||||
@ -306,7 +315,7 @@ function buildUrl(pathValue, baseUrl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveStatusPath(aiRequestId, cfg) {
|
function resolveStatusPath(aiRequestId, cfg) {
|
||||||
const basePath = (cfg.responsesPath || "").replace(/\/+$/, "");
|
const basePath = (cfg.responsesPath || "").replace(///+$/, "");
|
||||||
if (!basePath) {
|
if (!basePath) {
|
||||||
return `/ai-request/${encodeURIComponent(String(aiRequestId))}/status`;
|
return `/ai-request/${encodeURIComponent(String(aiRequestId))}/status`;
|
||||||
}
|
}
|
||||||
@ -481,4 +490,4 @@ module.exports = {
|
|||||||
awaitResponse,
|
awaitResponse,
|
||||||
extractText,
|
extractText,
|
||||||
decodeJsonFromResponse,
|
decodeJsonFromResponse,
|
||||||
};
|
};
|
||||||
@ -4,7 +4,7 @@ import { MenuAsideItem } from './interfaces'
|
|||||||
const menuAside: MenuAsideItem[] = [
|
const menuAside: MenuAsideItem[] = [
|
||||||
{
|
{
|
||||||
href: '/studio',
|
href: '/studio',
|
||||||
label: 'Music Studio',
|
label: 'AI Music Generator Creator',
|
||||||
icon: icon.mdiMusicNotePlus,
|
icon: icon.mdiMusicNotePlus,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -106,7 +106,7 @@ const Dashboard = () => {
|
|||||||
main>
|
main>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
href="/studio"
|
href="/studio"
|
||||||
label="Open Music Studio"
|
label="Open AI Music Generator"
|
||||||
icon={icon.mdiMusicNotePlus}
|
icon={icon.mdiMusicNotePlus}
|
||||||
color="info"
|
color="info"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -10,12 +10,12 @@ import { mdiMusic, mdiAccountKey, mdiPlayCircle, mdiCloudDownload, mdiAutoFix }
|
|||||||
import BaseIcon from '../components/BaseIcon';
|
import BaseIcon from '../components/BaseIcon';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const title = 'AI Music Studio Pro';
|
const title = 'AI Music Generator Creator Pro';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-slate-950 text-white min-h-screen font-sans selection:bg-emerald-500/30">
|
<div className="bg-slate-950 text-white min-h-screen font-sans selection:bg-emerald-500/30">
|
||||||
<Head>
|
<Head>
|
||||||
<title>{getPageTitle('Professional AI Music Generator')}</title>
|
<title>{getPageTitle('AI Music Generator Creator')}</title>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
@ -35,7 +35,7 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 className="text-5xl md:text-7xl font-extrabold tracking-tight mb-6 bg-clip-text text-transparent bg-gradient-to-b from-white to-slate-400">
|
<h1 className="text-5xl md:text-7xl font-extrabold tracking-tight mb-6 bg-clip-text text-transparent bg-gradient-to-b from-white to-slate-400">
|
||||||
Professional AI <br /> Music Creator
|
Professional AI <br /> Music Generator
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="max-w-2xl text-lg md:text-xl text-slate-400 mb-10 leading-relaxed">
|
<p className="max-w-2xl text-lg md:text-xl text-slate-400 mb-10 leading-relaxed">
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import { SelectField } from '../../components/SelectField';
|
|||||||
import BaseIcon from '../../components/BaseIcon';
|
import BaseIcon from '../../components/BaseIcon';
|
||||||
import FormField from '../../components/FormField';
|
import FormField from '../../components/FormField';
|
||||||
import NotificationBar from '../../components/NotificationBar';
|
import NotificationBar from '../../components/NotificationBar';
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const StudioPage = () => {
|
const StudioPage = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@ -36,26 +35,26 @@ const StudioPage = () => {
|
|||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
song_title: '',
|
song_title: '',
|
||||||
generation_mode: 'manual_lyrics',
|
generation_mode: 'auto_lyrics',
|
||||||
lyrics_text: '',
|
lyrics_text: '',
|
||||||
languageId: '',
|
language: '',
|
||||||
styleId: '',
|
style: '',
|
||||||
eraId: '',
|
era: '',
|
||||||
voiceId: '',
|
voice: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const validate = (values: any) => {
|
const validate = (values: any) => {
|
||||||
const errors: any = {};
|
const errors: any = {};
|
||||||
if (!values.song_title) errors.song_title = 'Required';
|
if (!values.song_title) errors.song_title = 'Required';
|
||||||
if (values.generation_mode === 'manual_lyrics' && !values.lyrics_text) errors.lyrics_text = 'Required';
|
if (values.generation_mode === 'manual_lyrics' && !values.lyrics_text) errors.lyrics_text = 'Required';
|
||||||
if (!values.languageId) errors.languageId = 'Required';
|
if (!values.language) errors.language = 'Required';
|
||||||
if (!values.styleId) errors.styleId = 'Required';
|
if (!values.style) errors.style = 'Required';
|
||||||
if (!values.eraId) errors.eraId = 'Required';
|
if (!values.era) errors.era = 'Required';
|
||||||
return errors;
|
return errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGenerateLyrics = async (values: any, setFieldValue: any) => {
|
const handleGenerateLyrics = async (values: any, setFieldValue: any) => {
|
||||||
if (!values.song_title || !values.styleId || !values.eraId) {
|
if (!values.song_title || !values.style || !values.era) {
|
||||||
alert('Please provide a title, style, and era first.');
|
alert('Please provide a title, style, and era first.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -81,9 +80,9 @@ const StudioPage = () => {
|
|||||||
song_title: values.song_title,
|
song_title: values.song_title,
|
||||||
generation_mode: values.generation_mode,
|
generation_mode: values.generation_mode,
|
||||||
lyrics_text: values.lyrics_text,
|
lyrics_text: values.lyrics_text,
|
||||||
languageId: values.languageId,
|
language: values.language,
|
||||||
styleId: values.styleId,
|
style: values.style,
|
||||||
eraId: values.eraId,
|
era: values.era,
|
||||||
status: 'queued',
|
status: 'queued',
|
||||||
requested_at: new Date().toISOString(),
|
requested_at: new Date().toISOString(),
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
@ -91,7 +90,7 @@ const StudioPage = () => {
|
|||||||
const songId = songResult.id || songResult.data?.id;
|
const songId = songResult.id || songResult.data?.id;
|
||||||
|
|
||||||
await dispatch(createJob({
|
await dispatch(createJob({
|
||||||
songId: songId,
|
song: songId,
|
||||||
job_type: 'music_composition',
|
job_type: 'music_composition',
|
||||||
status: 'queued',
|
status: 'queued',
|
||||||
progress_percent: 0,
|
progress_percent: 0,
|
||||||
@ -103,7 +102,7 @@ const StudioPage = () => {
|
|||||||
setTimeout(() => setGenerationSuccess(false), 5000);
|
setTimeout(() => setGenerationSuccess(false), 5000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to generate song:', error);
|
console.error('Failed to generate song:', error);
|
||||||
alert('Failed to start generation. Please check the logs.');
|
alert('Failed to start generation. Please check the permissions and logs.');
|
||||||
} finally {
|
} finally {
|
||||||
setIsGenerating(false);
|
setIsGenerating(false);
|
||||||
}
|
}
|
||||||
@ -150,7 +149,7 @@ const StudioPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HeadInstance>
|
<HeadInstance>
|
||||||
<title>{getPageTitle('AI Music Studio')}</title>
|
<title>{getPageTitle('AI Music Generator Creator')}</title>
|
||||||
</HeadInstance>
|
</HeadInstance>
|
||||||
|
|
||||||
<audio
|
<audio
|
||||||
@ -160,7 +159,7 @@ const StudioPage = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<SectionMain>
|
<SectionMain>
|
||||||
<SectionTitleLineWithButton icon={mdiMusic} title="AI Music Generation Studio" main>
|
<SectionTitleLineWithButton icon={mdiMusic} title="AI Music Generator Creator" main>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
href="/songs/songs-list"
|
href="/songs/songs-list"
|
||||||
label="Library"
|
label="Library"
|
||||||
@ -201,41 +200,41 @@ const StudioPage = () => {
|
|||||||
name="generation_mode"
|
name="generation_mode"
|
||||||
className="w-full bg-slate-800 border-slate-700 text-white rounded-lg p-3 focus:ring-emerald-500 border focus:border-emerald-500 outline-none transition-all"
|
className="w-full bg-slate-800 border-slate-700 text-white rounded-lg p-3 focus:ring-emerald-500 border focus:border-emerald-500 outline-none transition-all"
|
||||||
>
|
>
|
||||||
<option value="manual_lyrics">Manual Lyrics</option>
|
|
||||||
<option value="auto_lyrics">AI Auto-Lyrics (Full Song)</option>
|
<option value="auto_lyrics">AI Auto-Lyrics (Full Song)</option>
|
||||||
|
<option value="manual_lyrics">Manual Lyrics</option>
|
||||||
<option value="remix_reference">Remix Reference</option>
|
<option value="remix_reference">Remix Reference</option>
|
||||||
</Field>
|
</Field>
|
||||||
</FormField>
|
</FormField>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<FormField label="Language" error={errors.languageId && touched.languageId}>
|
<FormField label="Language" error={errors.language && touched.language}>
|
||||||
<SelectField
|
<SelectField
|
||||||
itemRef="languages"
|
itemRef="languages"
|
||||||
showField="language_name"
|
showField="language_name"
|
||||||
field={{ name: 'languageId', value: values.languageId }}
|
field={{ name: 'language', value: values.language }}
|
||||||
form={{ setFieldValue }}
|
form={{ setFieldValue }}
|
||||||
options={{ id: 'languageId' }}
|
options={{ id: 'language' }}
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<FormField label="Era" error={errors.eraId && touched.eraId}>
|
<FormField label="Era" error={errors.era && touched.era}>
|
||||||
<SelectField
|
<SelectField
|
||||||
itemRef="eras"
|
itemRef="eras"
|
||||||
showField="era_name"
|
showField="era_name"
|
||||||
field={{ name: 'eraId', value: values.eraId }}
|
field={{ name: 'era', value: values.era }}
|
||||||
form={{ setFieldValue }}
|
form={{ setFieldValue }}
|
||||||
options={{ id: 'eraId' }}
|
options={{ id: 'era' }}
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<FormField label="Style" error={errors.styleId && touched.styleId}>
|
<FormField label="Style" error={errors.style && touched.style}>
|
||||||
<SelectField
|
<SelectField
|
||||||
itemRef="music_styles"
|
itemRef="music_styles"
|
||||||
showField="style_name"
|
showField="style_name"
|
||||||
field={{ name: 'styleId', value: values.styleId }}
|
field={{ name: 'style', value: values.style }}
|
||||||
form={{ setFieldValue }}
|
form={{ setFieldValue }}
|
||||||
options={{ id: 'styleId' }}
|
options={{ id: 'style' }}
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
</div>
|
</div>
|
||||||
@ -244,9 +243,9 @@ const StudioPage = () => {
|
|||||||
<SelectField
|
<SelectField
|
||||||
itemRef="ai_voices"
|
itemRef="ai_voices"
|
||||||
showField="voice_name"
|
showField="voice_name"
|
||||||
field={{ name: 'voiceId', value: values.voiceId }}
|
field={{ name: 'voice', value: values.voice }}
|
||||||
form={{ setFieldValue }}
|
form={{ setFieldValue }}
|
||||||
options={{ id: 'voiceId' }}
|
options={{ id: 'voice' }}
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user