Unity集成Google Cloud Speech-to-Text API仅返回指定字段的解决方法
Unity调用Google Cloud Speech-to-Text API无识别结果问题排查与解决
问题现象
调用https://speech.googleapis.com/v1/speech:recognize?key={API_KEY}接口后,仅返回requestId和totalBilledTime,缺失results、speechAdaptationInfo等核心识别结果字段。
排查方向与解决办法
1. 音频格式与编码验证
Google Speech-to-Text对LINEAR16编码的音频有严格要求:
- 强制转为单声道:如果原AudioClip是立体声,会直接导致识别失败。修改
ConvertAudioClipToBase64方法,添加单声道转换逻辑:// 转为单声道 float[] monoSamples = new float[clip.samples]; if (clip.channels == 2) { for (int i = 0; i < clip.samples; i++) { monoSamples[i] = (samples[i * 2] + samples[i * 2 + 1]) / 2f; } } else { monoSamples = samples; } // 后续用monoSamples转换为PCM16 - 严格匹配采样率:代码中设置的是16000Hz,必须保证原AudioClip的采样率也是16000Hz,否则需先对音频进行重采样处理。
2. JSON序列化问题
Unity自带的JsonUtility存在序列化限制,可能导致JSON字段名或结构不符合API要求:
- 检查
JsonUtility.ToJson(jsonRequest)的输出,确认config、encoding等字段为小写(Google API要求全小写字段名)。如果序列化结果异常,改用Newtonsoft.Json(可通过Unity Package Manager导入):string json = JsonConvert.SerializeObject(jsonRequest);
3. 音频数据完整性优化
- 避免本地文件中转:原代码先写入
output.pcm再读取,可能触发IO错误。直接在内存中处理音频数据:// 替换文件读写部分 using (MemoryStream ms = new MemoryStream()) using (BinaryWriter bw = new BinaryWriter(ms)) { foreach (short sample in pcmData) { bw.Write(sample); } byte[] audioData = ms.ToArray(); string base64String = Convert.ToBase64String(audioData); return base64String; } - 验证Base64有效性:将生成的Base64字符串解码为PCM文件,用Audacity等工具打开,确认音频可正常播放。
4. API请求配置补充
- 确认使用正确的接口:当前地址为同步识别接口,仅支持1分钟以内的音频;若音频更长,需改用异步识别接口。
- 可在
config中添加enableAutomaticPunctuation: true等参数,提升识别准确率,但核心前提是音频格式符合要求。
修正后的核心代码示例
音频转换优化
string ConvertAudioClipToBase64(AudioClip clip) { // 校验采样率 if (clip.frequency != 16000) { Debug.LogError("AudioClip采样率必须为16000Hz"); return string.Empty; } float[] samples = new float[clip.samples * clip.channels]; clip.GetData(samples, 0); // 转为单声道 float[] monoSamples = new float[clip.samples]; if (clip.channels == 2) { for (int i = 0; i < clip.samples; i++) { monoSamples[i] = (samples[i * 2] + samples[i * 2 + 1]) / 2f; } } else { monoSamples = samples; } short[] pcmData = ConvertToPCM16(monoSamples); // 内存中处理音频数据 using (MemoryStream ms = new MemoryStream()) using (BinaryWriter bw = new BinaryWriter(ms)) { foreach (short sample in pcmData) { bw.Write(sample); } byte[] audioData = ms.ToArray(); return Convert.ToBase64String(audioData); } } private short[] ConvertToPCM16(float[] samples) { short[] pcmData = new short[samples.Length]; for (int i = 0; i < samples.Length; i++) { pcmData[i] = (short)(Mathf.Clamp(samples[i], -1f, 1f) * short.MaxValue); } return pcmData; }
请求序列化优化(使用Newtonsoft.Json)
// 需先导入Newtonsoft.Json包 var jsonRequest = new SpeechToTextRequest { config = new AudioConfig { encoding = "LINEAR16", sampleRateHertz = 16000, languageCode = "ja-JP"}, audio = new SpeechToTextInput { content = base64Audio} }; string json = JsonConvert.SerializeObject(jsonRequest); var request = new UnityWebRequest(url, "POST") { uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json)), downloadHandler = new DownloadHandlerBuffer() }; request.SetRequestHeader("Content-Type", "application/json"); await request.SendWebRequest().ToUniTask(); if (request.result == UnityWebRequest.Result.Success) { var response = request.downloadHandler.text; // 反序列化为响应类查看完整结果 var speechResponse = JsonConvert.DeserializeObject<SpeechToTextResponse>(response); } else { throw new Exception($"Error: {request.error}"); } // 响应类定义 [Serializable] private class SpeechToTextResponse { public List<SpeechResult> results; public string totalBilledTime; public SpeechAdaptationInfo speechAdaptationInfo; public string requestId; } [Serializable] private class SpeechResult { // 根据API文档添加对应字段,如alternatives等 } [Serializable] private class SpeechAdaptationInfo { // 对应API返回的适配信息字段 }
内容的提问来源于stack exchange,提问作者ばねっと
相关产品推荐
相关产品推荐

