Home > Mobile >  Send an image to an OCR API with Rertofit and Kotlin
Send an image to an OCR API with Rertofit and Kotlin

Time:12-18

I'm trying to send an image to extract text from it using https://api-ninjas.com/api/imagetotext. I still get an HTTP 400 Error though and couldn't figure out why! I have an image in my assets folder and I should receive a list of words from the API as mentioned in the link. Any hints about how to get a appropriate error or to fix it would be great. My Code is:

data class Word(
    val bounding_box: BoundingBox,
    val text: String
)

data class BoundingBox(
    val x1: Int,
    val x2: Int,
    val y1: Int,
    val y2: Int
)

FileApi.kt

import com.example.misinfo.retrofitfileupload.dto.Word
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part

interface FileApi {

    @Multipart
    @POST("/v1/imagetotext")
    suspend fun uploadImage(
        @Part image: MultipartBody.Part,
    ): Call<List<Word>>


    companion object {
        private val client = OkHttpClient.Builder().build()
        val instance by lazy {
            Retrofit.Builder()
                //TODO: add some API url
                .baseUrl("https://api.api-ninjas.com/")
                .client(client) // add a client instance here, e.g. OkHttpClient
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(FileApi::class.java)
        }
    }
}

FileRepository.kt


import android.util.Log
import com.example.misinfo.retrofitfileupload.dto.Word
import okhttp3.MultipartBody
import java.io.File
import java.io.IOException
import okhttp3.RequestBody.Companion.asRequestBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.HttpException
import retrofit2.Response

class FileRepository {

    suspend fun uploadImage(file: File): Boolean {
        var res = false
        try {
            FileApi.instance.uploadImage(
                image = MultipartBody.Part
                    .createFormData(
                        "image",
                        file.name,
                        file.asRequestBody()
                    )
            ).enqueue(
                object : Callback<List<Word>> {
                    override fun onFailure(call: Call<List<Word>>, t: Throwable) {
                        Log.e("API Request", "I got an error and i don't know why :(")
                    }
                    override fun onResponse( call: Call<List<Word>>, response: Response<List<Word>>) {
                        val responseBody = response.body()
                        Log.e("API Request", responseBody.toString())
                    }
                }
            )
            res = true
            return res
        } catch (e: IOException) {
            e.printStackTrace()
            return res
        } catch (e: HttpException) {
            e.printStackTrace()
            return res
        } finally {
            Log.e("API Request", res.toString())
        }
    }
}

FileViewModel.kt

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.misinfo.retrofitfileupload.FileRepository
import kotlinx.coroutines.launch
import java.io.File

class FileViewModel(
    private val repository: FileRepository= FileRepository()
): ViewModel() {
    fun uploadImage(file: File){
        viewModelScope.launch {
            repository.uploadImage(file)
        }
    }

}

MainActicity.kt

class MainActivity : ComponentActivity() {

    class MyReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            println("Clicked on Pip Action")
        }
    }

    private val isPipSupported by lazy {
        packageManager.hasSystemFeature(
            PackageManager.FEATURE_PICTURE_IN_PICTURE
        )
    }

    private var viewBounds = Rect()

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MisInfoTheme {
                //ApplicationSwitcher()
                val viewModel = viewModel<FileViewModel>()
                Box(
                    modifier = Modifier.fillMaxSize(),
                    contentAlignment = Alignment.Center
                ) {
                    Button(onClick = {
                        val file = File(cacheDir, "img.png")
                        file.createNewFile()
                        file.outputStream().use {
                            assets.open("img.png").copyTo(it)
                        }
                        viewModel.uploadImage(file)
                    }) {
                        Text(text = "Upload image")
                    }
                }
            }
        }
    }
}

CodePudding user response:

HTTP 400 Bad Request so I guess the problem here as you trying to send with the wrong path as you see here you setting your POST endpoint wrong it shouldn't start with the "/" remove this and it should work fine I guess

@Multipart
    @POST("v1/imagetotext")
    suspend fun uploadImage(
        @Part image: MultipartBody.Part,
    ): Call<List<Word>>

CodePudding user response:

I solved the problem by adding a header to my post request.

interface FileApi {

    @Headers("X-Api-Key: add your header")
    @Multipart
    @POST("v1/imagetotext")
    fun uploadImage(
        @Part image: MultipartBody.Part,
    ): Call<List<Word>>


    companion object {
        private val client = OkHttpClient.Builder().build()
        val instance by lazy {
            Retrofit.Builder()
                //TODO: add some API url
                .baseUrl("https://api.api-ninjas.com/")
                .client(client) // add a client instance here, e.g. OkHttpClient
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(FileApi::class.java)
        }
    }
}
  • Related