Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Android/src/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ android {
applicationId = "com.google.aiedge.gallery"
minSdk = 31
targetSdk = 35
versionCode = 29
versionName = "1.0.12"
versionCode = 30
versionName = "1.0.13"

// Needed for HuggingFace auth workflows.
// Use the scheme of the "Redirect URLs" in HuggingFace app.
Expand Down
2 changes: 1 addition & 1 deletion Android/src/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="gallery_high_priority_push_channel" />

<uses-native-library android:name="libvndksupport.so" android:required="false"/>
<uses-native-library android:name="libOpenCL.so" android:required="false"/>
<uses-native-library android:name="libcdsprpc.so" android:required="false" />
<uses-native-library android:name="libedgetpu_litert.so" android:required="false" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.ai.edge.gallery.common

import com.google.ai.edge.gallery.data.SystemPromptRepository
import com.google.ai.edge.gallery.data.Task
import kotlinx.coroutines.flow.firstOrNull

/** Helper object for system prompt retrieval and compilation. */
object SystemPromptHelper {

/**
* Retrieves the effective system prompt for the given [Task].
*
* Returns the user-defined custom prompt from the [SystemPromptRepository] if available;
* otherwise, falls back to the task's default system prompt.
*
* @param repo The optional [SystemPromptRepository] for custom overrides. If null, returns the
* default.
* @param task The target [Task] containing the identifier and the default fallback system prompt.
* @return A [String] representing the effective system prompt instructions.
*/
suspend fun getEffectiveSystemPrompt(repo: SystemPromptRepository?, task: Task): String {
if (repo == null) return task.defaultSystemPrompt
val customPrompt = repo.getCustomSystemPrompt(task.id).firstOrNull()
return customPrompt ?: task.defaultSystemPrompt
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.ime
Expand All @@ -36,7 +37,9 @@ import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.exifinterface.media.ExifInterface
import com.google.ai.edge.gallery.GalleryEvent
import com.google.ai.edge.gallery.data.SAMPLE_RATE
import com.google.ai.edge.gallery.firebaseAnalytics
import com.google.gson.Gson
import java.io.File
import java.io.FileInputStream
Expand Down Expand Up @@ -378,3 +381,14 @@ fun isAICoreSupported(allowedDeviceModels: Set<String>?): Boolean {
val currentModel = Build.MODEL?.lowercase() ?: return false
return allowedDeviceModels.contains(currentModel)
}

fun logErrorToFirebase(event: GalleryEvent, errorType: String, errorMessage: String?) {
firebaseAnalytics?.logEvent(
event.id,
Bundle().apply {
putBoolean("success", false)
putString("error_type", errorType)
putString("error_message", errorMessage ?: "Unknown error")
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.ai.edge.gallery.R
import com.google.ai.edge.gallery.ui.common.CursorTrackingTextField
import com.google.ai.edge.gallery.ui.theme.customColors
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ fun AgentChatScreen(
showAudioPicker = true,
getActiveSkills = {
skillManagerViewModel.getSelectedSkills().map { skill ->
if (skill.builtIn) skill.name else "custom_skill"
skillManagerViewModel.getSkillShortId(skill)
}
},
composableBelowMessageList = { model ->
Expand Down Expand Up @@ -236,6 +236,8 @@ fun AgentChatScreen(
} else {
action.url
}
val skill = skillManagerViewModel.getSkill(name = skillName)
val skillId = skill?.let { skillManagerViewModel.getSkillShortId(it) } ?: "xxxx"
try {
// Set up a safety net timeout so we NEVER hang the chat or tool execution
launch {
Expand All @@ -250,6 +252,7 @@ fun AgentChatScreen(
GalleryEvent.SKILL_EXECUTION.id,
Bundle().apply {
putString("skill_name", skillName)
putString("skill_id", skillId)
putBoolean("success", false)
putString("error_type", "timeout")
},
Expand Down Expand Up @@ -285,6 +288,7 @@ fun AgentChatScreen(
GalleryEvent.SKILL_EXECUTION.id,
Bundle().apply {
putString("skill_name", skillName)
putString("skill_id", skillId)
putBoolean("success", isSuccess)
putString("error_type", errorType)
},
Expand Down Expand Up @@ -323,6 +327,7 @@ fun AgentChatScreen(
GalleryEvent.SKILL_EXECUTION.id,
Bundle().apply {
putString("skill_name", skillName)
putString("skill_id", skillId)
putBoolean("success", false)
putString("error_type", "exception")
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class AgentChatTask @Inject constructor() : CustomTask {
LlmChatModelHelper.initialize(
context = context,
model = model,
taskId = task.id,
supportImage = true,
supportAudio = true,
onDone = onDone,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import kotlinx.coroutines.runBlocking

private const val TAG = "AGAgentTools"

class AgentTools() : ToolSet {
open class AgentTools() : ToolSet {
lateinit var context: Context
lateinit var skillManagerViewModel: SkillManagerViewModel

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.ai.edge.gallery.R
import com.google.ai.edge.gallery.ui.common.CursorTrackingTextField
import kotlinx.coroutines.launch

private val PROMPT_TEMPLATE =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -173,7 +175,7 @@ fun SkillManagerBottomSheet(
var addSkillOptionTypeToConfirm by remember { mutableStateOf<AddSkillOptionType?>(null) }
var skillToEditIndex by remember { mutableIntStateOf(-1) }
var searchQuery by remember { mutableStateOf("") }
var savedSelectedSkillsNamesAndDescriptions = remember { "" }
var savedSelectedSkillsNamesAndDescriptions by remember { mutableStateOf("") }
var filteredSkills by remember { mutableStateOf(uiState.skills) }
val listState = rememberLazyListState()
val uriHandler = LocalUriHandler.current
Expand Down Expand Up @@ -860,7 +862,8 @@ private fun SkillItemRow(
Switch(
checked = skill.selected,
onCheckedChange = onSkillEnabledChange,
modifier = Modifier.offset(y = (-4).dp),
modifier =
Modifier.offset(y = (-4).dp).semantics { contentDescription = "Toggle ${skill.name}" },
enabled = !inMultiSelectMode,
)
}
Expand Down
Loading
Loading