Designing an AI song generator: the UI states beyond the prompt box
Disclosure: I work on SingMyLyrics. This article was written with AI assistance. These are design recommendations, not a claim that every safeguard described below is already implemented in the product. A song generator
Disclosure: I work on SingMyLyrics. This article was written with AI assistance. These are design recommendations, not a claim that every safeguard described below is already implemented in the product.
A song generator can start with a single text box. The difficult part is explaining what happens after someone presses Generate, especially when they have pasted lyrics they care about and the request spends credits.
The product context is straightforward: someone brings original words, chooses a musical style and voice, and wants to hear an arrangement. The lyrics-to-song walkthrough shows that user-facing task. Here is how I would break down the interface contract behind it.
1. Model writing and generation as separate actions
An idea such as "a birthday song about our late-night road trips" is not the same input as a finished verse and chorus.
Give the composer an explicit mode: start from an idea, or use my lyrics. If an AI writes a draft, keep the draft editable before sending it to audio generation. Avoid making a user regenerate the audio just to correct a name in the text.
Treat a title as optional metadata where the provider permits it. If the provider requires one, validate that requirement before submission. The same applies to length limits: count the text that will actually be submitted, including section markers, rather than guessing from the visible number of lines.
2. Keep the user's text when a request fails
A failed request should leave the lyrics, title and musical choices intact. Store the current draft in component state and consider a local draft with a clear delete option for recovery after navigation.
Local persistence has a privacy tradeoff. Lyrics may contain personal stories. Tell users when a draft is stored on their device, avoid putting the text in URLs, and do not send full lyrics to analytics just to count form errors.
3. Separate job state from the browser's patience
The following is an illustrative UI model, not a provider API schema:
type GenerationView =
| { kind: "editing" }
| { kind: "submitting"; requestId: string }
| { kind: "pending"; jobId: string }
| { kind: "ready"; jobId: string; songId: string }
| { kind: "failed"; jobId?: string; message: string }
| { kind: "checking"; jobId: string };
checking matters. A browser that has stopped waiting does not prove that the provider stopped working. Keep the job identifier and offer a status refresh. Starting a new generation should be an explicit action because it may create another charge.
Use provider progress only when the provider actually reports it. Otherwise, an honest "Still generating" message is more useful than an invented percentage or a countdown that repeatedly resets.
4. Make credit handling a server responsibility
Show the credit cost before submission, but resolve the authoritative price and balance on the server. A disabled Generate button improves the interface; it does not prevent duplicate requests from another tab or a network retry.
A robust design needs a stable request identity, an atomic balance update and a durable record of the resulting job. Repeating the same request identity should retrieve the existing job rather than spend again. If the provider supports idempotency, pass an appropriate identity through that boundary too. Without that support, a timeout during submission needs reconciliation before resubmission.
Also distinguish a credit reservation, a final charge and a refund in the ledger. The appropriate policy depends on the provider's billing behavior. Whatever policy you choose, explain it in the interface and apply refunds once, even if a failure event arrives twice.
5. Make playback and download recoverable
"Job completed" and "this browser can play the file" are different checks. The player needs a visible loading state and a useful media-error state. Keep the generated song page reachable if playback fails.
If a provider returns temporary audio URLs, decide whether you will copy permitted assets into durable storage or refresh the URL through the server. Do not promise permanent downloads until the storage and retention policy supports that promise.
6. Test transitions, not just the happy path
Before polishing the waveform, try these scenarios:
- Double-click Generate and confirm that one intended request creates one job and one credit operation.
- Refresh while a job is pending and confirm that its status can be recovered.
- Let a browser request time out, then let the provider finish, and confirm that the finished song remains discoverable.
- Deliver the same completion or failure event twice and confirm that neither the charge nor refund is duplicated.
- Return a completed job with an unavailable media URL and confirm that the UI preserves the song record and offers recovery.
- Fail lyric generation and confirm that the original idea is still present.
These checks do not establish musical quality. They establish whether the application respects the user's input, time and credits. That is a useful foundation for any product that turns a prompt into a slower, paid generation job.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.