All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.whitemagic2014.tts.TTS Maven / Gradle / Ivy

There is a newer version: 1.2.3
Show newest version
package io.github.whitemagic2014.tts;

import io.github.whitemagic2014.tts.bean.Voice;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class TTS {

    private String EDGE_URL = "wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=6A5AA1D4EAFF4E9FB37E23D68491D6F4";
    private String EDGE_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.55";
    private String EDGE_ORIGIN = "chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold";
    private String voicesListUrl = "https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list?trustedclienttoken=6A5AA1D4EAFF4E9FB37E23D68491D6F4";

    private Map headers;

    private Voice voice;
    private String content;
    private Boolean findHeadHook = false;
    private String format = "audio-24khz-48kbitrate-mono-mp3";
    private String voicePitch = "+0Hz";
    private String voiceRate = "+0%";
    private String voiceVolume = "+0%";
    private String storage = "./storage";

    public TTS voicePitch(String voicePitch) {
        this.voicePitch = voicePitch;
        return this;
    }

    public TTS voiceRate(String voiceRate) {
        this.voiceRate = voiceRate;
        return this;
    }

    public TTS voiceVolume(String voiceVolume) {
        this.voiceVolume = voiceVolume;
        return this;
    }

    public TTS formatMp3() {
        this.format = "audio-24khz-48kbitrate-mono-mp3";
        return this;
    }

    public TTS formatOpus() {
        this.format = "webm-24khz-16bit-mono-opus";
        return this;
    }

    /**
     * This hook is more generic as it searches for the file header marker in the given file header and removes it. However, it may have lower efficiency.
     */
    public TTS findHeadHook() {
        this.findHeadHook = true;
        return this;
    }

    /**
     * default
     * This hook directly specifies the file header marker, which makes it faster. However, if the format changes, it may become unusable.
     */
    public TTS fixHeadHook() {
        this.findHeadHook = false;
        return this;
    }

    public TTS storage(String storage) {
        this.storage = storage;
        return this;
    }


    public TTS(Voice voice, String content) {
        this.voice = voice;
        this.content = content;
    }

    public TTS headers(Map headers) {
        this.headers = headers;
        return this;
    }

    public String trans() {
        if (voice == null) {
            throw new RuntimeException("please set voice");
        }
        String str = removeIncompatibleCharacters(content);
        if (StringUtils.isBlank(str)) {
            throw new RuntimeException("invalid content");
        }

        File storageFolder = new File(storage);
        if (!storageFolder.exists()) {
            storageFolder.mkdirs();
        }

        String dateStr = dateToString(new Date());
        String reqId = uuid();

        String audioFormat = mkAudioFormat(dateStr);
        String ssml = mkssml(voice.getLocale(), voice.getName());
        String ssmlHeadersPlusData = ssmlHeadersPlusData(reqId, dateStr, ssml);

        if (headers == null) {
            headers = new HashMap<>();
            headers.put("Origin", EDGE_ORIGIN);
            headers.put("Pragma", "no-cache");
            headers.put("Cache-Control", "no-cache");
            headers.put("User-Agent", EDGE_UA);
        }
        String fileName = reqId;
        if (format.equals("audio-24khz-48kbitrate-mono-mp3")) {
            fileName += ".mp3";
        } else if (format.equals("webm-24khz-16bit-mono-opus")) {
            fileName += ".opus";
        }
        try {
            TTSWebsocket client = new TTSWebsocket(EDGE_URL, headers, storage, fileName, findHeadHook);
            client.connect();
            while (!client.isOpen()) {
                // wait open
                Thread.sleep(100);
            }
            client.send(audioFormat);
            client.send(ssmlHeadersPlusData);
            while (client.isOpen()) {
                // wait close
            }
            return fileName;
        } catch (URISyntaxException | InterruptedException e) {
            e.printStackTrace();
            return null;
        }
    }


    private String mkAudioFormat(String dateStr) {
        return "X-Timestamp:" + dateStr + "\r\n" +
                "Content-Type:application/json; charset=utf-8\r\n" +
                "Path:speech.config\r\n\r\n" +
                "{\"context\":{\"synthesis\":{\"audio\":{\"metadataoptions\":{\"sentenceBoundaryEnabled\":\"false\",\"wordBoundaryEnabled\":\"true\"},\"outputFormat\":\"" + format + "\"}}}}\n";
    }


    private String mkssml(String locate, String voiceName) {
        return "" +
                "" +
                content + "";
    }


    private String ssmlHeadersPlusData(String requestId, String timestamp, String ssml) {
        return "X-RequestId:" + requestId + "\r\n" +
                "Content-Type:application/ssml+xml\r\n" +
                "X-Timestamp:" + timestamp + "Z\r\n" +
                "Path:ssml\r\n\r\n" + ssml;
    }


    private String dateToString(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (zzzz)");
        return sdf.format(date);
    }


    private String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    private String removeIncompatibleCharacters(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        StringBuilder output = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            int code = (int) c;
            if ((0 <= code && code <= 8) || (11 <= code && code <= 12) || (14 <= code && code <= 31)) {
                output.append(" ");
            } else {
                output.append(c);
            }
        }
        return output.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy