Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when using Gemini OpenAI API #412

Open
MUKAPP opened this issue Jan 14, 2025 · 6 comments · May be fixed by #428
Open

Error when using Gemini OpenAI API #412

MUKAPP opened this issue Jan 14, 2025 · 6 comments · May be fixed by #428

Comments

@MUKAPP
Copy link

MUKAPP commented Jan 14, 2025

Description

When using the Gemini OpenAI API, an error occurs, but the packet capture shows that the request is normal.

Error during chat completion
com.aallam.openai.api.exception.OpenAIHttpException: Illegal input: Field 'id' is required for type with serial name 'com.aallam.openai.api.chat.ChatCompletion', but it was missing at path: $
	at com.aallam.openai.client.internal.http.HttpTransport.handleException(HttpTransport.kt:52)
	at com.aallam.openai.client.internal.http.HttpTransport.perform(HttpTransport.kt:23)
	at com.aallam.openai.client.internal.http.HttpTransport$perform$1.invokeSuspend(Unknown Source:15)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:101)
	at android.os.Handler.handleCallback(Handler.java:959)
	at android.os.Handler.dispatchMessage(Handler.java:100)
	at android.os.Looper.loopOnce(Looper.java:249)
	at android.os.Looper.loop(Looper.java:337)
	at android.app.ActivityThread.main(ActivityThread.java:9590)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
Caused by: io.ktor.serialization.JsonConvertException: Illegal input: Field 'id' is required for type with serial name 'com.aallam.openai.api.chat.ChatCompletion', but it was missing at path: $
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:77)
	at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1$2.emit(Emitters.kt:51)
	at kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:111)
	at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1.collect(SafeCollector.common.kt:109)
	at kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:239)
	at kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source:1)
	at io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:99)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.ContentNegotiation$lambda$13$convertResponse(ContentNegotiation.kt:234)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.access$ContentNegotiation$lambda$13$convertResponse(ContentNegotiation.kt:1)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invokeSuspend(ContentNegotiation.kt:249)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invoke(Unknown Source:19)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invoke(Unknown Source:10)
	at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invokeSuspend(KtorCallContexts.kt:105)
	at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invoke(Unknown Source:11)
	at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invoke(Unknown Source:6)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:1379)
	at io.ktor.client.HttpClient$4.invoke(Unknown Source:11)
	at io.ktor.client.HttpClient$4.invoke(Unknown Source:6)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.client.plugins.logging.ReceiveHook$Context.proceed(Logging.kt:289)
	at io.ktor.client.plugins.logging.LoggingKt$Logging$2$3.invokeSuspend(Logging.kt:209)
	at io.ktor.client.plugins.logging.LoggingKt$Logging$2$3.invoke(Unknown Source:13)
	at io.ktor.client.plugins.logging.LoggingKt$Logging$2$3.invoke(Unknown Source:6)
	at io.ktor.client.plugins.logging.ReceiveHook$install$1.invokeSuspend(Logging.kt:297)
	at io.ktor.client.plugins.logging.ReceiveHook$install$1.invoke(Unknown Source:11)
	at io.ktor.client.plugins.logging.ReceiveHook$install$1.invoke(Unknown Source:6)

Steps to Reproduce

  1. It's just sending a request to the Gemini OpenAI API.

Environment

  • openai-kotlin version: 4.0.0-beta01
  • Kotlin version: 2.1.0
  • OS: Android 15

Additional Info

Captured packet request image:
image

@stardomains3
Copy link

Yes. I get this too. Is there a way to have deserialization ignore missing fields?

@stardomains3
Copy link

I emailed the Google guy asking them to add it

@stardomains3
Copy link

I asked an AI, they said if they change:

data class ChatCompletion(
    val id: String,
    val created: Long,
    val model: ModelId,
    val choices: List<ChatChoice>,
    val usage: Usage? = null,
    val systemFingerprint: String? = null
)

to:

data class ChatCompletion(
    val id: String? = null,  // Now nullable
    val created: Long,
    val model: ModelId,
    val choices: List<ChatChoice>,
    val usage: Usage? = null,
    val systemFingerprint: String? = null
)

it should then work

@stardomains3
Copy link

better yet this:

data class ChatCompletion(
    val id: String? = null,
    val created: Long,
    val model: ModelId,
    val choices: List<ChatChoice>,
    val usage: Usage? = null,
    val systemFingerprint: String? = null,
    val citations: List<String>? = null  // Confirmed as List<String>
)

@stardomains3
Copy link

git clone https://github.com/aallam/openai-kotlin.git

cd openai-kotlin

edit the ChatCompletion.kt in core

to

package com.aallam.openai.api.chat

import com.aallam.openai.api.core.Usage
import com.aallam.openai.api.model.ModelId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * An object containing a response from the chat completion api.
 *
 * [documentation](https://platform.openai.com/docs/api-reference/chat/create)
 */
@Serializable
public data class ChatCompletion(
    /**
     * A unique id assigned to this completion
     */
    @SerialName("id") public val id: String? = null,  // Made nullable

    /**
     * The creation time in epoch milliseconds.
     */
    @SerialName("created") public val created: Long,

    /**
     * The model used.
     */
    @SerialName("model") public val model: ModelId,

    /**
     * A list of generated completions
     */
    @SerialName("choices") public val choices: List<ChatChoice>,

    /**
     * Text completion usage data.
     */
    @SerialName("usage") public val usage: Usage? = null,

    /**
     * This fingerprint represents the backend configuration that the model runs with.
     *
     * Can be used in conjunction with the seed request parameter to understand when backend changes have been made that
     * might impact determinism.
     */
    @SerialName("system_fingerprint") public val systemFingerprint: String? = null,

    /**
     * A list of URLs cited in the completion response (Perplexity-specific).
     *
     * Only included when the 'return_citations' parameter is set to true in the request.
     */
    @SerialName("citations") public val citations: List<String>? = null  // Added 
)

and save

./gradlew :openai-core:assemble :openai-client:assemble

put the two jar files in libs folder

add dependencies

// implementation("com.aallam.openai:openai-client:4.0.1")
implementation(files("libs/openai-core-jvm.jar"))
implementation(files("libs/openai-client-jvm.jar"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
implementation("io.ktor:ktor-client-core:3.1.0") // HTTP client core
implementation("io.ktor:ktor-client-okhttp:3.0.3") // OkHttp backend (matches your usage)
implementation("io.ktor:ktor-client-content-negotiation:3.0.3") // For JSON negotiation
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.3") // Ktor JSON support
implementation("org.jetbrains.kotlin:kotlin-stdlib:2.1.10")
implementation("io.ktor:ktor-client-logging:3.0.0")
implementation("io.ktor:ktor-client-auth:3.0.0")

sync, clean rebuild, test

Voila! It works now with Gemini!

@sepatel sepatel linked a pull request Feb 21, 2025 that will close this issue
@sepatel
Copy link

sepatel commented Feb 23, 2025

It is probably important to also note though that the gemini api's are actually openai compliant because of the missing id field which is actually not a required field.

https://platform.openai.com/docs/api-reference/chat/create
https://platform.openai.com/docs/api-reference/chat/object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants