Skip to content

Commit 17ced37

Browse files
authored
Refactor LlamaDemo settings to use SettingsFields as single source of truth (#137)
1 parent 5309d68 commit 17ced37

2 files changed

Lines changed: 70 additions & 103 deletions

File tree

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

Lines changed: 60 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@
3232

3333
public class SettingsActivity extends AppCompatActivity {
3434

35-
private String mModelFilePath = "";
36-
private String mTokenizerFilePath = "";
37-
private String mDataPath = "";
3835
private TextView mBackendTextView;
3936
private TextView mModelTextView;
4037
private TextView mTokenizerTextView;
@@ -43,19 +40,11 @@ public class SettingsActivity extends AppCompatActivity {
4340
private EditText mSystemPromptEditText;
4441
private EditText mUserPromptEditText;
4542
private Button mLoadModelButton;
46-
private double mSetTemperature;
47-
private String mSystemPrompt;
48-
private String mUserPrompt;
49-
private BackendType mBackendType;
50-
private ModelType mModelType;
43+
// mSettingsFields is the single source of truth for all settings
5144
public SettingsFields mSettingsFields;
5245

53-
// Store initial values to detect changes
54-
private String mInitialModelFilePath = "";
55-
private String mInitialTokenizerFilePath = "";
56-
private String mInitialDataPath = "";
57-
private BackendType mInitialBackendType;
58-
private ModelType mInitialModelType;
46+
// Store initial settings to detect changes
47+
private SettingsFields mInitialSettingsFields;
5948

6049
private DemoSharedPreferences mDemoSharedPreferences;
6150
public static double TEMPERATURE_MIN_VALUE = 0.0;
@@ -145,24 +134,27 @@ private void setupSettings() {
145134
view -> {
146135
setupModelTypeSelectorDialog();
147136
});
148-
if (mModelFilePath != null && !mModelFilePath.isEmpty()) {
149-
mModelTextView.setText(getFilenameFromPath(mModelFilePath));
137+
String modelFilePath = mSettingsFields.getModelFilePath();
138+
if (modelFilePath != null && !modelFilePath.isEmpty()) {
139+
mModelTextView.setText(getFilenameFromPath(modelFilePath));
150140
}
151-
if (mTokenizerFilePath != null && !mTokenizerFilePath.isEmpty()) {
152-
mTokenizerTextView.setText(getFilenameFromPath(mTokenizerFilePath));
141+
String tokenizerFilePath = mSettingsFields.getTokenizerFilePath();
142+
if (tokenizerFilePath != null && !tokenizerFilePath.isEmpty()) {
143+
mTokenizerTextView.setText(getFilenameFromPath(tokenizerFilePath));
153144
}
154-
if (mDataPath != null && !mDataPath.isEmpty()) {
155-
mDataPathTextView.setText(getFilenameFromPath(mDataPath));
145+
String dataPath = mSettingsFields.getDataPath();
146+
if (dataPath != null && !dataPath.isEmpty()) {
147+
mDataPathTextView.setText(getFilenameFromPath(dataPath));
156148
}
157-
mModelType = mSettingsFields.getModelType();
158-
ETLogging.getInstance().log("mModelType from settings " + mModelType);
159-
if (mModelType != null) {
160-
mModelTypeTextView.setText(mModelType.toString());
149+
ModelType modelType = mSettingsFields.getModelType();
150+
ETLogging.getInstance().log("mModelType from settings " + modelType);
151+
if (modelType != null) {
152+
mModelTypeTextView.setText(modelType.toString());
161153
}
162-
mBackendType = mSettingsFields.getBackendType();
163-
ETLogging.getInstance().log("mBackendType from settings " + mBackendType);
164-
if (mBackendType != null) {
165-
mBackendTextView.setText(mBackendType.toString());
154+
BackendType backendType = mSettingsFields.getBackendType();
155+
ETLogging.getInstance().log("mBackendType from settings " + backendType);
156+
if (backendType != null) {
157+
mBackendTextView.setText(backendType.toString());
166158
setBackendSettingMode();
167159
}
168160

@@ -226,9 +218,9 @@ private void setupParameterSettings() {
226218
}
227219

228220
private void setupTemperatureSettings() {
229-
mSetTemperature = mSettingsFields.getTemperature();
221+
double temperature = mSettingsFields.getTemperature();
230222
EditText temperatureEditText = requireViewById(R.id.temperatureEditText);
231-
temperatureEditText.setText(String.valueOf(mSetTemperature));
223+
temperatureEditText.setText(String.valueOf(temperature));
232224
temperatureEditText.addTextChangedListener(
233225
new TextWatcher() {
234226
@Override
@@ -239,11 +231,12 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {}
239231

240232
@Override
241233
public void afterTextChanged(Editable s) {
242-
mSetTemperature = Double.parseDouble(s.toString());
234+
double newTemperature = Double.parseDouble(s.toString());
235+
mSettingsFields.saveParameters(newTemperature);
243236
// This is needed because temperature is changed together with model loading
244237
// Once temperature is no longer in LlmModule constructor, we can remove this
245238
mSettingsFields.saveLoadModelAction(true);
246-
saveSettings();
239+
mDemoSharedPreferences.addSettings(mSettingsFields);
247240
}
248241
});
249242
}
@@ -254,8 +247,8 @@ private void setupPromptSettings() {
254247
}
255248

256249
private void setupSystemPromptSettings() {
257-
mSystemPrompt = mSettingsFields.getSystemPrompt();
258-
mSystemPromptEditText.setText(mSystemPrompt);
250+
String systemPrompt = mSettingsFields.getSystemPrompt();
251+
mSystemPromptEditText.setText(systemPrompt);
259252
mSystemPromptEditText.addTextChangedListener(
260253
new TextWatcher() {
261254
@Override
@@ -266,7 +259,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {}
266259

267260
@Override
268261
public void afterTextChanged(Editable s) {
269-
mSystemPrompt = s.toString();
262+
mSettingsFields.savePrompts(s.toString(), mSettingsFields.getUserPrompt());
270263
}
271264
});
272265

@@ -291,8 +284,8 @@ public void onClick(DialogInterface dialog, int whichButton) {
291284
}
292285

293286
private void setupUserPromptSettings() {
294-
mUserPrompt = mSettingsFields.getUserPrompt();
295-
mUserPromptEditText.setText(mUserPrompt);
287+
String userPrompt = mSettingsFields.getUserPrompt();
288+
mUserPromptEditText.setText(userPrompt);
296289
mUserPromptEditText.addTextChangedListener(
297290
new TextWatcher() {
298291
@Override
@@ -304,7 +297,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {}
304297
@Override
305298
public void afterTextChanged(Editable s) {
306299
if (isValidUserPrompt(s.toString())) {
307-
mUserPrompt = s.toString();
300+
mSettingsFields.savePrompts(mSettingsFields.getSystemPrompt(), s.toString());
308301
} else {
309302
showInvalidPromptDialog();
310303
}
@@ -323,7 +316,7 @@ public void afterTextChanged(Editable s) {
323316
new DialogInterface.OnClickListener() {
324317
public void onClick(DialogInterface dialog, int whichButton) {
325318
// Clear the messageAdapter and sharedPreference
326-
mUserPromptEditText.setText(PromptFormat.getUserPromptTemplate(mModelType));
319+
mUserPromptEditText.setText(PromptFormat.getUserPromptTemplate(mSettingsFields.getModelType()));
327320
}
328321
})
329322
.setNegativeButton(android.R.string.no, null)
@@ -346,7 +339,7 @@ private void showInvalidPromptDialog() {
346339
.setPositiveButton(
347340
android.R.string.yes,
348341
(dialog, whichButton) -> {
349-
mUserPromptEditText.setText(PromptFormat.getUserPromptTemplate(mModelType));
342+
mUserPromptEditText.setText(PromptFormat.getUserPromptTemplate(mSettingsFields.getModelType()));
350343
})
351344
.setNegativeButton(android.R.string.no, null)
352345
.show();
@@ -367,7 +360,7 @@ private void setupBackendSelectorDialog() {
367360
-1,
368361
(dialog, item) -> {
369362
mBackendTextView.setText(backendTypes[item]);
370-
mBackendType = BackendType.valueOf(backendTypes[item]);
363+
mSettingsFields.saveBackendType(BackendType.valueOf(backendTypes[item]));
371364
setBackendSettingMode();
372365
updateLoadModelButtonState();
373366
dialog.dismiss();
@@ -385,8 +378,8 @@ private void setupModelSelectorDialog() {
385378
pteFiles,
386379
-1,
387380
(dialog, item) -> {
388-
mModelFilePath = pteFiles[item];
389-
mModelTextView.setText(getFilenameFromPath(mModelFilePath));
381+
mSettingsFields.saveModelPath(pteFiles[item]);
382+
mModelTextView.setText(getFilenameFromPath(pteFiles[item]));
390383
updateLoadModelButtonState();
391384
dialog.dismiss();
392385
});
@@ -409,10 +402,10 @@ private void setupDataPathSelectorDialog() {
409402
-1,
410403
(dialog, item) -> {
411404
if (dataPathOptions[item] != "(unused)") {
412-
mDataPath = dataPathOptions[item];
413-
mDataPathTextView.setText(getFilenameFromPath(mDataPath));
405+
mSettingsFields.saveDataPath(dataPathOptions[item]);
406+
mDataPathTextView.setText(getFilenameFromPath(dataPathOptions[item]));
414407
} else {
415-
mDataPath = null;
408+
mSettingsFields.saveDataPath(null);
416409
mDataPathTextView.setText(getFilenameFromPath("no data path selected"));
417410
}
418411
updateLoadModelButtonState();
@@ -456,8 +449,9 @@ private void setupModelTypeSelectorDialog() {
456449
-1,
457450
(dialog, item) -> {
458451
mModelTypeTextView.setText(modelTypes[item]);
459-
mModelType = ModelType.valueOf(modelTypes[item]);
460-
mUserPromptEditText.setText(PromptFormat.getUserPromptTemplate(mModelType));
452+
ModelType selectedModelType = ModelType.valueOf(modelTypes[item]);
453+
mSettingsFields.saveModelType(selectedModelType);
454+
mUserPromptEditText.setText(PromptFormat.getUserPromptTemplate(selectedModelType));
461455
updateLoadModelButtonState();
462456
dialog.dismiss();
463457
});
@@ -474,8 +468,8 @@ private void setupTokenizerSelectorDialog() {
474468
tokenizerFiles,
475469
-1,
476470
(dialog, item) -> {
477-
mTokenizerFilePath = tokenizerFiles[item];
478-
mTokenizerTextView.setText(getFilenameFromPath(mTokenizerFilePath));
471+
mSettingsFields.saveTokenizerPath(tokenizerFiles[item]);
472+
mTokenizerTextView.setText(getFilenameFromPath(tokenizerFiles[item]));
479473
updateLoadModelButtonState();
480474
dialog.dismiss();
481475
});
@@ -495,38 +489,27 @@ private String getFilenameFromPath(String uriFilePath) {
495489
}
496490

497491
private void storeInitialSettings() {
498-
mInitialModelFilePath = mModelFilePath != null ? mModelFilePath : "";
499-
mInitialTokenizerFilePath = mTokenizerFilePath != null ? mTokenizerFilePath : "";
500-
mInitialDataPath = mDataPath != null ? mDataPath : "";
501-
mInitialBackendType = mBackendType;
502-
mInitialModelType = mModelType;
492+
mInitialSettingsFields = new SettingsFields(mSettingsFields);
503493
}
504494

505495
private boolean hasSettingsChanged() {
506-
String currentModelPath = mModelFilePath != null ? mModelFilePath : "";
507-
String currentTokenizerPath = mTokenizerFilePath != null ? mTokenizerFilePath : "";
508-
String currentDataPath = mDataPath != null ? mDataPath : "";
509-
510-
boolean modelChanged = !currentModelPath.equals(mInitialModelFilePath);
511-
boolean tokenizerChanged = !currentTokenizerPath.equals(mInitialTokenizerFilePath);
512-
boolean dataPathChanged = !currentDataPath.equals(mInitialDataPath);
513-
boolean backendChanged = !java.util.Objects.equals(mBackendType, mInitialBackendType);
514-
boolean modelTypeChanged = !java.util.Objects.equals(mModelType, mInitialModelType);
515-
516-
return modelChanged || tokenizerChanged || dataPathChanged || backendChanged || modelTypeChanged;
496+
return !mSettingsFields.equals(mInitialSettingsFields);
517497
}
518498

519499
private void updateLoadModelButtonState() {
520500
// Enable button if settings changed OR if valid pre-filled paths are available
521-
boolean hasValidPaths = mModelFilePath != null && !mModelFilePath.isEmpty()
522-
&& mTokenizerFilePath != null && !mTokenizerFilePath.isEmpty();
501+
String modelFilePath = mSettingsFields.getModelFilePath();
502+
String tokenizerFilePath = mSettingsFields.getTokenizerFilePath();
503+
boolean hasValidPaths = modelFilePath != null && !modelFilePath.isEmpty()
504+
&& tokenizerFilePath != null && !tokenizerFilePath.isEmpty();
523505
mLoadModelButton.setEnabled(hasSettingsChanged() || hasValidPaths);
524506
}
525507

526508
private void setBackendSettingMode() {
527-
if (mBackendType.equals(BackendType.XNNPACK) || mBackendType.equals(BackendType.QUALCOMM)) {
509+
BackendType backendType = mSettingsFields.getBackendType();
510+
if (backendType.equals(BackendType.XNNPACK) || backendType.equals(BackendType.QUALCOMM)) {
528511
setXNNPACKSettingMode();
529-
} else if (mBackendType.equals(BackendType.MEDIATEK)) {
512+
} else if (backendType.equals(BackendType.MEDIATEK)) {
530513
setMediaTekSettingMode();
531514
}
532515
}
@@ -546,11 +529,13 @@ private void setMediaTekSettingMode() {
546529
requireViewById(R.id.parametersView).setVisibility(View.GONE);
547530
requireViewById(R.id.temperatureLayout).setVisibility(View.GONE);
548531
// For MediaTek, only set default paths if they're empty - preserve existing selections
549-
if (mModelFilePath == null || mModelFilePath.isEmpty()) {
550-
mModelFilePath = "/in/mtk/llama/runner";
532+
String modelFilePath = mSettingsFields.getModelFilePath();
533+
if (modelFilePath == null || modelFilePath.isEmpty()) {
534+
mSettingsFields.saveModelPath("/in/mtk/llama/runner");
551535
}
552-
if (mTokenizerFilePath == null || mTokenizerFilePath.isEmpty()) {
553-
mTokenizerFilePath = "/in/mtk/llama/runner";
536+
String tokenizerFilePath = mSettingsFields.getTokenizerFilePath();
537+
if (tokenizerFilePath == null || tokenizerFilePath.isEmpty()) {
538+
mSettingsFields.saveTokenizerPath("/in/mtk/llama/runner");
554539
}
555540
}
556541

@@ -559,32 +544,11 @@ private void loadSettings() {
559544
String settingsFieldsJSON = mDemoSharedPreferences.getSettings();
560545
if (!settingsFieldsJSON.isEmpty()) {
561546
mSettingsFields = gson.fromJson(settingsFieldsJSON, SettingsFields.class);
562-
563-
// Update local variables with loaded values for session persistence
564-
mModelFilePath =
565-
mSettingsFields.getModelFilePath() != null ? mSettingsFields.getModelFilePath() : "";
566-
mTokenizerFilePath =
567-
mSettingsFields.getTokenizerFilePath() != null
568-
? mSettingsFields.getTokenizerFilePath()
569-
: "";
570-
mDataPath = mSettingsFields.getDataPath(); // Can be null
571-
mSetTemperature = mSettingsFields.getTemperature();
572-
mSystemPrompt =
573-
mSettingsFields.getSystemPrompt() != null ? mSettingsFields.getSystemPrompt() : "";
574-
mUserPrompt = mSettingsFields.getUserPrompt() != null ? mSettingsFields.getUserPrompt() : "";
575-
mModelType = mSettingsFields.getModelType();
576-
mBackendType = mSettingsFields.getBackendType();
577547
}
578548
}
579549

580550
private void saveSettings() {
581-
mSettingsFields.saveModelPath(mModelFilePath);
582-
mSettingsFields.saveTokenizerPath(mTokenizerFilePath);
583-
mSettingsFields.saveDataPath(mDataPath);
584-
mSettingsFields.saveParameters(mSetTemperature);
585-
mSettingsFields.savePrompts(mSystemPrompt, mUserPrompt);
586-
mSettingsFields.saveModelType(mModelType);
587-
mSettingsFields.saveBackendType(mBackendType);
551+
// All values are now stored directly in mSettingsFields, so just persist to SharedPreferences
588552
mDemoSharedPreferences.addSettings(mSettingsFields);
589553
}
590554

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
package com.example.executorchllamademo;
1010

11+
import java.util.Objects;
12+
1113
public class SettingsFields {
1214

1315
public String getModelFilePath() {
@@ -142,15 +144,16 @@ public void saveDataPath(String dataPath) {
142144

143145
public boolean equals(SettingsFields anotherSettingsFields) {
144146
if (this == anotherSettingsFields) return true;
145-
return modelFilePath.equals(anotherSettingsFields.modelFilePath)
146-
&& tokenizerFilePath.equals(anotherSettingsFields.tokenizerFilePath)
147-
&& java.util.Objects.equals(dataPath, anotherSettingsFields.dataPath)
147+
if (anotherSettingsFields == null) return false;
148+
return Objects.equals(modelFilePath, anotherSettingsFields.modelFilePath)
149+
&& Objects.equals(tokenizerFilePath, anotherSettingsFields.tokenizerFilePath)
150+
&& Objects.equals(dataPath, anotherSettingsFields.dataPath)
148151
&& temperature == anotherSettingsFields.temperature
149-
&& systemPrompt.equals(anotherSettingsFields.systemPrompt)
150-
&& userPrompt.equals(anotherSettingsFields.userPrompt)
152+
&& Objects.equals(systemPrompt, anotherSettingsFields.systemPrompt)
153+
&& Objects.equals(userPrompt, anotherSettingsFields.userPrompt)
151154
&& isClearChatHistory == anotherSettingsFields.isClearChatHistory
152155
&& isLoadModel == anotherSettingsFields.isLoadModel
153-
&& modelType == anotherSettingsFields.modelType
154-
&& backendType == anotherSettingsFields.backendType;
156+
&& Objects.equals(modelType, anotherSettingsFields.modelType)
157+
&& Objects.equals(backendType, anotherSettingsFields.backendType);
155158
}
156159
}

0 commit comments

Comments
 (0)