Handle errors
This commit is contained in:
parent
48f721e756
commit
597fecd908
4 changed files with 44 additions and 26 deletions
|
@ -39,6 +39,7 @@ import androidx.compose.material3.IconButtonDefaults
|
|||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
|
||||
import androidx.compose.material3.windowsizeclass.WindowSizeClass
|
||||
|
@ -125,7 +126,7 @@ class ChatActivity : ComponentActivity() {
|
|||
if (uiState.requestInProgress) {
|
||||
chatState.composerValue = ""
|
||||
|
||||
// scroll to the last user message too
|
||||
// scroll to the last user message
|
||||
threadViewLazyListState.animateScrollToItem(uiState.messages.size - 2)
|
||||
} else if (uiState.messages.isNotEmpty()) {
|
||||
// scroll to the last user message too
|
||||
|
@ -148,6 +149,14 @@ class ChatActivity : ComponentActivity() {
|
|||
is ChatActivityUiEvent.Error -> {
|
||||
Toast.makeText(context, event.error, Toast.LENGTH_SHORT)
|
||||
.show() // TODO better way of showing this. snackbar?
|
||||
|
||||
// the user might have scrolled so this is good
|
||||
threadViewLazyListState.layoutInfo.visibleItemsInfo.firstOrNull {
|
||||
it.key == "composer"
|
||||
}?.let {
|
||||
chatState.requestFocus()
|
||||
softwareKeyboardController?.show() // TODO perhaps it's pointless to focus since we can click on the toolbar? maybe make it configurable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
@ -51,7 +52,7 @@ class ChatActivityViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
aiApiService.getChatCompletion(ChatCompletionRequest(
|
||||
model = "free-model",
|
||||
model = "i-model",
|
||||
messages = messages,
|
||||
temperature = 1.0f,
|
||||
maxTokens = 128,
|
||||
|
@ -60,7 +61,7 @@ class ChatActivityViewModel @Inject constructor(
|
|||
)).onEach { event ->
|
||||
when (event) {
|
||||
is SseEvent.Open -> {
|
||||
|
||||
// There is nothing to do here
|
||||
}
|
||||
is SseEvent.Event<ChatCompletionResponseEvent> -> {
|
||||
event.data.choices?.firstOrNull()?.let { choice ->
|
||||
|
@ -79,37 +80,28 @@ class ChatActivityViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
is SseEvent.Closed -> {
|
||||
// Closed is not used in case of an error
|
||||
|
||||
messages.add(ChatMessage(
|
||||
role = ChatMessage.Role.Assistant,
|
||||
content = responseContent
|
||||
))
|
||||
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
requestInProgress = false,
|
||||
messages = messages.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
is SseEvent.Failure -> {
|
||||
// TODO here
|
||||
println(event.response?.message)
|
||||
|
||||
_uiEvents.send(ChatActivityUiEvent.Error(event.error.toString()))
|
||||
|
||||
// TODO investigate if closed is called here too
|
||||
// The below should do. More investigation is needed but I believe this should do
|
||||
}
|
||||
}
|
||||
}.catch { exception ->
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
requestInProgress = false
|
||||
)
|
||||
}
|
||||
messages.removeFirst() // Removing the new user message
|
||||
|
||||
_uiEvents.send(ChatActivityUiEvent.Error(exception.toString()))
|
||||
|
||||
// TODO investigate if closed or failure is called
|
||||
}.onCompletion {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
requestInProgress = false,
|
||||
messages = messages.toList()
|
||||
)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
}
|
||||
}
|
|
@ -14,4 +14,4 @@ data class AiApiExceptionDataWrapper(
|
|||
class AiApiException(
|
||||
val httpCode: Int,
|
||||
val error: AiApiExceptionData?
|
||||
) : Exception("SSE HTTP Error: $httpCode")
|
||||
) : Exception("API problem: ${error?.message} (code $httpCode)")
|
|
@ -1,6 +1,8 @@
|
|||
package eu.m724.chatapp.api.retrofit.sse
|
||||
|
||||
import com.google.gson.Gson
|
||||
import eu.m724.chatapp.api.data.AiApiException
|
||||
import eu.m724.chatapp.api.data.AiApiExceptionDataWrapper
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
|
@ -66,8 +68,23 @@ class SseCallAdapter<T : Any>(
|
|||
t: Throwable?,
|
||||
response: Response?
|
||||
) {
|
||||
// TODO aiapiexception here
|
||||
val error = t ?: RuntimeException("Unknown SSE error")
|
||||
val exc = if (response != null) {
|
||||
println("sse response: " + response.code)
|
||||
println("sse response body: " + response.body?.string())
|
||||
|
||||
val apiError =
|
||||
try {
|
||||
gson.fromJson(response.body!!.string(), AiApiExceptionDataWrapper::class.java)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}?.error
|
||||
|
||||
AiApiException(response.code, apiError)
|
||||
} else {
|
||||
t
|
||||
}
|
||||
|
||||
val error = exc ?: RuntimeException("Unknown SSE error")
|
||||
trySend(SseEvent.Failure(error, response))
|
||||
close(error)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue