前言:

        我们正站在一个由人工智能驱动的时代变革节点之上,生成式人工智能(AIGC)的浪潮以前所未有的力量重塑着人机交互的边界。从文本、图像到代码、音频,AI的创造力正在各个领域迸发出惊人的火花。在语音技术这一关键赛道,大型语言模型与语音合成的结合,正将智能语音交互从简单的命令执行推向富有情感、表现力和逻辑深度的全新高度。

        在TTS(文本转语音)技术的发展历程中,我们经历了从参数合成、拼接合成到统计参数合成的演变。而如今,基于深度学习和端到端神经网络的生成式模型,正在将语音合成的质量推向一个全新的顶峰。MiniMax最新发布的语音模型,正是这一技术浪潮中的佼佼者。

        与传统的TTS系统不同,此类大模型驱动的解决方案的核心优势在于其极强的泛化能力和表现力。它能够通过海量数据的学习,捕捉到人类语音中细微的韵律、情感和风格特征,从而生成高度自然且富有表现力的语音,甚至在零样本(Zero-Shot)场景下模仿特定音色。

MiniMax地址链接:  https://www.minimaxi.com/platform_overview

初体验:

        首先要注册一个账号,注册后需要做一个实名认证,即可领取15元的体验劵(有效期:2个月)

这是使用教程,我们直接去创建账号

创建好并认证后是这样,认证后自动就有了15元的代金券,可以去代金券记录或余额中看

可以先到调试台体验,多种模型可以都体验一下

默认选择的是绅士青年音色

接下来直接输入台词,点击生成,会生成一个文件,播放即可

接入:

        体验过后觉得不错就可以尝试接入到我们的项目当中,这里给大家做一个大概步骤示范,相信大家也可以根据接入文档自己实现

文档地址:               https://platform.minimaxi.com/document/T2A%20V2?key=66719005a427f0c8a5701643

  步骤一:     根据文档,配置好接口地址,groupId以及apiKey

步骤二:     封装工具类

这里为测试,方法只给了两个变量,可以根据自己的需求添加参数,以提高工具类灵活性和可复用性,使其能够适应更多样的业务场景

package com.huayao.admin.common.utils;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.huayao.common.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import static com.huayao.admin.common.utils.ShiroUtils.getUserId;


/**
 * @ClassName MiniMaxUtils
 * @Description minimax语音合成
 * @Author wyh
 * @Date 2025/9/18 14:40
 */
@Slf4j
@Component
public class MiniMaxUtils {

    @Value("${miniMax.speech-02-hd}")
    private String speech02Hd;
    @Value("${miniMax.apiKey}")
    private String apiKey;
    @Value("${miniMax.groupID}")
    private String groupID;


    public String Speech02HD(String content,String voiceId){
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("model","speech-02-hd");
        map1.put("text",content);
        List<HashMap<String, Object>> timbreWeights = new ArrayList<>();
        HashMap<String, Object> map2 = new HashMap<>();
        map2.put("voice_id",voiceId);
        map2.put("weight",1);
        timbreWeights.add(map2);
        map1.put("timbre_weights",timbreWeights);
        HashMap<String, Object> voiceSetting = new HashMap<>();
        voiceSetting.put("voice_id",voiceId);
        voiceSetting.put("speed",1);
        voiceSetting.put("pitch",0);
        voiceSetting.put("vol",1);
        voiceSetting.put("latex_read",false);
        map1.put("voice_setting",voiceSetting);
        HashMap<String, Object> audioSetting = new HashMap<>();
        audioSetting.put("sample_rate",32000);
        audioSetting.put("bitrate",128000);
        audioSetting.put("format","mp3");
        map1.put("audio_setting",audioSetting);
        map1.put("language_boost","auto");
        HashMap<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + apiKey);
        headers.put("Content-Type", "application/json");
        try {
            String post = HttpClientUtil.post(speech02Hd, JSONObject.toJSONString(map1), headers);
            JSONObject jsonObject = JSONObject.parseObject(post);
            log.info("response body: {}", jsonObject);
            JSONObject data = jsonObject.getJSONObject("data");
            String audio = data.getString("audio");
            //将十六进制字符串解码
            String fileName="文件名";
            String outputFilePath = "文件目录/"+fileName ;
            File targetFile = new File(outputFilePath);
            File parentDir = targetFile.getParentFile();

// 检查父目录是否存在
            if (parentDir != null && !parentDir.exists()) {
                // 创建所有不存在的父目录,mkdirs() 会递归创建目录
                boolean dirsCreated = parentDir.mkdirs();
                if (dirsCreated) {
                    System.out.println("目录创建成功: " + parentDir.getAbsolutePath());
                } else {
                    // 处理创建失败的情况(例如权限不足)
                    System.err.println("错误:无法创建目录 " + parentDir.getAbsolutePath());
                    // 这里应该根据您的业务逻辑进行异常处理,可能是抛出异常或返回错误信息
                }
            }
            boolean success = saveAudioFromHex(audio, outputFilePath);
            if (success) {
                return "文件地址";
            } else {
                log.info("音频文件保存失败");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 将十六进制字符串解码为字节数组并保存为MP3文件
     * @param hexString 十六进制音频字符串
     * @param outputFilePath 输出文件路径
     * @return 是否成功保存
     * @throws IOException 如果文件写入失败
     */
    public static boolean saveAudioFromHex(String hexString, String outputFilePath) throws IOException {
        if (hexString == null || hexString.isEmpty()) {
            System.err.println("十六进制字符串为空");
            return false;
        }

        try {

            byte[] audioData = hexStringToByteArray(hexString);

            // 将字节数组写入文件
            try (FileOutputStream fos = new FileOutputStream(outputFilePath)) {
                fos.write(audioData);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            System.out.println("成功解码并保存音频,文件大小: " + audioData.length + " 字节");
            return true;

        } catch (IllegalArgumentException e) {
            System.err.println("十六进制字符串格式错误: " + e.getMessage());
            return false;
        }
    }

    /**
     * 适用于Java 8-16的十六进制字符串转字节数组方法
     * @param hexString 十六进制字符串
     * @return 字节数组
     */
    public static byte[] hexStringToByteArray(String hexString) {
        int len = hexString.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("十六进制字符串长度必须是偶数");
        }

        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 每两个字符转换为一个字节
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }
}

步骤三:编写控制层及业务层测试(跳过)

效果展示:

tts语音

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐