Democratizing Music Creation with an AI-powered Music Generation App
Published: 2024-05-07 12:45:23

Music creation has traditionally been a skill reserved for trained musicians or those with access to expensive recording studios and software. However, the digital age presents an opportunity to democratize music creation, making it accessible to a broader audience.

The challenge lies in developing a user-friendly and intuitive platform that empowers individuals, regardless of musical background, to generate unique and engaging music.

Here’s where our solution comes in:

We propose building a Music Generation App utilizing Lyzr Automata, Suno AI and AI-powered text generation. This app will allow users to:

Describe their desired music: Users can input text descriptions of their musical ideas, including desired genre, mood, instrumentation, and melody.
Generate unique music: The AI engine will analyze the user’s input and generate a corresponding musical piece based on advanced machine learning models.

**Setting Up the Environment**
**task.py**

```
pip install lyzr-automata requests streamlit python-dotenv
from lyzr_automata import Task
from lyzr_automata.ai_models.openai import OpenAIModel
from emails import send_email
from dotenv import load_dotenv
import os

load_dotenv()
api = os.getenv("OPENAI_API_KEY")
```
lyzr_automata: Likely provides functionalities for task management.
lyzr_automata.ai_models.openai: Provides access to the OpenAI model for text completion.
emails: Offers functions for sending emails.
dotenv: Enables loading environment variables.
os: Used for interacting with the operating system (potentially for environment variables).
load_dotenv() loads environment variables from a .env file.
One such variable, likely named OPENAI_API_KEY, is retrieved using os.getenv("OPENAI_API_KEY") and stored in the api variable. This API key is presumably used for authentication with the OpenAI service.

**OpenAI Model Setup:**

```
open_ai_text_completion_model = OpenAIModel(
    api_key=api,
    parameters={
        "model": "gpt-4-turbo-preview",
        "temperature": 0.2,
        "max_tokens": 1500,
    },
)
```
An OpenAIModel object is created, likely using the lyzr_automata.ai_models.openai library.

The api_key argument is set to the retrieved API key (api).
A dictionary named parameters defines settings for the OpenAI model:
model: Specifies the model to use (here, "gpt-4-turbo-preview").
temperature: Controls the randomness of the generated text (0.2 represents a lower randomness).
max_tokens: Sets the maximum number of tokens (words) the model can generate.

**email_task Function:**

```
def email_task(email):
    se = send_email(rec_email=email)

    Task(
        name="Send Email",
        tool=se,
        model=open_ai_text_completion_model,
        instructions=f"""Just write Below Script:
        Hello user,
        Your Music Is generated.Please Review that.
        """
    ).execute()
```

**email.py**

```
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
```
smtplib: Provides functionalities for interacting with SMTP servers (Simple Mail Transfer Protocol).
email.mime.multipart: Used for creating multipart email messages.
email.mime.text: Used for creating plain text email message bodies.
**send_emails Function:**

```
def send_emails(sender_email, receiver_email, subject, body_message, smtp_server, smtp_port, smtp_username, smtp_password):
    # Create a multipart message
    message = MIMEMultipart()
    message["From"] = sender_email
    message["To"] = receiver_email
    message["Subject"] = subject

    # Add body message
    message.attach(MIMEText(body_message, "plain"))

    # Connect to the SMTP server and send the email
    with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
        server.login(smtp_username, smtp_password)
        server.sendmail(sender_email, receiver_email, message.as_string())
```
This function takes eight arguments:
sender_email: Email address of the sender.
receiver_email: Email address of the recipient.
subject: Subject line of the email.
body_message: The main content of the email body.
smtp_server: Address of the SMTP server to use for sending the email.
smtp_port: Port number used by the SMTP server.
smtp_username: Username for authentication with the SMTP server.
smtp_password: Password for authentication with the SMTP server.
**Creating the Email Message:**
A MIMEMultipart object named message is created. This object represents the overall email structure, which can contain multiple parts (text, attachments, etc.).
The sender email address is set in the From header of the message.
The recipient email address is set in the To header of the message.
The subject line is set in the Subject header of the message.
Adding the Email Body:
A MIMEText object is created, containing the email body text (body_message).
The content type is set to “plain” to indicate plain text.
The MIMEText object is attached to the main message object using the .attach method.

```
def send_email(rec_email):
    sender_email = "harshilnariya7422@gmail.com"
    receiver_email = rec_email
    subject = "Lyzr Music Generation Completed!!"
    body_message = f"""Hello User,

    Thanks For Using Lyzr Music Generator.
    """
    smtp_server = "smtp.gmail.com"
    smtp_port = 465
    smtp_username = "harshilnariya7422@gmail.com"
    smtp_password = "qeyb shss cbxx xaam"

    send_emails(sender_email, receiver_email, subject, body_message, smtp_server, smtp_port, smtp_username, smtp_password)
```
This function serves as a wrapper around the send_emails function.
It defines default values for sender email, subject, body message, and SMTP server details (likely using a personal Gmail account in this example).
It calls the send_emails function with these pre-defined values and the recipient email address (rec_email) passed as an argument.
**App.py**

```
import os
import requests
import streamlit as st
import time
from task import email_task
from dotenv import load_dotenv
from PIL import Image

load_dotenv()
api = os.getenv('OPENAI_API_KEY')
```
os: Used for interacting with the operating system (potentially for environment variables).
requests: Used for making HTTP requests to external APIs.
streamlit as st: Provides functionalities for building the Streamlit web app interface.
time: Used for pausing execution with sleep.
task: Likely provides functionalities for background tasks (potentially email sending).
dotenv: Enables loading environment variables from a .env file.
PIL (not directly used in this snippet): Used for image processing (likely for the app logo).
load_dotenv(): Loads environment variables from a .env file.
One such variable, likely named SUNO_API_KEY, is retrieved using os.getenv('SUNO_API_KEY') and stored in the api_key variable. This API key is presumably used for authentication with the SUNO music generation API.
**Song Generation Functions:**

```
def get_song_id(title, tags, prompt):
    song_id_list = []
    url = "https://api.sunoaiapi.com/api/v1/gateway/generate/music"

    headers = {
        "api-key": api_key,
        "Content-Type": "application/json"
    }

    payload = {
        "title": title,
        "tags": tags,  # Music style
        "prompt": prompt
    }

    response = requests.post(url, headers=headers, json=payload)

    if response.status_code == 200:
        data = response.json()['data']

        for i in range(len(data)):
            song_id_list.append(response.json()['data'][i]['song_id'])

        return song_id_list


def generate_song(song_id):
    url_song = f"https://api.sunoaiapi.com/api/v1/gateway/feed/{song_id}"

    headers = {
        "api-key": api_key,
        "Content-Type": "application/json"
    }

    song_response = requests.get(url_song, headers=headers)

    if song_response.status_code == 200:
        data1 = song_response.json()['data']
        return data1
```
get_song_id(title, tags, prompt):
Takes user input for music title, tags (style), and prompt as arguments.
Constructs a URL for the SUNO API endpoint to generate music.
Defines headers with the API key and content type.
Creates a payload containing the title, tags, and prompt.
Sends a POST request using requests.post.
If successful (status code 200), extracts song IDs from the parsed JSON response.
Returns a list of song IDs.
generate_song(song_id):
Takes a song ID as input.
Constructs a URL for the SUNO API endpoint to retrieve song details.
Defines headers with the API key and content type.
Sends a GET request using requests.get.
If successful (status code 200), parses the JSON response and returns the song data.

**User Input:**

```
email = st.text_input("Email")
title = st.text_input("Title")
tag_list = ["Jazz", "Rock", "Pop", "Classical", "Hip-hop", "Electronic", "Country", "Blues", "Reggae", "Folk"]
tags = st.selectbox("Tags", options=tag_list)
prompt = st.text_area("Enter Prompt")
```
email = st.text_input("Email"): Creates a text input field for users to enter their email address.
title = st.text_input("Title"): Creates a text input field for users to enter the desired music title.
tag_list: Defines a list of music style options (tags).
tags = st.selectbox("Tags", options=tag_list): Creates a dropdown menu for users to select a music style tag.
prompt = st.text_area("Enter Prompt"): Creates a text area for users to enter a prompt describing the desired music.

**Generate Button and Music Playback:**

```
if st.button("Generate"):

    songs_url = []
    n = 0
    while n < 4:
        song_ids = get_song_id(title, tags, prompt)

        for song_id in song_ids:
            while True:
                songs = generate_song(song_id)
                if songs['status'] in ['streaming', 'complete']:
                    songs_url.append(songs)
                    n += 1
                    break
                else:
                    time.sleep(10)

    for s in songs_url:
        st.audio(s['audio_url'])

    email_task(email)
```
The song data (songs) is retrieved using generate_song(song_id).
The song’s audio URL is extracted from the songs data and appended to the songs_url list.
The counter n is incremented.
The inner loop breaks to move to the next song ID. — Otherwise, the code waits for 10 seconds using time.sleep(10) before checking the status again.
After iterating through song IDs:
A loop iterates through the songs_url list:
st.audio(s['audio_url']) plays each song using the retrieved audio URL.
email_task(email): Calls the email_task function (likely from the task.py file) with the user's email address, potentially to send a notification after music generation.

try it now: https://lyzr-music-generator.streamlit.app/

Github: https://github.com/harshit-lyzr/music_generator

For more information explore the website: [Lyzr](https://www.lyzr.ai/)