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 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, {
|
||||
headers: options.headers,
|
||||
timeout: options.timeout_per_call,
|
||||
@ -165,14 +168,15 @@ async function awaitResponse(aiRequestId, options = {}) {
|
||||
const data = statusResp.data || {};
|
||||
if (data && typeof data === "object") {
|
||||
if (data.status === "success") {
|
||||
return {
|
||||
isComplete = true;
|
||||
finalResponse = {
|
||||
success: true,
|
||||
status: 200,
|
||||
data: data.response || data,
|
||||
};
|
||||
}
|
||||
if (data.status === "failed") {
|
||||
return {
|
||||
} else if (data.status === "failed") {
|
||||
isComplete = true;
|
||||
finalResponse = {
|
||||
success: false,
|
||||
status: 500,
|
||||
error: String(data.error || "AI request failed"),
|
||||
@ -181,19 +185,24 @@ async function awaitResponse(aiRequestId, options = {}) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return statusResp;
|
||||
isComplete = true;
|
||||
finalResponse = statusResp;
|
||||
}
|
||||
|
||||
if (Date.now() >= deadline) {
|
||||
return {
|
||||
success: false,
|
||||
error: "timeout",
|
||||
message: "Timed out waiting for AI response.",
|
||||
};
|
||||
if (!isComplete) {
|
||||
await sleep(interval * 1000);
|
||||
}
|
||||
|
||||
await sleep(interval * 1000);
|
||||
}
|
||||
|
||||
if (!finalResponse) {
|
||||
return {
|
||||
success: false,
|
||||
error: "timeout",
|
||||
message: "Timed out waiting for AI response.",
|
||||
};
|
||||
}
|
||||
|
||||
return finalResponse;
|
||||
}
|
||||
|
||||
function extractText(response) {
|
||||
@ -306,7 +315,7 @@ function buildUrl(pathValue, baseUrl) {
|
||||
}
|
||||
|
||||
function resolveStatusPath(aiRequestId, cfg) {
|
||||
const basePath = (cfg.responsesPath || "").replace(/\/+$/, "");
|
||||
const basePath = (cfg.responsesPath || "").replace(///+$/, "");
|
||||
if (!basePath) {
|
||||
return `/ai-request/${encodeURIComponent(String(aiRequestId))}/status`;
|
||||
}
|
||||
@ -481,4 +490,4 @@ module.exports = {
|
||||
awaitResponse,
|
||||
extractText,
|
||||
decodeJsonFromResponse,
|
||||
};
|
||||
};
|
||||
@ -4,7 +4,7 @@ import { MenuAsideItem } from './interfaces'
|
||||
const menuAside: MenuAsideItem[] = [
|
||||
{
|
||||
href: '/studio',
|
||||
label: 'Music Studio',
|
||||
label: 'AI Music Generator Creator',
|
||||
icon: icon.mdiMusicNotePlus,
|
||||
},
|
||||
{
|
||||
|
||||
@ -106,7 +106,7 @@ const Dashboard = () => {
|
||||
main>
|
||||
<BaseButton
|
||||
href="/studio"
|
||||
label="Open Music Studio"
|
||||
label="Open AI Music Generator"
|
||||
icon={icon.mdiMusicNotePlus}
|
||||
color="info"
|
||||
/>
|
||||
|
||||
@ -10,12 +10,12 @@ import { mdiMusic, mdiAccountKey, mdiPlayCircle, mdiCloudDownload, mdiAutoFix }
|
||||
import BaseIcon from '../components/BaseIcon';
|
||||
|
||||
export default function Home() {
|
||||
const title = 'AI Music Studio Pro';
|
||||
const title = 'AI Music Generator Creator Pro';
|
||||
|
||||
return (
|
||||
<div className="bg-slate-950 text-white min-h-screen font-sans selection:bg-emerald-500/30">
|
||||
<Head>
|
||||
<title>{getPageTitle('Professional AI Music Generator')}</title>
|
||||
<title>{getPageTitle('AI Music Generator Creator')}</title>
|
||||
</Head>
|
||||
|
||||
{/* Hero Section */}
|
||||
@ -35,7 +35,7 @@ export default function Home() {
|
||||
</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">
|
||||
Professional AI <br /> Music Creator
|
||||
Professional AI <br /> Music Generator
|
||||
</h1>
|
||||
|
||||
<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 FormField from '../../components/FormField';
|
||||
import NotificationBar from '../../components/NotificationBar';
|
||||
import axios from 'axios';
|
||||
|
||||
const StudioPage = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@ -36,26 +35,26 @@ const StudioPage = () => {
|
||||
|
||||
const initialValues = {
|
||||
song_title: '',
|
||||
generation_mode: 'manual_lyrics',
|
||||
generation_mode: 'auto_lyrics',
|
||||
lyrics_text: '',
|
||||
languageId: '',
|
||||
styleId: '',
|
||||
eraId: '',
|
||||
voiceId: '',
|
||||
language: '',
|
||||
style: '',
|
||||
era: '',
|
||||
voice: '',
|
||||
};
|
||||
|
||||
const validate = (values: any) => {
|
||||
const errors: any = {};
|
||||
if (!values.song_title) errors.song_title = 'Required';
|
||||
if (values.generation_mode === 'manual_lyrics' && !values.lyrics_text) errors.lyrics_text = 'Required';
|
||||
if (!values.languageId) errors.languageId = 'Required';
|
||||
if (!values.styleId) errors.styleId = 'Required';
|
||||
if (!values.eraId) errors.eraId = 'Required';
|
||||
if (!values.language) errors.language = 'Required';
|
||||
if (!values.style) errors.style = 'Required';
|
||||
if (!values.era) errors.era = 'Required';
|
||||
return errors;
|
||||
};
|
||||
|
||||
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.');
|
||||
return;
|
||||
}
|
||||
@ -81,9 +80,9 @@ const StudioPage = () => {
|
||||
song_title: values.song_title,
|
||||
generation_mode: values.generation_mode,
|
||||
lyrics_text: values.lyrics_text,
|
||||
languageId: values.languageId,
|
||||
styleId: values.styleId,
|
||||
eraId: values.eraId,
|
||||
language: values.language,
|
||||
style: values.style,
|
||||
era: values.era,
|
||||
status: 'queued',
|
||||
requested_at: new Date().toISOString(),
|
||||
})).unwrap();
|
||||
@ -91,7 +90,7 @@ const StudioPage = () => {
|
||||
const songId = songResult.id || songResult.data?.id;
|
||||
|
||||
await dispatch(createJob({
|
||||
songId: songId,
|
||||
song: songId,
|
||||
job_type: 'music_composition',
|
||||
status: 'queued',
|
||||
progress_percent: 0,
|
||||
@ -103,7 +102,7 @@ const StudioPage = () => {
|
||||
setTimeout(() => setGenerationSuccess(false), 5000);
|
||||
} catch (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 {
|
||||
setIsGenerating(false);
|
||||
}
|
||||
@ -150,7 +149,7 @@ const StudioPage = () => {
|
||||
return (
|
||||
<>
|
||||
<HeadInstance>
|
||||
<title>{getPageTitle('AI Music Studio')}</title>
|
||||
<title>{getPageTitle('AI Music Generator Creator')}</title>
|
||||
</HeadInstance>
|
||||
|
||||
<audio
|
||||
@ -160,7 +159,7 @@ const StudioPage = () => {
|
||||
/>
|
||||
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiMusic} title="AI Music Generation Studio" main>
|
||||
<SectionTitleLineWithButton icon={mdiMusic} title="AI Music Generator Creator" main>
|
||||
<BaseButton
|
||||
href="/songs/songs-list"
|
||||
label="Library"
|
||||
@ -201,41 +200,41 @@ const StudioPage = () => {
|
||||
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"
|
||||
>
|
||||
<option value="manual_lyrics">Manual Lyrics</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>
|
||||
</Field>
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<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
|
||||
itemRef="languages"
|
||||
showField="language_name"
|
||||
field={{ name: 'languageId', value: values.languageId }}
|
||||
field={{ name: 'language', value: values.language }}
|
||||
form={{ setFieldValue }}
|
||||
options={{ id: 'languageId' }}
|
||||
options={{ id: 'language' }}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Era" error={errors.eraId && touched.eraId}>
|
||||
<FormField label="Era" error={errors.era && touched.era}>
|
||||
<SelectField
|
||||
itemRef="eras"
|
||||
showField="era_name"
|
||||
field={{ name: 'eraId', value: values.eraId }}
|
||||
field={{ name: 'era', value: values.era }}
|
||||
form={{ setFieldValue }}
|
||||
options={{ id: 'eraId' }}
|
||||
options={{ id: 'era' }}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Style" error={errors.styleId && touched.styleId}>
|
||||
<FormField label="Style" error={errors.style && touched.style}>
|
||||
<SelectField
|
||||
itemRef="music_styles"
|
||||
showField="style_name"
|
||||
field={{ name: 'styleId', value: values.styleId }}
|
||||
field={{ name: 'style', value: values.style }}
|
||||
form={{ setFieldValue }}
|
||||
options={{ id: 'styleId' }}
|
||||
options={{ id: 'style' }}
|
||||
/>
|
||||
</FormField>
|
||||
</div>
|
||||
@ -244,9 +243,9 @@ const StudioPage = () => {
|
||||
<SelectField
|
||||
itemRef="ai_voices"
|
||||
showField="voice_name"
|
||||
field={{ name: 'voiceId', value: values.voiceId }}
|
||||
field={{ name: 'voice', value: values.voice }}
|
||||
form={{ setFieldValue }}
|
||||
options={{ id: 'voiceId' }}
|
||||
options={{ id: 'voice' }}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user