IBM 的 Speech to Text 的 Retrofit2 身份验证错误
Retrofit2 authentication error to IBM's Speech to Text
我试图在不使用库的情况下访问 IBM 的 Speech to Text 服务。我正在使用带有 GSON 的 Retrofit。
问题出在身份验证中,显然没有正确发生,返回代码 401。从 official documentation 开始,HTTP 请求应该采用这种格式
curl -X POST -u "apikey:{apikey}" \
--header "Content-Type: audio/flac" \
--data-binary @{path_to_file}audio-file.flac \
"{url}/v1/recognize"
当我使用我的凭据测试 curl
命令时,该服务工作正常。
这是我正在使用的界面
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)
这就是我设置 Retrofit 的方式
private val retrofit = Retrofit.Builder()
.baseUrl(STT_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
private val service = retrofit.create(SpeechToTextApi::class.java)
调用实际服务时如下所示
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
。
问题似乎出在身份验证的工作方式上。在上面显示的代码之前,我使用了
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
参数。
非常感谢任何形式的帮助。
我有点难过没有人能够更快地解决这个问题,但这是我在处理完全不同的项目时偶然遇到的解决方案。
正如您从 curl
命令中看到的那样,身份验证以 username: password
模式的形式出现,在这种情况下,用户名是 apikey
字符串,密码是您的 API键。
因此,您应该以这种方式构建 Retrofit 实例来解决此问题:
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()
才能对凭据进行编码。
我真的希望有类似问题的人偶然发现这个问题并节省一些时间。
我试图在不使用库的情况下访问 IBM 的 Speech to Text 服务。我正在使用带有 GSON 的 Retrofit。
问题出在身份验证中,显然没有正确发生,返回代码 401。从 official documentation 开始,HTTP 请求应该采用这种格式
curl -X POST -u "apikey:{apikey}" \
--header "Content-Type: audio/flac" \
--data-binary @{path_to_file}audio-file.flac \
"{url}/v1/recognize"
当我使用我的凭据测试 curl
命令时,该服务工作正常。
这是我正在使用的界面
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)
这就是我设置 Retrofit 的方式
private val retrofit = Retrofit.Builder()
.baseUrl(STT_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
private val service = retrofit.create(SpeechToTextApi::class.java)
调用实际服务时如下所示
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
。
问题似乎出在身份验证的工作方式上。在上面显示的代码之前,我使用了
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
参数。
非常感谢任何形式的帮助。
我有点难过没有人能够更快地解决这个问题,但这是我在处理完全不同的项目时偶然遇到的解决方案。
正如您从 curl
命令中看到的那样,身份验证以 username: password
模式的形式出现,在这种情况下,用户名是 apikey
字符串,密码是您的 API键。
因此,您应该以这种方式构建 Retrofit 实例来解决此问题:
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()
才能对凭据进行编码。
我真的希望有类似问题的人偶然发现这个问题并节省一些时间。