百度人工智能api使用问题总结

607 阅读1分钟

最近开发的一款app有使用百度人工智能图像方面的api,但由于个人的疏忽,导致部分问题排查了很久才发现,于此记录

okhttp3.internal.http2.StreamResetException: stream was reset: CANCEL

  • 正常使用retrofit2调用接口的时候出现问题,本来以为是base64转码后编码长度过大,后来发现没到1M还是报错,经过层层排查,发现在发起请求的Service部分我写成了
package com.ericmoin.myapplication

import retrofit2.Call
import retrofit2.http.Header
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query

interface ImageService {
    @Headers(
        "Content-Type:application/x-www-form-urlencoded",
        "Accept:application/json"
    )
    @POST("contrast_enhance?access_token=${Constants.ACCESS_TOKEN}")
    fun contrastEnhanceByImage( @Query("image") image:String ): Call<ImageResponse>
}
  • @Query注解用习惯了,一直以为在URL后诸如image=xxx的参数都用@Query的形式标注。事实上百度在请求头部分已经说明x-www-form-urlencoded表示其后的参数要以表单数据的形式提交,正确写法应为
package com.ericmoin.myapplication

import retrofit2.Call
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.Header
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query

interface ImageService {
    @FormUrlEncoded
    @Headers(
        "Content-Type:application/x-www-form-urlencoded",
        "Accept:application/json"
    )
    @POST("contrast_enhance?access_token=${Constants.ACCESS_TOKEN}")
    fun contrastEnhanceByImage( @Field("image") image:String ): Call<ImageResponse>
}

base64转码

  • 百度的api需要将图片转成base64编码,在app内展示的时候我已经有了一个bitmap,想着用已经展示的bitmap直接转码,结果发现报OOM异常,代码如下
    suspend fun convertBitmap2String(
        bitmap: Bitmap,
        format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG,
        quality: Int = 100
    ) = withContext(Dispatchers.IO){
        ByteArrayOutputStream().use { outputStream ->
            bitmap.compress(format, quality, outputStream)
            val buffer = outputStream.toByteArray()
            Base64.encodeToString(buffer, Base64.DEFAULT)
        }
    }
    suspend fun convertString2Bitmap(bitmapStr: String): Bitmap {
        val result = CoroutineScope(Dispatchers.IO).async {
            val byteArray = Base64.decode(bitmapStr, Base64.DEFAULT)
            BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
        }
        return result.await()
    }
  • 想到可能是一次分配的空间太多了,而且在运行过程中JVM一直在启动GC。苦思冥想许久找不到结果,最后百度的文档中提供了一个直接转化文件的方法
    fun getFileContentAsBase64(path: String, urlEncode: Boolean = true): String {
        val b = Files.readAllBytes(Paths.get(path))
        var base64 = java.util.Base64.getEncoder().encodeToString(b)
        if (urlEncode) {
            base64 = URLEncoder.encode(base64, "utf-8")
        }
        return base64
    }
  • 需要注意,如果在Android中作为工具类的方法使用,需要保证你的minSdk >= 26