谷歌文字转语音 API

Posted

技术标签:

【中文标题】谷歌文字转语音 API【英文标题】:Google Text-To-Speech API 【发布时间】:2012-04-11 04:46:40 【问题描述】:

我想知道如何在我的 .NET 项目中使用 Google Text-to-Speech API。我想我需要调用一个 URL 才能使用 Web 服务,但我的想法并不清楚。有人可以帮忙吗?

【问题讨论】:

我也想知道有没有官方的API? ***.com/questions/32053442/… 这个对我有用github.com/pndurette/gTTS 【参考方案1】:

旧答案:

尝试使用此网址: http://translate.google.com/translate_tts?tl=en&q=Hello%20World 它将自动生成一个 wav 文件,您可以通过任何 .net 编程通过 HTTP 请求轻松获取该文件。

编辑:

哦,Google,您认为您可以通过脆弱的 http 标头验证来阻止人们使用您的出色服务。

以下是获得多种语言响应的解决方案(我会尝试添加更多语言):

NodeJS

// npm install `request`
const fs = require('fs');
const request = require('request');
const text = 'Hello World';

const options = 
    url: `https://translate.google.com/translate_tts?ie=UTF-8&q=$encodeURIComponent(text)&tl=en&client=tw-ob`,
    headers: 
        'Referer': 'http://translate.google.com/',
        'User-Agent': 'stagefright/1.2 (Linux;android 5.0)'
    


request(options)
    .pipe(fs.createWriteStream('tts.mp3'))

卷曲

curl 'https://translate.google.com/translate_tts?ie=UTF-8&q=Hello%20Everyone&tl=en&client=tw-ob' -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)' > google_tts.mp3

请注意,标头基于@Chris Cirefice 的示例,如果它们在某些时候停止工作,我将尝试重新创建此代码运行的条件。当前标头的所有功劳都归于他和 WireShark 出色的工具。 (也感谢谷歌没有修补这个)

【讨论】:

上面的链接坏了。 Google 翻译 API 文档位于 developers.google.com/translate。 试试这个translate.google.com/translate_tts?tl=en&q=Hello%20World 显然从 *** 引用链接有问题,但我通过 JS 使用 HTTP 请求尝试了它,并将它与 html5 声音 api 一起使用,工作正常! 如果您在隐身浏览器会话中尝试它会起作用,所以是的,请求中不应该有引用标头。 上述网址是否有任何速率限制? Google 已实施滥用保护,因此该网址现在重定向到验证码页面。要解决此问题,请参阅my answer-as-an-update。【参考方案2】:

在对Schahriar SaffarShargh's answer 的更新中,Google 最近实施了“Google 滥用”功能,因此无法向以下网址发送任何常规的旧 HTTP GET:

http://translate.google.com/translate_tts?tl=en&q=Hello%20World

以前工作得很好而且花花公子。现在,点击这样的链接会为您提供验证码。这也会影响浏览器外的 HTTP GET 请求(例如使用 cURL),因为使用该 URL 会重定向到滥用保护页面(验证码)。

首先,您必须将查询参数 client 添加到请求 URL:

http://translate.google.com/translate_tts?tl=en&q=Hello%20World&client=t

谷歌翻译发送&client=t,所以你也应该发送。

在发出 HTTP 请求之前,请确保设置了 Referer 标头:

Referer: http://translate.google.com/

显然,User-Agent 标头也是必需的,但有趣的是它可以是空白的:

User-Agent:

编辑注意 - 在某些用户代理(例如 Android 4.X)上,自定义 User-Agent 标头未发送,这意味着 Google 不会为请求提供服务。为了解决这个问题,我简单地将User-Agent 设置为一个有效的,例如stagefright/1.2 (Linux;Android 5.0)。如果 Google 的服务器没有响应,请使用 Wireshark 调试请求(就像我所做的那样),并确保在 GET! 中正确设置了这些标头!如果请求失败,Google 将回复 503 Service Unavailable,然后重定向到 CAPTCHA 页面。

这个解决方案有点脆弱;谷歌完全有可能在未来改变他们处理这些请求的方式,所以最后我建议让谷歌制作一个我们可以在没有的情况下使用的真正的 API 端点(免费或付费)为伪造 HTTP 标头感到肮脏。


编辑 2:对于那些感兴趣的人,这个 cURL 命令应该可以很好地下载英文 Hello 的 mp3:

curl 'http://translate.google.com/translate_tts?ie=UTF-8&q=Hello&tl=en&client=t' -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)' > google_tts.mp3

您可能注意到,我在请求中设置了RefererUser-Agent 标头,并将client=t 参数添加到查询字符串中。您可以使用https 代替http,您的选择!


编辑 3:Google 现在要求每个 GET 请求都有一个令牌(由查询字符串中的 tk 注明)。下面是修改后的 cURL 命令,可以正确下载 TTS mp3:

curl 'https://translate.google.com/translate_tts?ie=UTF-8&q=hello&tl=en&tk=995126.592330&client=t' -H 'user-agent: stagefright/1.2 (Linux;Android 5.0)' -H 'referer: https://translate.google.com/' > google_tts.mp3

注意查询字符串中的 &tk=995126.592330;这是新的令牌。我通过按下 translate.google.com 上的扬声器图标并查看 GET 请求来获得此令牌。我只是将这个查询字符串参数添加到前面的 cURL 命令中,它就可以工作了。

注意:显然这个解决方案非常脆弱,并且会因谷歌架构师的心血来潮而中断,他们引入了请求所需的令牌等新事物。这个令牌明天可能不起作用(尽管我会检查并报告)......关键是,依靠这种方法是不明智的;相反,应该转向商业 TTS 解决方案,尤其是在生产环境中使用 TTS 时。

有关令牌生成的进一步说明以及您可以采取的措施,请参阅Boude's answer。


如果此解决方案在未来任何时候出现故障,请对此答案发表评论,以便我们尝试找到解决方法!

【讨论】:

@Syom 查看我的编辑 :) 另外,检查 Wireshark 或其他一些网络分析工具以确保正确发送标头。正如我在回答中提到的那样,某些设备可能会删除自定义标头,或者执行其他不希望的操作导致请求失败。 @Syom 有趣的是,如果没有Referer,我无法让它工作......好吧,一个额外的标题“以防万一”现在不会受到伤害,是吗;) @dr.doom 很高兴知道我能帮上忙 :) @Akiva 只要您使用的语言可以打开文件,这绝对是可能的。您可以使用字符串连接来构建 CURL 命令,或使用字符串替换来替换 q=XXXXtl=XX 部分(这是首选)。请注意,整个字符串必须是 URL 编码的,否则文本查询中的空格会导致超时。所以q=Hello world必须编码为q=Hello%20world 这似乎又坏了。我基于这篇文章的代码在几个月前工作(大约 17 年 1 月至 2 月),但现在坏了(17 年 4 月)。用 client=tw-ob 替换 client=t 似乎可以解决问题。请验证并更新答案。【参考方案3】:

扩展至Chris' answer。我设法对令牌生成过程进行了逆向工程。

请求的令牌基于页面脚本中设置的文本和全局 TKK 变量。这些在 javascript 中进行哈希处理,从而产生 tk 参数。

在页面脚本的某个地方,您会发现类似这样的内容:

TKK='403413';

这是自纪元以来经过的小时数。

文本在以下函数中被抽取(有些反混淆):

var query = "Hello person";
var cM = function(a) 
    return function() 
        return a
    
;
var of = "=";
var dM = function(a, b) 
    for (var c = 0; c < b.length - 2; c += 3) 
        var d = b.charAt(c + 2),
            d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
            d = b.charAt(c + 1) == Tb ? a >>> d : a << d;
        a = b.charAt(c) == Tb ? a + d & 4294967295 : a ^ d
    
    return a
;

var eM = null;
var cb = 0;
var k = "";
var Vb = "+-a^+6";
var Ub = "+-3^+b+-f";
var t = "a";
var Tb = "+";
var dd = ".";
var hoursBetween = Math.floor(Date.now() / 3600000);
window.TKK = hoursBetween.toString();

fM = function(a) 
    var b;
    if (null === eM) 
        var c = cM(String.fromCharCode(84)); // char 84 is T
        b = cM(String.fromCharCode(75)); // char 75 is K
        c = [c(), c()];
        c[1] = b();
        // So basically we're getting window.TKK
        eM = Number(window[c.join(b())]) || 0
    
    b = eM;

    // This piece of code is used to convert d into the utf-8 encoding of a
    var d = cM(String.fromCharCode(116)),
        c = cM(String.fromCharCode(107)),
        d = [d(), d()];
    d[1] = c();
    for (var c = cb + d.join(k) +
            of, d = [], e = 0, f = 0; f < a.length; f++) 
        var g = a.charCodeAt(f);

        128 > g ? d[e++] = g : (2048 > g ? d[e++] = g >> 6 | 192 : (55296 == (g & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ? (g = 65536 + ((g & 1023) << 10) + (a.charCodeAt(++f) & 1023), d[e++] = g >> 18 | 240, d[e++] = g >> 12 & 63 | 128) : d[e++] = g >> 12 | 224, d[e++] = g >> 6 & 63 | 128), d[e++] = g & 63 | 128)
    


    a = b || 0;
    for (e = 0; e < d.length; e++) a += d[e], a = dM(a, Vb);
    a = dM(a, Ub);
    0 > a && (a = (a & 2147483647) + 2147483648);
    a %= 1E6;
    return a.toString() + dd + (a ^ b)
;

var token = fM(query);
var url = "https://translate.google.com/translate_tts?ie=UTF-8&q="  + encodeURI(query) + "&tl=en&total=1&idx=0&textlen=12&tk=" + token + "&client=t";
document.write(url);

我成功地将它移植到my fork of gTTS 中的python,所以我知道这是可行的。

编辑:目前 gTTS 使用的令牌生成代码已移至 gTTS-token。

编辑 2:Google 已更改 API(大约在 2016-05-10 左右),此方法需要进行一些修改。我目前正在做这件事。 In the meantime changing the client to tw-ob seems to work.

编辑 3:

这些变化很小,但至少可以说很烦人。 TKK 现在有两个部分。看起来像406986.2817744745。如您所见,第一部分保持不变。第二部分是两个看似随机的数字之和。 TKK=eval('((function()var a\x3d2680116022;var b\x3d137628723;return 406986+\x27.\x27+(a+b))())'); 这里\x3d 表示=\x27'。 a 和 b 都会每 UTC 分钟更改一次。在算法的最后一个步骤中,令牌与第二部分进行异或。

新的令牌生成代码是:

var xr = function(a) 
    return function() 
        return a
    
;
var yr = function(a, b) 
    for (var c = 0; c < b.length - 2; c += 3) 
        var d = b.charAt(c + 2)
          , d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d)
          , d = "+" == b.charAt(c + 1) ? a >>> d : a << d;
        a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d
    
    return a
;
var zr = null;
var Ar = function(a) 
    var b;
    if (null  !== zr)
        b = zr;
    else 
        b = xr(String.fromCharCode(84));
        var c = xr(String.fromCharCode(75));
        b = [b(), b()];
        b[1] = c();
        b = (zr = window[b.join(c())] || "") || ""
    
    var d = xr(String.fromCharCode(116))
      , c = xr(String.fromCharCode(107))
      , d = [d(), d()];
    d[1] = c();
    c = "&" + d.join("") + 
    "=";
    d = b.split(".");
    b = Number(d[0]) || 0;
    for (var e = [], f = 0, g = 0; g < a.length; g++) 
        var l = a.charCodeAt(g);
        128 > l ? e[f++] = l : (2048 > l ? e[f++] = l >> 6 | 192 : (55296 == (l & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023),
        e[f++] = l >> 18 | 240,
        e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224,
        e[f++] = l >> 6 & 63 | 128),
        e[f++] = l & 63 | 128)
    
    a = b;
    for (f = 0; f < e.length; f++)
        a += e[f],
        a = yr(a, "+-a^+6");
    a = yr(a, "+-3^+b+-f");
    a ^= Number(d[1]) || 0;
    0 > a && (a = (a & 2147483647) + 2147483648);
    a %= 1E6;
    return c + (a.toString() + "." + (a ^ b))

;
Ar("test");

当然我不能再生成有效的url了,因为我不知道a和b是如何生成的。

【讨论】:

感谢您添加另一个答案,+1!我将编辑我的答案以指向您的答案以进行进一步解释。 太棒了!非常感谢。 Google 再次更改了令牌结构。现在这个算法不起作用。有什么新的解决方案吗? @Syom A simpler approach has always existed in changing the client to tw-ob. 我目前正在研究 Google 所做的更改。它们看起来很小,但它们用每分钟变化的随机文本扩展了它们的种子。一旦我知道更多,我会回来报告。 感谢您的回复。我会寻找可能的解决方案。【参考方案4】:

另一种选择是:responsivevoice.org 一个简单的例子 JsFiddle 是 Here

HTML

<div id="container">
<input type="text" name="text">
<button id="gspeech" class="say">Say It</button>
<audio id="player1" src="" class="speech" hidden></audio>
</div>

JQuery

$(document).ready(function()

 $('#gspeech').on('click', function()
        
        var text = $('input[name="text"]').val();
        responsiveVoice.speak("" + text +"");
        <!--  http://responsivevoice.org/ -->
    );

);

外部资源:

https://code.responsivevoice.org/responsivevoice.js

【讨论】:

这实际上可以正常工作,而无需破解或担心某些东西会损坏。【参考方案5】:

好的,所以 Google 引入了令牌(请参阅新 url 中的 tk 参数),旧的解决方案似乎不起作用。我找到了另一种选择——我什至认为它听起来更好,而且声音更多!该命令并不漂亮,但它有效。请注意,这仅用于测试目的(我将其用于一个小型 domotica 项目),如果您打算将其用于商业用途,请使用 acapella-group 的真实版本。

curl $(curl --data 'MyLanguages=sonid10&MySelectedVoice=Sharon&MyTextForTTS=Hello%20World&t=1&SendToVaaS=' 'http://www.acapela-group.com/demo-tts/DemoHTML5Form_V2.php' | grep -o "http.*mp3") > tts_output.mp3

一些支持的声音是;

莎朗 Ella(纯正童声) EmilioEnglish(纯正童声) Josh(纯正的童声) 卡伦 肯尼(人工童声) 劳拉 弥迦 Nelly(人工童声) 杆 瑞安 扫罗 Scott(真正的少年声音) 特蕾西 ValeriaEnglish(纯正童声) 会 WillBadGuy(情绪化的声音) WillFromAfar(情绪化的声音) WillHappy(情绪化的声音) WillLittleCreature(情绪化的声音) WillOldMan(情绪化的声音) WillSad(情绪化的声音) WillUpClose(情绪化的声音)

它还支持多种语言和更多声音 - 为此我建议您访问他们的网站; http://www.acapela-group.com/

【讨论】:

嗨,你能发布如何在 php 中使用它吗? 正如@srik 报道的那样,这个解决方案已经被破坏,直到今天仍然存在。看起来 The Acapela Group 删除了这个 php 文件,以便从他们的服务器直接访问。 好像又开始工作了,不过后来 acapela 组给 tts 添加了背景音乐,所以现在用起来有点分散注意力。不过质量很好。【参考方案6】:

您可以使用 Wget:D 下载语音

wget -q -U Mozilla "http://translate.google.com/translate_tts?tl=en&q=Hello"

将输出保存到 mp3 文件中:

wget -q -U Mozilla "http://translate.google.com/translate_tts?tl=en&q=Hello" -O hello.mp3

尽情享受吧!

【讨论】:

【参考方案7】:

我创建了这样的:q= urlencode & tl = 语言名称

试试这个:

https://translate.google.com.vn/translate_tts?ie=UTF-8&q=%E0%A6%86%E0%A6%AE%E0%A6%BF%20%E0%A6%A4%E0%A7%8B%E0%A6%AE%E0%A6%BE%E0%A6%AF%E0%A6%BC%20%E0%A6%AD%E0%A6%BE%E0%A6%B2%E0%A7%8B%E0%A6%AC%E0%A6%BE%E0%A6%B8%E0%A6%BF+&tl=bn&client=tw-ob

【讨论】:

【参考方案8】:

谷歌文字转语音

<!DOCTYPE html>
<html>
    <head>
        <script>
            function play(id)
            var text = document.getElementById(id).value;
            var url = 'http://translate.google.com/translate_tts?tl=en&q='+text;
            var a = new Audio(url);
                a.play();
            
        </script>
    </head>
    <body>
        <input type="text" id="text" />
        <button onclick="play('text');"> Speak it </button>
    </body>
</html>

【讨论】:

【参考方案9】:

使用http://www.translate.google.com/translate_tts?tl=en&q=Hello%20World

注意 www.translate.google.com

【讨论】:

使用 wget translate.google.com/translate_tts?tl=en&q=Hello%20World 执行 wget 会发送此错误 HTTP 请求,等待响应... 403 Forbidden 2014-08-30 14:43:26 ERROR 403: Forbidden. 伙计们,我正在使用类似于此代码的 TTS。 “translate.google.com/translate_tts?tl=en&q=Hello”但我在 pc 上得到了高质量的回复,而在 android 上运行的代码质量真的很差。我应该允许某人下载文件吗?【参考方案10】:

截至目前,Google 官方 Text-to-Speech 服务在https://cloud.google.com/text-to-speech/提供

前 400 万个字符免费。

【讨论】:

我可以在商业 Android 应用中使用它吗? @August 是的。这是谷歌提供的官方服务。【参考方案11】:

我使用的网址如上:http://translate.google.com/translate_tts?tl=en&q=Hello%20World

并使用 python 库请求..但是我得到 HTTP 403 FORBIDDEN

最后我不得不用browser's one 模拟User-Agent 标头才能成功。

【讨论】:

【参考方案12】:

转到console.developer.google.com 登录并获取 API 密钥 或使用 microsoft bing 的 APIhttps://msdn.microsoft.com/en-us/library/?f=255&amp;MSPPError=-2147217396 甚至更好地使用 AT&T 的语音 API developer.att.com(付费一个) 用于语音识别

Public Class Voice_recognition

    Public Function convertTotext(ByVal path As String, ByVal output As String) As String
        Dim request As HttpWebRequest = DirectCast(HttpWebRequest.Create("https://www.google.com/speech-api/v1/recognize?xjerr=1&client=speech2text&lang=en-US&maxresults=10"), HttpWebRequest)
        'path = Application.StartupPath & "curinputtmp.mp3"
        request.Timeout = 60000
        request.Method = "POST"
        request.KeepAlive = True
        request.ContentType = "audio/x-flac; rate=8000"  
        request.UserAgent = "speech2text"

        Dim fInfo As New FileInfo(path)
        Dim numBytes As Long = fInfo.Length
        Dim data As Byte()

        Using fStream As New FileStream(path, FileMode.Open, FileAccess.Read)
            data = New Byte(CInt(fStream.Length - 1)) 
            fStream.Read(data, 0, CInt(fStream.Length))
            fStream.Close()
        End Using

        Using wrStream As Stream = request.GetRequestStream()
            wrStream.Write(data, 0, data.Length)
        End Using

        Try
            Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
            Dim resp = response.GetResponseStream()

            If resp IsNot Nothing Then
                Dim sr As New StreamReader(resp)
                MessageBox.Show(sr.ReadToEnd())

                resp.Close()
                resp.Dispose()
            End If
        Catch ex As System.Exception
            MessageBox.Show(ex.Message)
        End Try

        Return 0
    End Function
End Class

对于文字转语音:use this。

我想你会明白的 如果没有,则使用 vbscript 到 vb/C# 转换器。 还是没有联系我。

我以前做过,现在找不到代码,这就是为什么我不直接给你代码的原因。

【讨论】:

【参考方案13】:

因为它是在这里聊天中出现的,而谷歌搜索的第一页就是这个,我决定让我的发现全部投入谷歌搜索更多 XD

你真的不需要再费力地让它工作了,只需站在巨人的肩膀上:

有一个标准

https://dvcs.w3.org/hg/speech-api/raw-file/tip/webspeechapi.html

还有一个例子

http://html5-examples.craic.com/google_chrome_text_to_speech.html

至少对于您的网络项目,这应该可以工作(例如 asp.net)

【讨论】:

【参考方案14】:
#! /usr/bin/python2
# -*- coding: utf-8 -*-

def run(cmd):
    import os
    import sys
    from subprocess import Popen, PIPE
    print(cmd)
    proc=Popen(cmd, stdin=None, stdout=PIPE, stderr=None, shell=True)
    while True:
        data = proc.stdout.readline()   # Alternatively proc.stdout.read(1024)
        if len(data) == 0:
            print("Finished process")
            break
        sys.stdout.write(data)

import urllib

msg='Hello preety world'
msg=urllib.quote_plus(msg)
# -v verbosity
cmd='curl '+ \
    '--output tts_responsivevoice.mp2 '+ \
    "\""+'https://code.responsivevoice.org/develop/getvoice.php?t='+msg+'&tl=en-US&sv=g2&vn=&pitch=0.5&rate=0.5&vol=1'+"\""+ \
    ' -H '+"\""+'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0'+"\""+ \
    ' -H '+"\""+'Accept: audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5'+"\""+ \
    ' -H '+"\""+'Accept-Language: pl,en-US;q=0.7,en;q=0.3'+"\""+ \
    ' -H '+"\""+'Range: bytes=0-'+"\""+ \
    ' -H '+"\""+'Referer: http://code.responsivevoice.org/develop/examples/example2.html'+"\""+ \
    ' -H '+"\""+'Cookie: __cfduid=ac862i73b6a61bf50b66713fdb4d9f62c1454856476; _ga=GA1.2.2126195996.1454856480; _gat=1'+"\""+ \
    ' -H '+"\""+'Connection: keep-alive'+"\""+ \
    ''
print('***************************')
print(cmd)
print('***************************')
run(cmd)

行:

/getvoice.php?t='+msg+'&tl=en-US&sv=g2&vn=&pitch=0.5&rate=0.5&vol=1'+"\""+ \

负责语言。

tl=en-US

还有一个非常有趣的网站,其中包含可以以这种方式使用的 tts 引擎。

用 o 代替 null iv0na.c0m

祝你有美好的一天

【讨论】:

以上是关于谷歌文字转语音 API的主要内容,如果未能解决你的问题,请参考以下文章

三星手机出现Google文字转语音引擎以停止出现声音屏幕打不开

iOS 文字转语音 API

使用 Google Cloud 文字转语音 API

安卓手机怎么关闭 文本转语音选项?

Google语音转文字Speech to Text 超级好用的语音转文本API

Android文字转语音引擎(TTS)使用