Todos os artigos

Cinco Motores de Música, Um Adaptador

Ouvir o artigo (experimental) · 09:02

00:00 / 09:02

Cinco blocos de formas diferentes à esquerda, cada um representando um fornecedor distinto, todos ligados a uma única tomada idêntica, com um botão de reprodução limpo à direita

Um potencial cliente pediu-me recentemente para avaliar a adição de geração de música por IA ao seu produto. Dois geradores, o utilizador escolhe um estilo, sai uma música. À superfície, é um pedido POST a um fornecedor e um botão de reprodução. Acabei por mapear grande parte do mercado para responder às perguntas dele, e o panorama revelou-se suficientemente interessante para eu construir a integração cinco vezes, contra cinco motores diferentes, para mostrar o que é realmente preciso. O resultado é uma pequena prova de conceito funcional: uma camada de adaptador, cinco fornecedores, uma CLI e uma UI de estúdio em Docker onde trocar de motor é um dropdown.

Eis o que esse exercício ensina.

A chamada de API é a parte fácil

A geração de música não é pedido e resposta. Uma faixa demora entre 30 segundos e alguns minutos a ficar pronta, por isso a verdadeira engenharia está em tudo o que rodeia a chamada: um modelo de jobs, webhooks ou polling com backoff, novas tentativas que toleram um endpoint de estado instável, timeouts que falham de forma bem visível e armazenamento. Sobretudo armazenamento. Os URLs dos fornecedores expiram: um apaga os ficheiros ao fim de 14 dias, outro ao fim de uma semana, um terceiro mata o link ao fim de 24 horas. Se o teu produto guarda o URL do fornecedor em vez do áudio, a biblioteca dos teus utilizadores apodrece em silêncio. A primeira regra de quem constrói sobre estas APIs é descarregar o ficheiro no momento em que um job termina com sucesso e colocá-lo em armazenamento que é teu.

Cinco fornecedores, cinco formatos diferentes

Os cinco motores que integrei, e o formato que cada um acabou por revelar:

  • Suno, revendido. A Suno não tem API pública própria, por isso o som favorito do mercado chega através de revendedores não oficiais. O que integrei exige um URL de callback mesmo que faças polling, responde aos polls em camelCase e aos webhooks em snake_case para os mesmos dados, e devolve duas variações da faixa por pedido.
  • MiniMax. Oficialmente suportado e, surpreendentemente, síncrono: a resposta HTTP da chamada de criação já contém a faixa terminada. A integração mais simples possível, e o link devolvido morre em 24 horas.
  • ACE-Step. Um modelo de pesos abertos com licença Apache, servido através de uma API de fila. A palavra do esquema de autenticação é literalmente "Key" em vez de "Bearer", e não existe campo de prompt: quer tags de estilo e letra, em que "[inst]" significa instrumental.
  • Treblo. Uma API oficial cujo endpoint de estado devolve uma string JSON e nada mais, cujo formato de saída por omissão é ogg, e que exige atribuição visível em qualquer produto virado para o utilizador. Além disso, mudou de nome (era Sonauto) e moveu endpoints a meio da minha pesquisa, o que pareceu o universo a sublinhar o argumento deste artigo.
  • Eleven Music. Síncrono como o MiniMax, mas o corpo da resposta são os bytes de áudio em bruto. Sem id de job, sem URL, nada para consultar. Ou apanhas os bytes, ou ficas sem eles.

Cinco fornecedores, cinco esquemas de autenticação, três modelos de assincronia, dois estilos de nomenclatura nas respostas e uma mudança de marca, tudo numa única semana. Nada disto deve chegar perto do código do teu produto.

O adaptador é a decisão de produto

A solução é antiga, aborrecida e funciona: colocar cada motor atrás de um único contrato. O meu são duas funções, criar um job e atualizar um job, ambas a devolver o mesmo formato normalizado. A orquestração, o armazenamento, a UI e a faturação nunca ficam a saber que motor correu. Adicionar um fornecedor é um ficheiro; trocar de fornecedor é uma string de configuração; e quando um revendedor desaparece de um dia para o outro, muda de marca ou surge finalmente uma API oficial, reconfiguras em vez de reescreveres.

Esta última frase não é hipotética. Os wrappers não oficiais assentam em terreno legalmente contestado enquanto os processos das editoras contra os criadores dos modelos seguem o seu curso, e o wrapper que integras hoje pode não existir com o mesmo nome no próximo trimestre. Vi isso acontecer a meio do projeto. O adaptador não é um floreado de arquitetura, é a apólice de seguro.

O que os advogados vão perguntar

As perguntas que realmente decidem que motor podes usar não têm nada a ver com qualidade de som:

  • Direitos comerciais. Um fornecedor atribui-te nos termos a propriedade dos resultados. Outro concede uso comercial apenas através de texto de marketing, sem qualquer licença contratual por trás. Um terceiro é totalmente omisso quanto aos clientes de API. São três posições de risco muito diferentes que parecem idênticas numa demonstração da funcionalidade.
  • Marcas de água. Um motor reserva-se o direito de aplicar marca de água quando entender. Outro oferece credenciais de conteúdo em regime de adesão voluntária. O modelo de pesos abertos não tem nenhuma. Se a marca do teu cliente não pode carregar uma marca de água, isto é um filtro, não uma preferência.
  • Atribuição. Um motor exige um crédito "Powered by" visível na tua UI. Isso é uma restrição de design de produto escondida numa página de termos.
  • Indemnização. Nenhum dos cinco te vai defender se uma faixa gerada ficar demasiado próxima da música de alguém. Esse risco fica contigo, o que na prática significa que os teus termos de serviço o passam aos teus utilizadores. Vale uma hora de advogado antes do lançamento, não depois.

Guardo tudo isto numa tabela comparativa no repositório, ao lado do código, porque a tabela muda o adaptador que ativas com muito mais frequência do que qualquer benchmark.

Ouve

Um prompt, direto pelo adaptador: uma música sobre um marido e uma mulher em Banff, a caminhar na margem do Lago Louise, neve nos picos, a apaixonarem-se outra vez. O que se segue é exatamente o que veio de volta, uma única geração, sem escolher a melhor de várias.

Treblo (Melodia v3), 2 minutos e 50:

Treblo (Melodia v3), primeira tentativa — 2 min 50. Canção gerada por IA a partir de um só prompt: um casal em Banff, a caminhar pela margem do lago Louise. Cantada por voz de mulher.

Uma nota destas duas gerações: o prompt pedia vozes masculinas quentes, e o Treblo cantou a primeira tentativa com voz de mulher. A segunda, abaixo, pôs a voz masculina nas primeiras palavras do prompt, e também saiu cantada por uma mulher. Este motor não expõe nenhum parâmetro de género vocal (o Suno via kie.ai tem um vocalGender literal), o que transforma um requisito de uma palavra numa lotaria. É uma lição que vale os créditos: quando um controlo é importante para o teu produto, escolhe um motor que o exponha como parâmetro, não como sugestão no prompt.

Treblo (Melodia v3), segunda tentativa — o mesmo prompt com a indicação de voz masculina nas primeiras palavras. Outra vez cantada por voz de mulher.

Esta secção cresce à medida que corro o mesmo prompt nos outros motores; as versões deles vão ficar aqui lado a lado. Cada resultado é gerado por IA, e os direitos sobre ele são regidos pelos termos do fornecedor.

Vê-o a funcionar

O estúdio ai-audio: seleção de motor e modelo à esquerda, gerações com leitores de forma de onda à direita

O que está por trás deste artigo é real e está a funcionar: uma edição CLI em Node do adaptador, sem dependências, e um estúdio FastAPI mais React em Docker onde os motores e os respetivos modelos são dropdowns, um motor simulado demonstra o pipeline inteiro sem chaves de API, e cada faixa terminada fica em armazenamento local no momento em que é concluída, porque a esta altura já sabes porquê. Guardo-o como um protótipo privado a funcionar, e a vantagem de um protótipo é que o próximo, o teu, se constrói muito mais depressa.

Se estás a avaliar geração de música, ou qualquer funcionalidade generativa que corre sobre o modelo de outra pessoa, o formato da resposta é o mesmo: o fornecedor é um plugin, o contrato é teu, e as partes aborrecidas, a fila, o armazenamento, os termos, são onde o projeto realmente vive. É também exatamente o tipo de projeto que ajudo equipas a lançar.

Perguntas a que este artigo responde

  • Porquê construir um adaptador em vez de chamar diretamente a API do fornecedor?

    Porque o fornecedor é a peça com mais probabilidade de mudar debaixo dos teus pés. A Suno não tem API pública própria, por isso o seu som chega através de revendedores não oficiais que assentam em terreno legalmente contestado enquanto correm os processos das editoras contra os criadores dos modelos, e o Treblo mudou de nome (era Sonauto) e moveu endpoints a meio desta pesquisa. Atrás de um único contrato, isso é uma string de configuração; ligado diretamente ao código do produto, é uma reescrita.

  • Durante quanto tempo é que as faixas geradas ficam disponíveis no URL do fornecedor?

    Não o suficiente para construir uma biblioteca em cima disso. Um fornecedor apaga os ficheiros ao fim de 14 dias, outro ao fim de uma semana e um terceiro mata o link ao fim de 24 horas, e o Eleven Music devolve os bytes de áudio em bruto, sem URL nenhum. Descarrega o ficheiro no momento em que o job termina com sucesso e coloca-o em armazenamento que é teu, ou a biblioteca dos teus utilizadores apodrece em silêncio.

  • Posso usar música gerada por IA comercialmente no meu produto?

    Depende inteiramente do motor que escolheste, e os cinco são diferentes. Um atribui-te nos termos a propriedade dos resultados, outro concede uso comercial apenas através de texto de marketing, sem qualquer licença contratual por trás, e um terceiro é totalmente omisso quanto aos clientes de API. Além disso, um reserva-se o direito de aplicar marca de água quando entender e outro exige um crédito visível na tua UI, e nenhum dos cinco te vai defender se uma faixa gerada ficar demasiado próxima da música de alguém.

  • Porque é que o motor ignorou o prompt e cantou a música com a voz errada?

    Porque um prompt é uma sugestão e não um controlo. O prompt da música de Banff pedia vozes masculinas quentes e o Treblo cantou a primeira tentativa com voz de mulher; pôr a voz masculina nas primeiras palavras do prompt deu uma segunda tentativa também cantada por uma mulher. O Treblo não expõe nenhum parâmetro de género vocal, enquanto o Suno via kie.ai tem um vocalGender literal, por isso quando um controlo é importante para o teu produto escolhe um motor que o exponha como parâmetro.