Retrofit2身份验证错误到IBM的语音转文本 [英] Retrofit2 authentication error to IBM's Speech to Text
问题描述
我正在尝试不使用库而访问IBM的语音转文本服务.我正在GSON上使用Retrofit.
I am trying to access IBM's Speech to Text service without using the library. I am using Retrofit with GSON.
The issue is in the authentication, which apparently does not occur correctly, returning code 401. From the official documentation, the HTTP request should come in this format
curl -X POST -u "apikey:{apikey}" \
--header "Content-Type: audio/flac" \
--data-binary @{path_to_file}audio-file.flac \
"{url}/v1/recognize"
当我使用凭据测试curl
命令时,该服务运行正常.
When I test the curl
command with my credentials, the service works fine.
这是我正在使用的界面
interface SpeechToTextApi {
@Multipart
@POST("v1/recognize")
fun speechToText(
@Header("Authorization") authKey: String,
@Part("file") filename: RequestBody,
@Part voiceFile: MultipartBody.Part
): Call<List<SpeechToText>>
}
我具有以下数据类
data class SpeechToText(val results: List<SttResult>)
data class SttResult(val alternatives: List<RecognitionResult>, val final: Boolean)
data class RecognitionResult(val confidence: Float, val transcript: String)
这就是我设置翻新的方式
and this is how I set up Retrofit
private val retrofit = Retrofit.Builder()
.baseUrl(STT_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
private val service = retrofit.create(SpeechToTextApi::class.java)
在调用实际服务时看起来像这样
while calling the actual service looks like this
val requestFile = RequestBody.create(MediaType.parse("audio/mp3"), file.name)
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
service
.speechToText(getString(R.string.stt_iam_api_key), requestFile, body)
.enqueue(object: Callback<List<SpeechToText>> {
override fun onResponse(call: Call<List<SpeechToText>>, response: Response<List<SpeechToText>>) {
val listOfStts = response.body()
Log.d(TAG, "Response code: ${response.code()}")
if (listOfStts != null) {
for (stt in listOfStts) {
for (res in stt.results) {
Log.d(TAG, "Final value: ${res.final}")
for (alt in res.alternatives) {
Log.d(TAG, "Alternative confidence: ${alt.confidence}\nTranscript: ${alt.transcript}")
Toast.makeText(this@MainActivity, alt.transcript, Toast.LENGTH_SHORT).show()
}
}
}
}
}
override fun onFailure(call: Call<List<SpeechToText>>, t: Throwable) {
Log.d(TAG, "Error: ${t.message}")
t.printStackTrace()
}
})
录音是MP3文件,对于这些文件,我相信它们可以正确存储并可以访问.我也用audio/mp3
替换了audio/flac
.
Recordings are MP3 files, for which I am sure they are stored correctly and accessible. I have replaced audio/flac
with audio/mp3
as well.
问题似乎是验证工作的方式.在上面显示的代码之前,我已经使用
Issue seems to be in the way authentication works. Prior to the code I have shown above, I've used
private val retrofit = Retrofit.Builder()
.baseUrl(STT_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request()
val headers = request
.headers()
.newBuilder()
.add("Authorization", getString(R.string.stt_iam_api_key))
.build()
val finalRequest = request.newBuilder().headers(headers).build()
chain.proceed(finalRequest)
}
.build())
.build()
,但相同的响应代码401仍然存在.当然,接口方法缺少@Header
参数.
but the same response code 401 persisted. Of course, the interface method lacked the @Header
parameter.
非常感谢您提供任何帮助.
Any sort of help is much appreciated.
推荐答案
我为没有人能尽快解决这个问题感到难过,但这是我在从事其他项目时偶然遇到的解决方案
I am kind of saddened by the fact nobody was able to solve this one sooner, but here's the solution I came across by accident when working on a different project altogether.
从curl
命令可以看到,身份验证采用username: password
模式的形式,在这种情况下,用户名是apikey
字符串,密码是您的API密钥.
As you can see from the curl
command, authentication comes in the form of username: password
pattern, in this case, username being apikey
string and password is your API key.
因此,您应该通过以下方式构建Retrofit实例来解决此问题:
So the way you should tackle this is by building your Retrofit instance this way:
fun init(token: String) {
//Set logging interceptor to BODY and redact Authorization header
interceptor.level = HttpLoggingInterceptor.Level.BODY
interceptor.redactHeader("Authorization")
//Build OkHttp client with logging and token interceptors
val okhttp = OkHttpClient().newBuilder()
.addInterceptor(interceptor)
.addInterceptor(TokenInterceptor(token))
.build()
//Set field naming policy for Gson
val gsonBuilder = GsonBuilder()
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
//Build Retrofit instance
retrofit = Retrofit.Builder()
.baseUrl(IBM_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
.client(okhttp)
.build()
}
并创建此自定义拦截器
class TokenInterceptor constructor(private val token: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
val requestBuilder = original
.newBuilder()
.addHeader("Authorization", Credentials.basic("apikey", token))
.url(original.url)
return chain.proceed(requestBuilder.build())
}
}
您需要使用Credentials.basic()
来对凭据进行编码.
You need to use Credentials.basic()
in order to encode credentials.
我真的希望遇到类似问题的人偶然发现这一点并节省一些时间.
I really hope somebody with a similar issue stumbles across this and saves themselves some time.
这篇关于Retrofit2身份验证错误到IBM的语音转文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!