From 5b3b6126e4b7ff060e2e7a2fed1f5700f0b5e39b Mon Sep 17 00:00:00 2001 From: Han Yin Date: Mon, 7 Jul 2025 20:25:51 -0700 Subject: [PATCH] remote: fix the incorrect parse of HuggingFace's inconsistent & weird JSON response --- .../llama/data/remote/GatedTypeAdapter.kt | 26 +++++++++++++++++++ .../java/com/example/llama/di/AppModule.kt | 23 +++++++++++----- 2 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 examples/llama.android/app/src/main/java/com/example/llama/data/remote/GatedTypeAdapter.kt diff --git a/examples/llama.android/app/src/main/java/com/example/llama/data/remote/GatedTypeAdapter.kt b/examples/llama.android/app/src/main/java/com/example/llama/data/remote/GatedTypeAdapter.kt new file mode 100644 index 0000000000..a6206f1143 --- /dev/null +++ b/examples/llama.android/app/src/main/java/com/example/llama/data/remote/GatedTypeAdapter.kt @@ -0,0 +1,26 @@ +package com.example.llama.data.remote + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import java.lang.reflect.Type + +class GatedTypeAdapter : JsonDeserializer { + override fun deserialize( + json: JsonElement, + typeOfT: Type, + context: JsonDeserializationContext + ): Boolean { + return when { + json.isJsonPrimitive -> { + val primitive = json.asJsonPrimitive + when { + primitive.isBoolean -> primitive.asBoolean + primitive.isString -> primitive.asString != "false" + else -> false + } + } + else -> false + } + } +} diff --git a/examples/llama.android/app/src/main/java/com/example/llama/di/AppModule.kt b/examples/llama.android/app/src/main/java/com/example/llama/di/AppModule.kt index 508be94bfa..202114d1c9 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/di/AppModule.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/di/AppModule.kt @@ -6,6 +6,7 @@ import android.llama.cpp.KleidiLlama import android.llama.cpp.TierDetection import android.llama.cpp.gguf.GgufMetadataReader import com.example.llama.data.local.AppDatabase +import com.example.llama.data.remote.GatedTypeAdapter import com.example.llama.data.remote.HuggingFaceApiService import com.example.llama.data.remote.HuggingFaceRemoteDataSource import com.example.llama.data.remote.HuggingFaceRemoteDataSourceImpl @@ -21,6 +22,7 @@ import com.example.llama.engine.ModelLoadingService import com.example.llama.engine.StubInferenceEngine import com.example.llama.engine.StubTierDetection import com.example.llama.monitoring.PerformanceMonitor +import com.google.gson.Gson import com.google.gson.GsonBuilder import dagger.Binds import dagger.Module @@ -34,7 +36,8 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Singleton -private const val HUGGINGFACE_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" +const val HUGGINGFACE_HOST = "https://huggingface.co/" +const val HUGGINGFACE_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" @Module @InstallIn(SingletonComponent::class) @@ -110,13 +113,21 @@ internal abstract class AppModule { @Provides @Singleton - fun provideHuggingFaceApiService(okHttpClient: OkHttpClient): HuggingFaceApiService = + fun provideGson(): Gson = GsonBuilder() + .setDateFormat(HUGGINGFACE_DATETIME_FORMAT) + .registerTypeAdapter(Boolean::class.java, GatedTypeAdapter()) + .create() + + @Provides + @Singleton + fun provideHuggingFaceApiService( + okHttpClient: OkHttpClient, + gson: Gson, + ): HuggingFaceApiService = Retrofit.Builder() - .baseUrl("https://huggingface.co/") + .baseUrl(HUGGINGFACE_HOST) .client(okHttpClient) - .addConverterFactory(GsonConverterFactory.create( - GsonBuilder().setDateFormat(HUGGINGFACE_DATETIME_FORMAT).create() - )) + .addConverterFactory(GsonConverterFactory.create(gson)) .build() .create(HuggingFaceApiService::class.java) }