Open kevinrss01 opened 8 months ago
import axios from "axios"
import qs from "qs"
import fs from "fs"
import FormData from "form-data"
interface LalalAPIResponse {
status: "success" | "error"
result: Result
}
interface Result {
[key: string]: SplitDetail
archive: SplitDetail
batch: SplitDetail
}
interface SplitDetail {
status: "success" | "error"
name?: string
size?: number
duration?: number
stem?: string
splitter?: "orion" | "phoenix"
preview?: Preview | null
split?: any
player?: Player | null
task?: TaskDetail
error?: string
}
interface ArchiveBatchResult {
url: string
size: number
}
interface Preview {
duration: number
stem_track: string
stem_track_size: number
back_track: string
back_track_size: number
}
interface Player {
stem_track: string
stem_track_size: number
back_track: string
back_track_size: number
}
interface TaskDetail {
id: string[]
state: "success" | "error" | "progress" | "cancelled"
progress?: number
split_id?: string
error?: string
}
interface ApiUploadResponse {
status: "success" | "error"
id?: string
size?: number
duration?: number
expires?: number
error?: string
}
const licenseKey = "YOUR_LALAL_LICENSE_KEY"
const apiUrlBase = "https://www.lalal.ai/api"
let fileId: string = ""
const checkStatus = async (fileId: string) => {
let isCompleted = false
let statusData: null | LalalAPIResponse = null
while (!isCompleted) {
try {
const data = qs.stringify({ id: fileId })
const response = await axios.post(`${apiUrlBase}/check/`, data, {
headers: {
Authorization: `license ${licenseKey}`,
"Content-Type": "application/x-www-form-urlencoded",
},
})
if (response.data.status === "success") {
const taskState = response.data.result[fileId]?.task?.state
if (taskState === "success") {
isCompleted = true
if (response.data.result.archive) {
statusData = response.data
} else {
console.log(
"Split operation details:",
response.data.result[fileId].split
)
}
} else {
console.log("Task in progress, checking again in 1 second...")
await new Promise((resolve) => setTimeout(resolve, 1000))
}
} else {
console.error("Error checking status:", response.data.error)
throw new Error(response.data.error || "Status check failed")
}
} catch (error) {
console.error("An error occurred while checking status:", error)
throw error // Rethrow the error to exit the while loop and handle it outside
}
}
if (!statusData) throw new Error("No status data found")
return statusData
}
const processAudio = async (filePath: string): Promise<LalalAPIResponse> => {
try {
const form = new FormData()
form.append("file", fs.createReadStream(filePath), {
filename: filePath.split("/").pop(),
})
const uploadResponse = await axios.post<ApiUploadResponse>(
`${apiUrlBase}/upload/`,
form,
{
headers: {
...form.getHeaders(),
"Content-Disposition": `attachment; filename=${filePath
.split("/")
.pop()}`,
Authorization: `license ${licenseKey}`,
},
}
)
if (uploadResponse.data.status !== "success") {
console.error("Upload failed:", uploadResponse.data.error)
throw new Error("Upload failed")
}
if (!uploadResponse.data.id) throw new Error("No file ID")
fileId = uploadResponse.data.id
if (!fileId) throw new Error("No file ID")
console.log("File uploaded successfully, ID:", fileId)
interface SplitParams {
id: string
stem:
| "vocals"
| "drum"
| "bass"
| "piano"
| "electric_guitar"
| "acoustic_guitar"
| "synthesizer"
| "voice"
| "strings"
| "wind"
splitter: "orion" | "phoenix"
filter: 0 | 1 | 2
}
//Neural network selection option. Currently, the "Orion" neural network only supports the stems "vocal" and "voice"
// Split audio
const params: SplitParams[] = [
{
id: fileId,
stem: "voice",
splitter: "orion",
filter: 1,
},
]
const splitResponse = await axios.post(
`${apiUrlBase}/split/`,
qs.stringify({ params: JSON.stringify(params) }),
{
headers: {
...form.getHeaders(),
Authorization: `license ${licenseKey}`,
"Content-Type": "application/x-www-form-urlencoded",
},
}
)
if (splitResponse.data.status !== "success") {
console.error("Split operation failed:", splitResponse.data.error)
throw new Error("Split operation failed.")
}
console.log("Split operation initiated successfully")
return await checkStatus(fileId)
} catch (error) {
console.error("Process failed:", error)
throw new Error("Error while processing audio")
}
}
//Example of use
const filePath = "YOUR_FILE"
const getLalalResponse = async () => {
const lalalResponse = await processAudio(filePath)
const vocals = lalalResponse.result[fileId].split.stem_track
const accompaniment = lalalResponse.result[fileId].split.back_track
console.log("Vocals:", vocals)
console.log("Accompaniment:", accompaniment)
}
getLalalResponse()
I have noticed that the current TypeScript documentation in this repository, specifically for the lalal.ai API, could benefit from additional details and examples. The lalal.ai API provides powerful capabilities in splitting voices and music within an audio file. A more robust TypeScript guide can enhance developers' understanding and effectiveness when integrating this API into their applications.
To address this, I propose the addition of a detailed TypeScript code example that I have developed. This example encompasses various use-cases and illustrates how to properly implement and use the lalal.ai API features using TypeScript.