I am trying to develop an app as well as learn Kotlin. I decided to create an app that allows a User to create a story using AI, based on prompts, a sort of Text RPG game. I finished the UI, so now I moved on to incorporating the OpenAI API into the app. I finished writing the Kotlin code for the API request:
fun makeAPIRequest(message: String) {
// Launch a coroutine to handle the API request asynchronously
GlobalScope.launch(Dispatchers.IO) {
// Create a ChatCompletionRequest to send to OpenAI
val chatRequest = ChatCompletionRequest(
model = ModelId("gpt-3.5-turbo-1106"), // Use the correct model name
messages = mutableListOf(
ChatMessage(
role = Role.User, // User sends the message
content = message // The message entered by the user
)
),
temperature = 0.7,
maxTokens = 150
)
// Send the request to OpenAI API and get the response asynchronously
val response = openAI.chatCompletion(chatRequest)
// Process the response on the main thread
withContext(Dispatchers.Main) {
val responseMessage = response.choices.first().message
// Handle the response here, e.g., update UI or process data
chatGPTResponse = responseMessage.toString()
}
}
}
The reason I didn’t make the function async is because I call it elsware in my MainActivity.kt
There are no syntax errors when the project is just sitting inside the IDE. However, when I try to launch the app, it crashes instantly and gives me this output in Logcat:
`
java.lang.NoClassDefFoundError: Failed resolution of: Lio/ktor/client/plugins/contentnegotiation/ContentNegotiation;
…
Caused by: java.lang.ClassNotFoundException: Didn’t find class “io.ktor.client.plugins.contentnegotiation.ContentNegotiation” on path: DexPathList[[zip file “/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.apk”],nativeLibraryDirectories=[/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/lib/x86_64, /data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.apk!/lib/x86_64, /system/lib64, /system_ext/lib64]]
The reason I point out that second and longer replica of the first error is because before the app even starts, there is 2 warnings that It cannot access that exact file path
com.example.worldcrafter W Unable to open ‘/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.dm’: No such file or directory
2024-12-12 11:50:03.402 20454-20454 ziparchive
com.example.worldcrafter W Unable to open ‘/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.dm’: No such file or directory
`
Here are my implementations:
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.recyclerview)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
implementation("com.aallam.openai:openai-client:3.8.2")
implementation(platform(libs.ktor.bom))
//not using the toml file because i hate it with a burning passion
implementation("io.ktor:ktor-client-core:3.0.2")
implementation("io.ktor:ktor-client-android:3.0.2")
implementation("io.ktor:ktor-client-content-negotiation:3.0.2")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.2")
implementation("io.ktor:ktor-client-logging:3.0.2")
implementation("io.ktor:ktor-client-cio:3.0.2")
}
And here is my MainActivity.kt, which I have slimmed down to only the relevant functions and variables, as it also handles UI switches.
package com.example.worldcrafter
import android.os.Bundle
import android.view.KeyEvent
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.aallam.openai.api.chat.*
import com.aallam.openai.api.model.ModelId
import com.aallam.openai.api.core.Role
import com.aallam.openai.api.http.Timeout
import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIConfig
import com.example.worldcrafter.ui.adapters.ChatAdapter
import com.google.android.material.textfield.TextInputEditText
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
// App startup
class MainActivity() : ComponentActivity() {
val openAI = OpenAI(OpenAIConfig(BuildConfig.OPENAI_API_KEY, timeout = Timeout(socket = 60.seconds)))
var chatGPTResponse: String = ""
// on creation of app
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize the buttons in the Chat layout
private fun initChatButtons() {
// Setup navigation buttons
setupButton(R.id.btSavedChats2) { switchLayout(LayoutType.SAVED_CHATS) }
setupButton(R.id.btSettings2) { switchLayout(LayoutType.SETTINGS) }
// Initialize mutable list to store messages
val messages = mutableListOf<String>()
// Set up RecyclerView and Adapter
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
val chatAdapter = ChatAdapter(messages) // Use ChatAdapter directly
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = chatAdapter
// Reference to TextInputEditText
val inputEditText = findViewById<TextInputEditText>(R.id.textInputEditText)
// Set an action listener to detect "Enter" key
inputEditText.setOnEditorActionListener { _, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE || (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER)) {
val message = inputEditText.text.toString().trim()
if (message.isNotEmpty()) {
// Use addMessage() instead of direct list manipulation
chatAdapter.addMessage(message)
// Scroll to the latest message
recyclerView.smoothScrollToPosition(messages.size - 1)
//chatgpt message here
makeAPIRequest(message)
// Add the response to the list
chatAdapter.addMessage(chatGPTResponse)
recyclerView.smoothScrollToPosition(messages.size - 1)
// Clear the input field
inputEditText.text?.clear()
// Hide the keyboard after the message is added
hideKeyboard()
return@setOnEditorActionListener true
}
}
false
}
}
//chatgpt stuff
@OptIn(DelicateCoroutinesApi::class)
fun makeAPIRequest(message: String) {
// Launch a coroutine to handle the API request asynchronously
GlobalScope.launch(Dispatchers.IO) {
// Create a ChatCompletionRequest to send to OpenAI
val chatRequest = ChatCompletionRequest(
model = ModelId("gpt-3.5-turbo-1106"), // Use the correct model name
messages = mutableListOf(
ChatMessage(
role = Role.User, // User sends the message
content = message // The message entered by the user
)
),
temperature = 0.7,
maxTokens = 150
)
// Send the request to OpenAI API and get the response asynchronously
val response = openAI.chatCompletion(chatRequest)
// Process the response on the main thread
withContext(Dispatchers.Main) {
val responseMessage = response.choices.first().message
// Handle the response here, e.g., update UI or process data
chatGPTResponse = responseMessage.toString()
}
}
}
}
I have tried cleaning and rebuilding, using different versions of both Content Negotiation, Kotlin, and the entirety of Ktor. Any help will be greatly appreciated.
Alexander Mailyants is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
have you checked BuildConfig.OPENAI_API_KEY. Make sure the API_KEY is properly defined in build.gradle or your project configuration.
Or ensure all resources and files required for the app are properly included in the project.
Powerhouse is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
3