Skip to content

Commit 9d0db45

Browse files
Make android demo app responsive and improve some ux (#116)
1 parent 58e8f3a commit 9d0db45

5 files changed

Lines changed: 99 additions & 30 deletions

File tree

llm/android/LlamaDemo/app/build.gradle.kts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@ dependencies {
6363
if (useLocalAar == true) {
6464
implementation(files("libs/executorch.aar"))
6565
} else {
66-
implementation("org.pytorch:executorch-android:1.0.0")
66+
implementation("org.pytorch:executorch-android:1.0.1")
67+
// https://mvnrepository.com/artifact/org.pytorch/executorch-android-qnn
68+
// Uncomment this to enable QNN
69+
// implementation("org.pytorch:executorch-android-qnn:1.0.1")
70+
71+
// https://mvnrepository.com/artifact/org.pytorch/executorch-android-vulkan
72+
// uncomment to enable vulkan
73+
// implementation("org.pytorch:executorch-android-vulkan:1.0.1")
6774
}
6875
implementation("com.google.android.material:material:1.12.0")
6976
implementation("androidx.activity:activity:1.9.0")

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/MainActivity.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -775,9 +775,17 @@ private void onModelRunStopped() {
775775
}
776776
addSelectedImagesToChatThread(mSelectedImageUri);
777777
String rawPrompt = mEditTextMessage.getText().toString();
778-
String finalPrompt =
779-
(shouldAddSystemPrompt ? mCurrentSettingsFields.getFormattedSystemPrompt() : "")
780-
+ mCurrentSettingsFields.getFormattedUserPrompt(rawPrompt, mThinkMode);
778+
String finalPrompt;
779+
// For LLaVA, the first turn uses a special template since the preset prompt
780+
// already ends with "USER: "
781+
if (mCurrentSettingsFields.getModelType() == ModelType.LLAVA_1_5 && shouldAddSystemPrompt) {
782+
finalPrompt = PromptFormat.getLlavaFirstTurnUserPrompt()
783+
.replace(PromptFormat.USER_PLACEHOLDER, rawPrompt);
784+
} else {
785+
finalPrompt =
786+
(shouldAddSystemPrompt ? mCurrentSettingsFields.getFormattedSystemPrompt() : "")
787+
+ mCurrentSettingsFields.getFormattedUserPrompt(rawPrompt, mThinkMode);
788+
}
781789
shouldAddSystemPrompt = false;
782790
// We store raw prompt into message adapter, because we don't want to show the extra
783791
// tokens from system prompt

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/PromptFormat.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static String getUserPromptTemplate(ModelType modelType) {
4747
+ "<|im_start|>assistant\n"
4848
+ THINKING_MODE_PLACEHOLDER;
4949
case LLAVA_1_5:
50-
return "User: " + USER_PLACEHOLDER;
50+
return " USER: " + USER_PLACEHOLDER + " ASSISTANT:";
5151
default:
5252
return USER_PLACEHOLDER;
5353
}
@@ -101,6 +101,9 @@ public static String getLlavaPresetPrompt() {
101101
+ " gives helpful, detailed, and polite answers to the human's questions. USER: ";
102102
}
103103

104+
public static String getLlavaFirstTurnUserPrompt() {
105+
return USER_PLACEHOLDER + " ASSISTANT:";
106+
}
104107
public static String getFormattedLlamaGuardPrompt(String userPrompt) {
105108
return getUserPromptTemplate(ModelType.LLAMA_GUARD_3)
106109
.replace(

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/SettingsActivity.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,22 +93,51 @@ private void setupSettings() {
9393
view -> {
9494
setupBackendSelectorDialog();
9595
});
96+
requireViewById(R.id.backendLayout)
97+
.setOnClickListener(
98+
view -> {
99+
setupBackendSelectorDialog();
100+
});
101+
96102
modelImageButton.setOnClickListener(
97103
view -> {
98104
setupModelSelectorDialog();
99105
});
106+
requireViewById(R.id.modelLayout)
107+
.setOnClickListener(
108+
view -> {
109+
setupModelSelectorDialog();
110+
});
111+
100112
tokenizerImageButton.setOnClickListener(
101113
view -> {
102114
setupTokenizerSelectorDialog();
103115
});
116+
requireViewById(R.id.tokenizerLayout)
117+
.setOnClickListener(
118+
view -> {
119+
setupTokenizerSelectorDialog();
120+
});
121+
104122
dataPathImageButton.setOnClickListener(
105123
view -> {
106124
setupDataPathSelectorDialog();
107125
});
126+
requireViewById(R.id.dataPathLayout)
127+
.setOnClickListener(
128+
view -> {
129+
setupDataPathSelectorDialog();
130+
});
131+
108132
modelTypeImageButton.setOnClickListener(
109133
view -> {
110134
setupModelTypeSelectorDialog();
111135
});
136+
requireViewById(R.id.modelTypeLayout)
137+
.setOnClickListener(
138+
view -> {
139+
setupModelTypeSelectorDialog();
140+
});
112141
mModelFilePath = mSettingsFields.getModelFilePath();
113142
if (!mModelFilePath.isEmpty()) {
114143
mModelTextView.setText(getFilenameFromPath(mModelFilePath));
@@ -357,14 +386,13 @@ private void setupModelSelectorDialog() {
357386
}
358387

359388
private void setupDataPathSelectorDialog() {
360-
String[] dataPathFiles = listLocalFile("/data/local/tmp/llama/", new String[] {".ptd"});
389+
String[] dataPathFiles =
390+
listLocalFile("/data/local/tmp/llama/", new String[] {".ptd"});
361391
AlertDialog.Builder dataPathBuilder = new AlertDialog.Builder(this);
362392
dataPathBuilder.setTitle("Select data path");
363393

364394
String[] dataPathOptions = new String[dataPathFiles.length + 1];
365-
for (int i = 0; i < dataPathFiles.length; i++) {
366-
dataPathOptions[i] = dataPathFiles[i];
367-
}
395+
System.arraycopy(dataPathFiles, 0, dataPathOptions, 0, dataPathFiles.length);
368396
dataPathOptions[dataPathOptions.length - 1] = "(unused)";
369397

370398
dataPathBuilder.setSingleChoiceItems(
@@ -393,7 +421,7 @@ static String[] listLocalFile(String path, String[] suffix) {
393421
File directory = new File(path);
394422
if (directory.exists() && directory.isDirectory()) {
395423
File[] files = directory.listFiles((dir, name) -> (fileHasExtension(name, suffix)));
396-
String[] result = new String[files.length];
424+
String[] result = new String[files.length];
397425
for (int i = 0; i < files.length; i++) {
398426
if (files[i].isFile() && fileHasExtension(files[i].getName(), suffix)) {
399427
result[i] = files[i].getAbsolutePath();

llm/android/LlamaDemo/app/src/main/res/layout/activity_settings.xml

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,40 @@
77
android:layout_height="match_parent"
88
tools:context=".SettingsActivity">
99

10-
<LinearLayout
10+
<ScrollView
1111
android:layout_width="match_parent"
1212
android:layout_height="match_parent"
13-
android:background="#16293D"
14-
android:orientation="vertical"
1513
app:layout_constraintTop_toTopOf="parent"
1614
tools:layout_editor_absoluteX="1dp">
1715

18-
<TextView
19-
android:id="@+id/textView"
16+
<LinearLayout
2017
android:layout_width="match_parent"
2118
android:layout_height="wrap_content"
22-
android:fontFamily="sans-serif-medium"
23-
android:text="Settings"
24-
android:textAlignment="viewStart"
25-
android:textColor="#FFFFFF"
26-
android:textSize="22sp"
27-
android:translationX="5dp"
28-
android:translationY="5dp" />
19+
android:background="#16293D"
20+
android:orientation="vertical">
21+
22+
<TextView
23+
android:id="@+id/textView"
24+
android:layout_width="match_parent"
25+
android:layout_height="wrap_content"
26+
android:fontFamily="sans-serif-medium"
27+
android:text="Settings"
28+
android:textAlignment="viewStart"
29+
android:textColor="#FFFFFF"
30+
android:textSize="22sp"
31+
android:translationX="5dp"
32+
android:translationY="5dp" />
2933

3034
<LinearLayout
3135
android:id="@+id/backendLayout"
3236
android:layout_width="match_parent"
3337
android:layout_height="wrap_content"
3438
android:layout_marginTop="40dp"
35-
android:orientation="horizontal">
39+
android:background="?attr/selectableItemBackground"
40+
android:clickable="true"
41+
android:focusable="true"
42+
android:orientation="horizontal"
43+
android:padding="10dp">
3644

3745
<TextView
3846
android:id="@+id/backendLabel"
@@ -71,7 +79,11 @@
7179
android:layout_width="match_parent"
7280
android:layout_height="wrap_content"
7381
android:layout_marginTop="20dp"
74-
android:orientation="horizontal">
82+
android:background="?attr/selectableItemBackground"
83+
android:clickable="true"
84+
android:focusable="true"
85+
android:orientation="horizontal"
86+
android:padding="10dp">
7587

7688
<TextView
7789
android:id="@+id/modelLabel"
@@ -110,7 +122,11 @@
110122
android:layout_width="match_parent"
111123
android:layout_height="wrap_content"
112124
android:layout_marginTop="20dp"
113-
android:orientation="horizontal">
125+
android:background="?attr/selectableItemBackground"
126+
android:clickable="true"
127+
android:focusable="true"
128+
android:orientation="horizontal"
129+
android:padding="10dp">
114130

115131
<TextView
116132
android:id="@+id/tokenizerLabel"
@@ -148,7 +164,11 @@
148164
android:layout_width="match_parent"
149165
android:layout_height="wrap_content"
150166
android:layout_marginTop="20dp"
151-
android:orientation="horizontal">
167+
android:background="?attr/selectableItemBackground"
168+
android:clickable="true"
169+
android:focusable="true"
170+
android:orientation="horizontal"
171+
android:padding="10dp">
152172

153173
<TextView
154174
android:id="@+id/dataPathLabel"
@@ -186,7 +206,11 @@
186206
android:layout_width="match_parent"
187207
android:layout_height="wrap_content"
188208
android:layout_marginTop="20dp"
189-
android:orientation="horizontal">
209+
android:background="?attr/selectableItemBackground"
210+
android:clickable="true"
211+
android:focusable="true"
212+
android:orientation="horizontal"
213+
android:padding="10dp">
190214

191215
<TextView
192216
android:id="@+id/modelTypeLabel"
@@ -370,7 +394,6 @@
370394
android:textColor="@android:color/white"
371395
android:theme="@style/DefaultButton" />
372396

373-
</LinearLayout>
374-
375-
397+
</LinearLayout>
398+
</ScrollView>
376399
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
 (0)