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
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ fun GalleryTopAppBar(

// Click a button to navigate up.
AppBarActionType.NAVIGATE_UP -> {
TextButton(onClick = rightAction.actionFn) { Text("Done") }
TextButton(onClick = rightAction.actionFn) { Text(stringResource(R.string.done)) }
}

else -> {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

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

import androidx.annotation.StringRes
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import com.squareup.moshi.JsonClass
Expand Down Expand Up @@ -65,6 +66,7 @@ data class SkillTryOutChip(
val label: String,
val prompt: String,
val skillName: String,
@StringRes val labelResId: Int = 0,
)

data class SkillInfo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ private fun ScriptsTabContent(
AlertDialog(
onDismissRequest = { showDeleteConfirmation = false },
title = { Text(stringResource(R.string.delete_script_dialog_title)) },
text = { Text("Are you sure you want to delete '$selectedScript'?") },
text = { Text(stringResource(R.string.delete_script_confirmation, selectedScript ?: "")) },
confirmButton = {
Button(
onClick = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,14 +376,14 @@ fun AgentChatScreen(
)
Text(
buildAnnotatedString {
append("Use specialized, high-order reasoning by loading different skills or ")
append(stringResource(R.string.agent_skills_description_part1))
append(
buildTrackableUrlAnnotatedString(
url = "https://github.com/google-ai-edge/gallery/tree/main/skills",
linkText = "creating\u00A0your\u00A0own",
linkText = stringResource(R.string.agent_skills_link_text),
)
)
append(".\n\nTry tapping a sample prompt below to see Agent Skills in action!")
append(stringResource(R.string.agent_skills_description_part2))
},
style =
MaterialTheme.typography.headlineSmall.copy(fontSize = 16.sp, lineHeight = 22.sp),
Expand Down Expand Up @@ -434,7 +434,10 @@ fun AgentChatScreen(
) {
Icon(promptChip.icon, contentDescription = null, modifier = Modifier.size(20.dp))
Spacer(modifier = Modifier.width(4.dp))
Text(promptChip.label)
Text(
if (promptChip.labelResId != 0) stringResource(promptChip.labelResId)
else promptChip.label
)
}
}
}
Expand Down Expand Up @@ -490,7 +493,7 @@ fun AgentChatScreen(
if (showAlertForDisabledSkill) {
AlertDialog(
onDismissRequest = { showAlertForDisabledSkill = false },
title = { Text("The \"$disabledSkillName\" skill is currently disabled") },
title = { Text(stringResource(R.string.skill_disabled_title, disabledSkillName)) },
text = { Text(stringResource(R.string.enable_skill_dialog_content)) },
confirmButton = {
Button(onClick = { showAlertForDisabledSkill = false }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,25 @@ import com.google.ai.edge.litertlm.tool
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope

class AgentChatTask @Inject constructor() : CustomTask {
class AgentChatTask @Inject constructor(private val context: Context) : CustomTask {
private val agentTools = AgentTools()

override val task: Task =
Task(
id = BuiltInTaskId.LLM_AGENT_CHAT,
label = "Agent Skills",
label = context.getString(R.string.task_agent_chat_label),
category = Category.LLM,
iconVectorResourceId = R.drawable.agent,
newFeature = true,
models = mutableListOf(),
description = "Chat with on-device large language models with skills and tools",
shortDescription = "Complete agentic tasks with chat",
description = context.getString(R.string.task_agent_chat_description),
shortDescription = context.getString(R.string.task_agent_chat_short_description),
docUrl = "https://github.com/google-ai-edge/LiteRT-LM/blob/main/kotlin/README.md",
sourceCodeUrl =
"https://github.com/google-ai-edge/gallery/blob/main/Android/src/app/src/main/java/com/google/ai/edge/gallery/customtasks/agentchat/",
Expand Down Expand Up @@ -122,7 +123,7 @@ class AgentChatTask @Inject constructor() : CustomTask {
internal object AgentChatTaskModule {
@Provides
@IntoSet
fun provideTask(): CustomTask {
return AgentChatTask()
fun provideTask(@ApplicationContext context: Context): CustomTask {
return AgentChatTask(context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.google.ai.edge.gallery.data.AllowedSkill
import com.google.ai.edge.gallery.data.DataStoreRepository
import com.google.ai.edge.gallery.data.SkillAllowlist
import com.google.ai.edge.gallery.proto.Skill
import com.google.ai.edge.gallery.R
import com.google.ai.edge.litertlm.Contents
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
Expand Down Expand Up @@ -69,49 +70,57 @@ val TRYOUT_CHIPS: List<SkillTryOutChip> =
label = "Interactive Map",
prompt = "Show me Googleplex on interactive map.",
skillName = "interactive-map",
labelResId = R.string.skill_chip_interactive_map,
),
SkillTryOutChip(
icon = Icons.Outlined.Kitchen,
label = "Kitchen Adventure",
prompt = "Start kitchen adventure",
skillName = "kitchen-adventure",
labelResId = R.string.skill_chip_kitchen_adventure,
),
SkillTryOutChip(
icon = Icons.Outlined.Tag,
label = "Calculate Hash",
prompt = "What is the sha1 hash of \"gemma\"?",
skillName = "calculate-hash",
labelResId = R.string.skill_chip_calculate_hash,
),
SkillTryOutChip(
icon = Icons.Outlined.ScreenRotation,
label = "Text Spinner",
prompt = "Spin \"Gemma\" on my head",
skillName = "text-spinner",
labelResId = R.string.skill_chip_text_spinner,
),
SkillTryOutChip(
icon = Icons.Outlined.Email,
label = "Send Email",
prompt = "Send email 'Good morning' to abc@example.com. Content: 'Any plans for tonight?'",
skillName = "send-email",
labelResId = R.string.skill_chip_send_email,
),
SkillTryOutChip(
icon = Icons.Outlined.SentimentVerySatisfied,
label = "Track my mood",
prompt =
"Log yesterday's mood as 2 because it was raining quite heavily, and log today's mood as 9 because I had a great time playing pickleball again. Then show me my mood dashboard.",
skillName = "mood-tracker",
labelResId = R.string.skill_chip_track_mood,
),
SkillTryOutChip(
icon = Icons.Outlined.LocalLibrary,
label = "Query Wikipedia",
prompt = "Check Wikipedia about Oscars 2026. Tell me who won the best picture.",
skillName = "query-wikipedia",
labelResId = R.string.skill_chip_query_wikipedia,
),
SkillTryOutChip(
icon = Icons.Outlined.QrCode,
label = "Generate QR code",
prompt = "Generate QR code for https://deepmind.google/models/gemma/",
skillName = "qr-code",
labelResId = R.string.skill_chip_generate_qr_code,
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ fun SkillTesterBottomSheet(agentTools: AgentTools, skill: Skill, onDismiss: () -
OutlinedTextField(
value = inputData,
onValueChange = { inputData = it },
label = { Text("Input Data") },
label = { Text(stringResource(R.string.input_data)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
)

// Input for "custom data"
OutlinedTextField(
value = customData,
onValueChange = { customData = it },
label = { Text("Custom Data") },
label = { Text(stringResource(R.string.custom_data)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.google.ai.edge.gallery.R
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
Expand All @@ -63,9 +65,9 @@ data class ExampleCustomTaskModelInstance(val content: String)
* These keys are used to uniquely identify and retrieve values for configurable parameters within a
* model.
*/
val EXAMPLE_CUSTOM_TASK_CONFIG_KEY_FONT_SIZE = ConfigKey(id = "font_size", label = "Font size")
val EXAMPLE_CUSTOM_TASK_CONFIG_KEY_FONT_SIZE = ConfigKey(id = "font_size", label = "Font size", labelResId = R.string.config_label_font_size)
val EXAMPLE_CUSTOM_TASK_CONFIG_KEY_MAX_CHAR_COUNT =
ConfigKey(id = "max_char_count", label = "Max character count")
ConfigKey(id = "max_char_count", label = "Max character count", labelResId = R.string.config_label_max_char_count)

/**
* A list of configurable parameters for the `ExampleCustomTask`'s models.
Expand Down Expand Up @@ -132,7 +134,10 @@ fun ExampleCustomTaskScreen(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(16.dp),
) {
Text("Text color: ")
Text(
stringResource(R.string.text_color_label),
color = MaterialTheme.colorScheme.onSurface,
)
for (color in colors) {
Box(
modifier =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
*/
package com.google.ai.edge.gallery.customtasks.mobileactions

import android.content.Context
import com.google.ai.edge.gallery.customtasks.common.CustomTask
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet

Expand All @@ -27,7 +29,7 @@ import dagger.multibindings.IntoSet
internal object MobileActionsModule {
@Provides
@IntoSet
fun provideTask(): CustomTask {
return MobileActionsTask()
fun provideTask(@ApplicationContext context: Context): CustomTask {
return MobileActionsTask(context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ private const val TAG = "AGMATask"
* A custom task that demonstrates how to use function calling to control various device
* functionalities.
*/
class MobileActionsTask @Inject constructor() : CustomTask {
class MobileActionsTask @Inject constructor(private val context: Context) : CustomTask {
private var curActions = mutableStateListOf<Action>()
private val tools = listOf(tool(MobileActionsTools(onFunctionCalled = { curActions.add(it) })))

override val task =
Task(
id = BuiltInTaskId.LLM_MOBILE_ACTIONS,
label = "Mobile Actions",
description = "Perform various device actions through Function Gemma",
shortDescription = "Leverage device mobile actions",
label = context.getString(R.string.task_mobile_actions_label),
description = context.getString(R.string.task_mobile_actions_description),
shortDescription = context.getString(R.string.task_mobile_actions_short_description),
docUrl = "https://github.com/google-ai-edge/LiteRT-LM/blob/main/kotlin/README.md",
sourceCodeUrl =
"https://github.com/google-ai-edge/gallery/blob/main/Android/src/app/src/main/java/com/google/ai/edge/gallery/customtasks/mobileactions",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Tips:
"""

/** A custom task that demonstrates how to use FunctionGemma to play a simple gardening game. */
class TinyGardenTask @Inject constructor() : CustomTask {
class TinyGardenTask @Inject constructor(private val context: Context) : CustomTask {
private val _updateChannel = Channel<TinyGardenCommand>(Channel.BUFFERED)
private val commandFlow = _updateChannel.receiveAsFlow()
private val tools =
Expand All @@ -84,10 +84,9 @@ class TinyGardenTask @Inject constructor() : CustomTask {
override val task =
Task(
id = BuiltInTaskId.LLM_TINY_GARDEN,
label = "Tiny Garden",
description =
"Use natural language to plant, water, and harvest in this fully offline mini-game.\n\nNote: This is powered by the experimental FunctionGemma model optimized for latency. Due to its compact size (270M), it works well on simple instructions but responses may vary to more complex interactions.",
shortDescription = "Use natural language to plant",
label = context.getString(R.string.task_tiny_garden_label),
description = context.getString(R.string.task_tiny_garden_description),
shortDescription = context.getString(R.string.task_tiny_garden_short_description),
docUrl = "https://github.com/google-ai-edge/LiteRT-LM/blob/main/kotlin/README.md",
sourceCodeUrl =
"https://github.com/google-ai-edge/gallery/blob/main/Android/src/app/src/main/java/com/google/ai/edge/gallery/customtasks/tinygarden",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
*/
package com.google.ai.edge.gallery.customtasks.tinygarden

import android.content.Context
import com.google.ai.edge.gallery.customtasks.common.CustomTask
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet

Expand All @@ -27,7 +29,7 @@ import dagger.multibindings.IntoSet
internal object TinyGardenTaskModule {
@Provides
@IntoSet
fun provideTask(): CustomTask {
return TinyGardenTask()
fun provideTask(@ApplicationContext context: Context): CustomTask {
return TinyGardenTask(context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.ai.edge.gallery.data

import androidx.annotation.StringRes
import com.google.ai.edge.gallery.R
import kotlin.math.abs

/**
Expand All @@ -42,40 +43,40 @@ enum class ValueType {
BOOLEAN,
}

data class ConfigKey(val id: String, val label: String)
data class ConfigKey(val id: String, val label: String, @StringRes val labelResId: Int? = null)

object ConfigKeys {
val MAX_TOKENS = ConfigKey("max_tokens", "Max tokens")
val TOPK = ConfigKey("topk", "TopK")
val TOPP = ConfigKey("topp", "TopP")
val TEMPERATURE = ConfigKey("temperature", "Temperature")
val DEFAULT_MAX_TOKENS = ConfigKey("default_max_tokens", "Default max tokens")
val DEFAULT_TOPK = ConfigKey("default_topk", "Default TopK")
val DEFAULT_TOPP = ConfigKey("default_topp", "Default TopP")
val DEFAULT_TEMPERATURE = ConfigKey("default_temperature", "Default temperature")
val SUPPORT_IMAGE = ConfigKey("support_image", "Support image")
val SUPPORT_AUDIO = ConfigKey("support_audio", "Support audio")
val SUPPORT_TINY_GARDEN = ConfigKey("support_tiny_garden", "Support tiny garden")
val SUPPORT_MOBILE_ACTIONS = ConfigKey("support_mobile_actions", "Support mobile actions")
val SUPPORT_THINKING = ConfigKey("support_thinking", "Support thinking")
val ENABLE_THINKING = ConfigKey("enable_thinking", "Enable thinking")
val MAX_RESULT_COUNT = ConfigKey("max_result_count", "Max result count")
val USE_GPU = ConfigKey("use_gpu", "Use GPU")
val ACCELERATOR = ConfigKey("accelerator", "Accelerator")
val VISION_ACCELERATOR = ConfigKey("vision_accelerator", "Vision accelerator")
val COMPATIBLE_ACCELERATORS = ConfigKey("compatible_accelerators", "Compatible accelerators")
val WARM_UP_ITERATIONS = ConfigKey("warm_up_iterations", "Warm up iterations")
val BENCHMARK_ITERATIONS = ConfigKey("benchmark_iterations", "Benchmark iterations")
val ITERATIONS = ConfigKey("iterations", "Iterations")
val THEME = ConfigKey("theme", "Theme")
val NAME = ConfigKey("name", "Name")
val MODEL_TYPE = ConfigKey("model_type", "Model type")
val MODEL = ConfigKey("model", "Model")
val MAX_TOKENS = ConfigKey("max_tokens", "Max tokens", R.string.config_label_max_tokens)
val TOPK = ConfigKey("topk", "TopK", R.string.config_label_topk)
val TOPP = ConfigKey("topp", "TopP", R.string.config_label_topp)
val TEMPERATURE = ConfigKey("temperature", "Temperature", R.string.config_label_temperature)
val DEFAULT_MAX_TOKENS = ConfigKey("default_max_tokens", "Default max tokens", R.string.config_label_default_max_tokens)
val DEFAULT_TOPK = ConfigKey("default_topk", "Default TopK", R.string.config_label_default_topk)
val DEFAULT_TOPP = ConfigKey("default_topp", "Default TopP", R.string.config_label_default_topp)
val DEFAULT_TEMPERATURE = ConfigKey("default_temperature", "Default temperature", R.string.config_label_default_temperature)
val SUPPORT_IMAGE = ConfigKey("support_image", "Support image", R.string.config_label_support_image)
val SUPPORT_AUDIO = ConfigKey("support_audio", "Support audio", R.string.config_label_support_audio)
val SUPPORT_TINY_GARDEN = ConfigKey("support_tiny_garden", "Support tiny garden", R.string.config_label_support_tiny_garden)
val SUPPORT_MOBILE_ACTIONS = ConfigKey("support_mobile_actions", "Support mobile actions", R.string.config_label_support_mobile_actions)
val SUPPORT_THINKING = ConfigKey("support_thinking", "Support thinking", R.string.config_label_support_thinking)
val ENABLE_THINKING = ConfigKey("enable_thinking", "Enable thinking", R.string.config_label_enable_thinking)
val MAX_RESULT_COUNT = ConfigKey("max_result_count", "Max result count", R.string.config_label_max_result_count)
val USE_GPU = ConfigKey("use_gpu", "Use GPU", R.string.config_label_use_gpu)
val ACCELERATOR = ConfigKey("accelerator", "Accelerator", R.string.config_label_accelerator)
val VISION_ACCELERATOR = ConfigKey("vision_accelerator", "Vision accelerator", R.string.config_label_vision_accelerator)
val COMPATIBLE_ACCELERATORS = ConfigKey("compatible_accelerators", "Compatible accelerators", R.string.config_label_compatible_accelerators)
val WARM_UP_ITERATIONS = ConfigKey("warm_up_iterations", "Warm up iterations", R.string.config_label_warm_up_iterations)
val BENCHMARK_ITERATIONS = ConfigKey("benchmark_iterations", "Benchmark iterations", R.string.config_label_benchmark_iterations)
val ITERATIONS = ConfigKey("iterations", "Iterations", R.string.config_label_iterations)
val THEME = ConfigKey("theme", "Theme", R.string.config_label_theme)
val NAME = ConfigKey("name", "Name", R.string.config_label_name)
val MODEL_TYPE = ConfigKey("model_type", "Model type", R.string.config_label_model_type)
val MODEL = ConfigKey("model", "Model", R.string.config_label_model)
val RESET_CONVERSATION_TURN_COUNT =
ConfigKey("reset_conversation_turn_count", "Number of turns before the conversation resets")
val PREFILL_TOKENS = ConfigKey("prefill_tokens", "Prefill tokens")
val DECODE_TOKENS = ConfigKey("decode_tokens", "Decode tokens")
val NUMBER_OF_RUNS = ConfigKey("number_of_runs", "Number of runs")
ConfigKey("reset_conversation_turn_count", "Number of turns before the conversation resets", R.string.config_label_reset_conversation_turn_count)
val PREFILL_TOKENS = ConfigKey("prefill_tokens", "Prefill tokens", R.string.config_label_prefill_tokens)
val DECODE_TOKENS = ConfigKey("decode_tokens", "Decode tokens", R.string.config_label_decode_tokens)
val NUMBER_OF_RUNS = ConfigKey("number_of_runs", "Number of runs", R.string.config_label_number_of_runs)
}

/**
Expand Down
Loading