jing332 / tts-server-go

微软TTS服务转发,以便在阅读APP中通过网络导入方式收听微软TTS / Edge大声朗读
378 stars 70 forks source link

在阅读app网络导入无反应直接没了 #8

Closed w970028619 closed 1 year ago

w970028619 commented 1 year ago

不知道为什么安卓阅读app 二维码导入和网络导入方式都没有tts出来,点击导入之后直接就消失了,什么都没出现,然后这个功能就是电脑当作转发服务器,然后手机请求电脑 电脑在发送到微软来请求语音是吗? ios有个爱阅书香,不知道怎么导入,请求作者帮帮我,很困扰

jing332 commented 1 year ago

请在阅读的朗读引擎设置中选择网络导入此链接。

你当成书源导入了吧?

对,本程序作用就是简化请求方式,方便阅读调用。

w970028619 commented 1 year ago

没有当成书源导入。按照你的说明 在引擎设置里网络导入了 但是没有显示

jing332 commented 1 year ago

那不知道了,是你自己的问题。

w970028619 commented 1 year ago

好吧 我用了两部手机测试 一个是安卓系统一个ios系统。都是在语音设置里网络导入。把edge接口的连接复制进去。然后确定就没反应了 不过还是感谢作者。这个软件能支持爱阅书香吗? http的连接方式就是自定义tts

jing332 commented 1 year ago

既然是安卓系统推荐用TTS Server Android,直接通过系统TTS播放,还可设置旁白对话朗读。

w970028619 commented 1 year ago

嗯嗯 安卓已经下载了。就是想在ios上用 感谢作者白忙之中回复我。不折腾了 还是弄不了 感谢

jing332 commented 1 year ago

你说的软件,只要能支持POST请求就可以

w970028619 commented 1 year ago

支持post请求 但是我该如何找到网址啊 按f12是元素里面找吗?

w970028619 commented 1 year ago

支持post求情 但是我该如何找到网址 按f12打开开发者工具后 再元素栏里面吗

jing332 commented 1 year ago

7

jing332 commented 1 year ago

有具体文档么?我帮你看看

w970028619 commented 1 year ago
let token = localStorage.getItem("token")
document.getElementsByName('token')[0].value = token

let voices = [];
fetch('https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list?trustedclienttoken=6A5AA1D4EAFF4E9FB37E23D68491D6F4')
    .then(response => {
        if (response.status === 200) {
            return response.json();
        } else {
            return response.text().then(text => Promise.reject(text));
        }
    }).then(data => {
    voices = data;
    refreshVoice();
}).catch(reason => {
    alert(reason);
});

function refreshVoice() {
    let langElement = document.getElementsByName('language')[0]
    langElement.innerHTML = ''
    let localeList = new Map()
    voices.forEach(item => {
        let friendlyName = item['FriendlyName']
        let locale = item['Locale']
        if (!localeList.has(locale)) {
            localeList.set(locale, cnLocalLanguage[locale] || friendlyName.split('- ')[1])
        }
    });
    //排序语言列表
    const sortMap = new Map([...localeList.entries()].sort((a, b) => a[1].localeCompare(b[1])));
    sortMap.forEach((value, key) => {
        let option = document.createElement('option');
        option.value = key
        option.innerText = value
        if (key === "zh-CN") option.selected = true
        langElement.appendChild(option)
    })

    updateLanguageConfig()
}

function updateLanguageConfig() {
    let voiceElement = document.getElementsByName('voiceName')[0];
    let language = document.getElementsByName('language')[0].value
    voiceElement.innerHTML = ''
    let voiceMap = new Map()
    voices.forEach(function (value, key) {
        if (value['locale'] === language) {
            let pro = value['properties']
            voiceMap.set(value['shortName'], (pro['LocalName'] ?? pro['ShortName']) + '-' + pro['LocaleDescription'])
        }
    })

    updateVoiceConfig()
}

function updateVoiceConfig() {
    let voiceElement = document.getElementsByName('voiceName')[0];
    let language = document.getElementsByName('language')[0].value;
    voiceElement.innerHTMl = '';
    voices.forEach(value => {
        if (value['Locale'] === language) {
            let option = document.createElement('option');
            let shortName = value['ShortName']
            option.value = shortName
            option.innerText = cnLocalVoice[shortName] + "(" + shortName + ")" || shortName;
            voiceElement.append(option)
        }
    })
    updateConfigName()
}

function updateConfigName() {
    let voice = document.getElementsByName('voiceName')[0].value;
    document.getElementsByName('name')[0].value = '大声朗读1233(' + voice + ')';
}

function createSSML(text, voiceName) {
    return '\
    <speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US">\
      <voice name="' + voiceName + '">\
          <prosody rate="0%" pitch="0%">\
              ' + text + '\
          </prosody >\
      </voice >\
    </speak > ';
}

function preview() {
    let headers = {'Content-Type': 'text/plain'};
    let voiceName = document.getElementsByName('voiceName')[0].value;
    let previewText = document.getElementsByName('previewText')[0].value;
    let ssml = createSSML(previewText, voiceName)
    let voiceFormat = document.getElementsByName('voiceFormat')[0].value;
    let token = document.getElementsByName('token')[0].value;

    headers['Format'] = voiceFormat
    localStorage.setItem("token", token)
    if (token) headers['Token'] = token

    let button = document.getElementById('previewButton')
    let textInfo = document.getElementById('audioInfoLabel')
    button.disabled = true
    textInfo.innerText = "大小: 0kb | 耗时: 0ms"
    let startTime = Date.now()
    let ctx = new AudioContext();
    fetch('/api/ra', {
        method: 'post',
        headers: headers,
        body: ssml
    }).then(response => {
        if (response.status === 200) {
            let audioSize = response.headers.get("Content-Length")
            let elapsedTme = Date.now() - startTime
            textInfo.innerText =
                `大小: ${unitConversion(audioSize)} | 耗时: ${elapsedTme}ms`
            return response.arrayBuffer()
        } else {
            return response.text().then(text => Promise.reject(text));
        }
    }).then(arrayBuffer => ctx.decodeAudioData(arrayBuffer))
        .then(audio => {
            let player = ctx.createBufferSource();
            player.buffer = audio;
            player.connect(ctx.destination);
            player.start(ctx.currentTime);
        })
        .catch(reason => {
            alert(reason);
        })
        .finally(() => {
            button.disabled = false
        });
}

function createLegadoUrl() {
    let name = document.getElementsByName('name')[0].value;
    let voiceName = document.getElementsByName('voiceName')[0].value;
    let voiceFormat = document.getElementsByName('voiceFormat')[0].value;
    let token = document.getElementsByName('token')[0].value;
    let interval = localStorage.getItem('interval') || 5000
    let url = window.location.protocol + '//' + window.location.host + '/api/legado?api=' + encodeURI(window.location.protocol + '//' + window.location.host + '/api/ra')
        + '&name=' + encodeURI(name)
        + '&voiceName=' + voiceName
        + '&voiceFormat=' + voiceFormat
        + '&token=' + token
        + '&concurrentRate=' + interval
    let modal = new bootstrap.Modal(document.getElementById('legadoUrlModal'))
    document.getElementById('legadoUrlQRCode').innerHTML = ''
    /* 折叠二维码 */
    let bsCollapse = new bootstrap.Collapse(document.getElementById('qrCodeCollapse'), {
        toggle: false
    })
    bsCollapse.hide()
    document.getElementById('legadoUrl').value = url;
    modal.show();
    localStorage.setItem("token", token)
}
jing332 commented 1 year ago

额?你发网页源码干嘛

w970028619 commented 1 year ago

那应该去哪里找呀

jing332 commented 1 year ago

这我就不知道了,软件总会提供使用文档给用户吧?

w970028619 commented 1 year ago

此功能需要一定的专业知识,你需要从某个平台申请语音合成的API接口,或者是从某个地方得到合成接口。一般情况下,是一个HTTP请求后,得到一段语音数据。

特殊字段名:playData表示最终取得的语音数据 特殊响应名称:ResponseData来表示整个响应结果 前置步骤的意思是:第一次请求请问合成时才需要用到,之后再次请求合成时,是不会再调用的。如先同登陆,认证后才可以调用语音合成接口一样。 图片

可以使用ResponseData来表示整个响应结果,比如请求后得到的数据全部是语音,则可以添加解析字段:playData=ResponseData

情形1 调用http://aa.xx.com/tts?text=要合成的数据&volume=100 得到了一段语音数据

则在爱阅书香可以这样设置: 1地址输入:http://aa.xx.com/tts?text=%@&volume=100 2解析字段输入:playData=ResponseData 测试发音效果

情形2 调用http://aa.xx.com/tts?text=要合成的数据&volume=100 得到了一个数据,数据中包括了一个语音合成的地址。再次访问得到的语音合成地址后,才能得到最终的语音数据

则在爱阅书香可以这样设置: 1地址输入:http://aa.xx.com/tts?text=%@&volume=100 2解析字段输入:audioUrl=@json:xxx, 其中audioUrl表示一个变量,方便后面使用,@json:则与书源教程中一致,表示如何解析出数据 3添加一个TTS语音步骤 4在第二个步骤中的地址输入:@json:audioUrl 表示从上一个结果中取得地址 5在第二步骤的解析字段输入:playData=ResponseData 6测试发音效果

情形3 需要先认证时,请在第一个步骤中输入认证的HTTP及参数,之前根据情况,与情形1或情形2类似

更多情形请自行多多研究哦,有问题请加群一起谈论。群号在公众号iosRead或是打开爱阅书香-设置-关于爱阅书香

jing332 commented 1 year ago

不成,貌似不支持POST。 IOS好像有个 源阅读APP,这个我从酷安得知可以导入阅读APP的TTS链接

w970028619 commented 1 year ago

源阅读 我通过自签安装了 但是在语音设置里导入大声朗读接口没有反应 语音设置 右上角菜单 然后通过网络导入 和通过二维码导入, 导入后没有任何显示 在安卓系统的阅读app也是一样的 没有引擎出来 貌似问题又回到了开始

jing332 commented 1 year ago

这……我没设备也无法,你可以去酷安阅读APP话题下问问

w970028619 commented 1 year ago

非常感谢您 一直在帮助我,非常感激 谢谢