Skip to content

Commit 8dd71bf

Browse files
Update PhotoReasoningViewModel.kt
1 parent ade77ee commit 8dd71bf

File tree

1 file changed

+53
-13
lines changed

1 file changed

+53
-13
lines changed

app/src/main/kotlin/com/google/ai/sample/feature/multimodal/PhotoReasoningViewModel.kt

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ class PhotoReasoningViewModel(
119119
private var commandProcessingJob: Job? = null
120120
private val stopExecutionFlag = AtomicBoolean(false)
121121

122+
// Added for retry on quota exceeded
123+
private var currentRetryAttempt = 0
124+
private var currentScreenInfoForPrompt: String? = null
125+
private var currentImageUrisForChat: List<String>? = null
126+
122127
private val aiResultReceiver = object : BroadcastReceiver() {
123128
override fun onReceive(context: Context?, intent: Intent?) {
124129
if (intent?.action == ScreenCaptureService.ACTION_AI_CALL_RESULT) {
@@ -134,9 +139,43 @@ class PhotoReasoningViewModel(
134139
saveChatHistory(MainActivity.getInstance()?.applicationContext)
135140
} else if (errorMessage != null) {
136141
Log.e(TAG, "AI Call Error via Broadcast: $errorMessage")
142+
val receiverContext = context ?: {
143+
Log.e(TAG, "Context null in receiver, cannot handle error")
144+
return
145+
}()
137146
_uiState.value = PhotoReasoningUiState.Error(errorMessage)
138147
_commandExecutionStatus.value = "Error during AI generation: $errorMessage"
139148
_chatState.replaceLastPendingMessage()
149+
150+
val apiKeyManager = ApiKeyManager.getInstance(receiverContext)
151+
val isQuotaError = isQuotaExceededError(errorMessage)
152+
153+
if (isQuotaError && currentRetryAttempt < MAX_RETRY_ATTEMPTS) {
154+
val currentKey = apiKeyManager.getCurrentApiKey()
155+
if (currentKey != null) {
156+
apiKeyManager.markKeyAsFailed(currentKey)
157+
val newKey = apiKeyManager.switchToNextAvailableKey()
158+
if (newKey != null) {
159+
// Increment retry attempt
160+
currentRetryAttempt++
161+
// Remove the last user message (pending already removed)
162+
val messages = _chatState.messages
163+
if (messages.isNotEmpty() && messages.last().participant == PhotoParticipant.USER) {
164+
_chatState.messages.removeLast()
165+
}
166+
// Retry by calling performReasoning with stored parameters
167+
performReasoning(
168+
currentUserInput,
169+
currentSelectedImages,
170+
currentScreenInfoForPrompt,
171+
currentImageUrisForChat
172+
)
173+
return // Exit without adding error message
174+
}
175+
}
176+
}
177+
178+
// Normal error handling if not quota or max retries reached
140179
_chatState.addMessage(
141180
PhotoReasoningMessage(
142181
text = errorMessage,
@@ -235,6 +274,8 @@ class PhotoReasoningViewModel(
235274
// Store the current user input and selected images
236275
currentUserInput = userInput // This should ideally store aiPromptText or handle context separately if needed for retry. For now, task is specific to prompt to AI and chat.
237276
currentSelectedImages = selectedImages
277+
currentScreenInfoForPrompt = screenInfoForPrompt
278+
currentImageUrisForChat = imageUrisForChat
238279

239280
// Clear previous commands
240281
_detectedCommands.value = emptyList()
@@ -319,6 +360,7 @@ class PhotoReasoningViewModel(
319360
return
320361
}
321362
ensureInitialized(context)
363+
currentRetryAttempt = 0 // Reset retry attempt on new reason call
322364
performReasoning(userInput, selectedImages, screenInfoForPrompt, imageUrisForChat)
323365
}
324366

@@ -546,8 +588,9 @@ class PhotoReasoningViewModel(
546588
_isInitialized.value = true // Add this line
547589
}
548590

549-
// Removed isQuotaExceededError, is503Error, handleQuotaExceededError, and handle503Error methods
550-
// as this logic is now delegated to the ScreenCaptureService.
591+
private fun isQuotaExceededError(message: String): Boolean {
592+
return message.contains("exceeded your current quota")
593+
}
551594

552595
/**
553596
* Helper function to format database entries as text.
@@ -927,30 +970,27 @@ class PhotoReasoningViewModel(
927970
* Chat state management class
928971
*/
929972
private class ChatState {
930-
private val _messages = mutableListOf<PhotoReasoningMessage>()
931-
932-
val messages: List<PhotoReasoningMessage>
933-
get() = _messages.toList()
973+
val messages = mutableListOf<PhotoReasoningMessage>() // Changed to mutableListOf for direct access in receiver
934974

935975
fun addMessage(message: PhotoReasoningMessage) {
936-
_messages.add(message)
976+
messages.add(message)
937977
}
938978

939979
fun clearMessages() {
940-
_messages.clear()
980+
messages.clear()
941981
}
942982

943983
fun replaceLastPendingMessage() {
944-
val lastPendingIndex = _messages.indexOfLast { it.isPending }
984+
val lastPendingIndex = messages.indexOfLast { it.isPending }
945985
if (lastPendingIndex >= 0) {
946-
_messages.removeAt(lastPendingIndex)
986+
messages.removeAt(lastPendingIndex)
947987
}
948988
}
949989

950990
fun updateLastMessageText(newText: String) {
951-
if (_messages.isNotEmpty()) {
952-
val lastMessage = _messages.last()
953-
_messages[_messages.size -1] = lastMessage.copy(text = newText, isPending = false)
991+
if (messages.isNotEmpty()) {
992+
val lastMessage = messages.last()
993+
messages[messages.size -1] = lastMessage.copy(text = newText, isPending = false)
954994
}
955995
}
956996
}

0 commit comments

Comments
 (0)