fix: ollama form combobox state (fixes #606)

This commit is contained in:
Carl-Robert Linnupuu 2024-07-03 17:00:00 +03:00
parent 1b6a7f2156
commit c193695fc1

View file

@ -1,8 +1,8 @@
package ee.carlrobert.codegpt.settings.service.ollama
import com.intellij.notification.NotificationType
import com.intellij.openapi.application.invokeLater
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.observable.util.whenTextChangedFromUi
@ -11,6 +11,7 @@ import com.intellij.openapi.ui.MessageType
import com.intellij.ui.TitledSeparator
import com.intellij.ui.components.JBPasswordField
import com.intellij.ui.components.JBTextField
import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.ui.FormBuilder
import ee.carlrobert.codegpt.CodeGPTBundle
import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.OLLAMA_API_KEY
@ -26,6 +27,7 @@ import kotlinx.coroutines.runBlocking
import java.awt.BorderLayout
import java.lang.String.format
import java.net.ConnectException
import java.util.concurrent.TimeoutException
import javax.swing.ComboBoxModel
import javax.swing.DefaultComboBoxModel
import javax.swing.JButton
@ -62,7 +64,9 @@ class OllamaSettingsForm {
modelComboBox.isEnabled = false
}
}
refreshModelsButton.addActionListener { refreshModels(getModel() ?: settings.model) }
refreshModelsButton.addActionListener {
refreshModels(getModel() ?: settings.model)
}
apiKeyField = JBPasswordField().apply {
columns = 30
text = runBlocking(Dispatchers.IO) {
@ -140,10 +144,10 @@ class OllamaSettingsForm {
|| getApiKey() != getCredential(OLLAMA_API_KEY)
}
fun refreshModels(currentModel: String?) {
private fun refreshModels(currentModel: String?) {
disableModelComboBoxWithPlaceholder(DefaultComboBoxModel(arrayOf("Loading")))
try {
val models = runBlocking(Dispatchers.IO) {
ReadAction.nonBlocking<List<String>> {
try {
OllamaClient.Builder()
.setHost(hostField.text)
.setApiKey(getApiKey())
@ -151,52 +155,62 @@ class OllamaSettingsForm {
.modelTags
.models
.map { it.name }
} catch (t: Throwable) {
handleModelLoadingError(t)
throw t
}
service<OllamaSettings>().state.availableModels = models.toMutableList()
runInEdt {
modelComboBox.apply {
if (models.isNotEmpty()) {
model = DefaultComboBoxModel(models.toTypedArray())
currentModel?.let {
if (models.contains(currentModel)) {
selectedItem = currentModel
} else {
OverlayUtil.showBalloon(
format(
CodeGPTBundle.get("validation.error.model.notExists"),
currentModel
),
MessageType.ERROR,
modelComboBox
)
}
}
isEnabled = true
} else {
model = DefaultComboBoxModel(arrayOf("No models"))
}
}
.finishOnUiThread(ModalityState.defaultModalityState()) { models ->
updateModelComboBoxState(models, currentModel)
}
.submit(AppExecutorUtil.getAppExecutorService())
}
private fun updateModelComboBoxState(models: List<String>, currentModel: String?) {
if (models.isNotEmpty()) {
modelComboBox.model = DefaultComboBoxModel(models.toTypedArray())
modelComboBox.isEnabled = true
currentModel?.let {
if (models.contains(currentModel)) {
modelComboBox.selectedItem = currentModel
} else {
OverlayUtil.showBalloon(
format(
CodeGPTBundle.get("validation.error.model.notExists"),
currentModel
),
MessageType.ERROR,
modelComboBox
)
}
}
} catch (ex: RuntimeException) {
logger.error(ex)
if (ex.cause is ConnectException) {
OverlayUtil.showNotification(
"Unable to connect to Ollama server",
NotificationType.ERROR
)
} else {
OverlayUtil.showNotification(ex.message ?: "Error", NotificationType.ERROR)
}
disableModelComboBoxWithPlaceholder(DefaultComboBoxModel(arrayOf("Unable to load models")))
} else {
modelComboBox.model = DefaultComboBoxModel(arrayOf("No models"))
}
}
private fun handleModelLoadingError(ex: Throwable) {
logger.error(ex)
when (ex) {
is TimeoutException -> OverlayUtil.showNotification(
"Connection to Ollama server timed out",
NotificationType.ERROR
)
is ConnectException -> OverlayUtil.showNotification(
"Unable to connect to Ollama server",
NotificationType.ERROR
)
else -> OverlayUtil.showNotification(ex.message ?: "Error", NotificationType.ERROR)
}
disableModelComboBoxWithPlaceholder(DefaultComboBoxModel(arrayOf("Unable to load models")))
}
private fun disableModelComboBoxWithPlaceholder(placeholderModel: ComboBoxModel<String>) {
invokeLater {
modelComboBox.apply {
model = placeholderModel
isEnabled = false
}
modelComboBox.apply {
model = placeholderModel
isEnabled = false
}
}
}