Skip to content

Commit aa11032

Browse files
authored
Chat history support (#197)
1 parent 237ae4a commit aa11032

3 files changed

Lines changed: 86 additions & 14 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ package com.example.executorchllamademo
1212
* Holds app-wide settings that are independent of the current module/model.
1313
*/
1414
data class AppSettings(
15-
val appearanceMode: AppearanceMode = AppearanceMode.SYSTEM
15+
val appearanceMode: AppearanceMode = AppearanceMode.SYSTEM,
16+
val saveChatHistory: Boolean = false
1617
)

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/screens/AppSettingsScreen.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import androidx.compose.material3.ButtonDefaults
3030
import androidx.compose.material3.Icon
3131
import androidx.compose.material3.IconButton
3232
import androidx.compose.material3.RadioButton
33+
import androidx.compose.material3.Switch
34+
import androidx.compose.material3.SwitchDefaults
3335
import androidx.compose.material3.Text
3436
import androidx.compose.material3.TextButton
3537
import androidx.compose.runtime.Composable
@@ -141,6 +143,42 @@ fun AppSettingsScreen(
141143

142144
Spacer(modifier = Modifier.height(8.dp))
143145

146+
// Save Chat History toggle
147+
Row(
148+
modifier = Modifier
149+
.fillMaxWidth()
150+
.background(appColors.settingsRowBackground, RoundedCornerShape(8.dp))
151+
.padding(horizontal = 16.dp, vertical = 12.dp),
152+
verticalAlignment = Alignment.CenterVertically
153+
) {
154+
Column(modifier = Modifier.weight(1f)) {
155+
Text(
156+
text = "Save Chat History",
157+
fontSize = 14.sp,
158+
color = appColors.settingsText
159+
)
160+
Text(
161+
text = "Persist conversations between sessions",
162+
fontSize = 12.sp,
163+
color = appColors.settingsText.copy(alpha = 0.6f)
164+
)
165+
}
166+
Switch(
167+
checked = appSettings.saveChatHistory,
168+
onCheckedChange = { enabled ->
169+
appSettings = appSettings.copy(saveChatHistory = enabled)
170+
val prefs = DemoSharedPreferences(context)
171+
prefs.saveAppSettings(appSettings)
172+
},
173+
colors = SwitchDefaults.colors(
174+
checkedThumbColor = Color.White,
175+
checkedTrackColor = BtnEnabled
176+
)
177+
)
178+
}
179+
180+
Spacer(modifier = Modifier.height(12.dp))
181+
144182
// Clear Chat button
145183
Button(
146184
onClick = { showClearChatDialog = true },
@@ -188,6 +226,8 @@ fun AppSettingsScreen(
188226
val prefs = DemoSharedPreferences(context)
189227
moduleSettings = moduleSettings.copy(isClearChatHistory = true)
190228
prefs.saveModuleSettings(moduleSettings)
229+
// Also clear the saved messages immediately
230+
prefs.removeExistingMessages()
191231
showClearChatDialog = false
192232
}
193233
) {

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,29 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L
8282
private val contentResolver = application.contentResolver
8383

8484
init {
85-
loadSavedMessages()
85+
// Check for clear chat history flag BEFORE loading saved messages
86+
val moduleSettings = demoSharedPreferences.getModuleSettings()
87+
if (moduleSettings.isClearChatHistory) {
88+
// Clear the flag and don't load messages
89+
// Keep isLoadModel flag so model still loads in checkAndLoadSettings()
90+
demoSharedPreferences.removeExistingMessages()
91+
demoSharedPreferences.saveModuleSettings(moduleSettings.copy(isClearChatHistory = false))
92+
// Don't update currentSettingsFields here - let checkAndLoadSettings() handle it
93+
// so it detects the change and loads the model if needed
94+
} else {
95+
loadSavedMessages()
96+
}
8697
}
8798

8899
private fun loadSavedMessages() {
100+
val appSettings = demoSharedPreferences.getAppSettings()
101+
// Only load saved messages if saveChatHistory is enabled
102+
if (!appSettings.saveChatHistory) {
103+
// Clear any existing saved messages since saving is disabled
104+
demoSharedPreferences.removeExistingMessages()
105+
return
106+
}
107+
89108
val existingMsgJSON = demoSharedPreferences.getSavedMessages()
90109
if (existingMsgJSON.isNotEmpty()) {
91110
val gson = Gson()
@@ -99,7 +118,14 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L
99118
}
100119

101120
fun saveMessages() {
102-
demoSharedPreferences.addMessages(_messages.toList())
121+
val appSettings = demoSharedPreferences.getAppSettings()
122+
// Only save messages if saveChatHistory is enabled
123+
if (appSettings.saveChatHistory) {
124+
demoSharedPreferences.addMessages(_messages.toList())
125+
} else {
126+
// Make sure no messages are persisted
127+
demoSharedPreferences.removeExistingMessages()
128+
}
103129
}
104130

105131
private val systemPromptMessage = "To get started, select your desired model and tokenizer from the top right corner"
@@ -109,27 +135,27 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L
109135
val isUpdated = currentSettingsFields != updatedSettingsFields
110136
val isLoadModel = updatedSettingsFields.isLoadModel
111137
if (isUpdated) {
112-
checkForClearChatHistory(updatedSettingsFields)
138+
val settingsAfterClear = checkForClearChatHistory(updatedSettingsFields)
113139

114140
if (isLoadModel) {
115141
// Update local copy BEFORE checking media capabilities
116-
val settingsWithLoadFlagCleared = updatedSettingsFields.copy(isLoadModel = false)
142+
val settingsWithLoadFlagCleared = settingsAfterClear.copy(isLoadModel = false)
117143
currentSettingsFields = settingsWithLoadFlagCleared
118144
demoSharedPreferences.saveModuleSettings(settingsWithLoadFlagCleared)
119145

120146
// Update media capabilities after settings are updated
121-
setBackendMode(updatedSettingsFields.backendType)
147+
setBackendMode(settingsAfterClear.backendType)
122148

123149
loadLocalModelAndParameters(
124-
updatedSettingsFields.modelFilePath,
125-
updatedSettingsFields.tokenizerFilePath,
126-
updatedSettingsFields.dataPath,
127-
updatedSettingsFields.temperature.toFloat()
150+
settingsAfterClear.modelFilePath,
151+
settingsAfterClear.tokenizerFilePath,
152+
settingsAfterClear.dataPath,
153+
settingsAfterClear.temperature.toFloat()
128154
)
129155
} else {
130-
currentSettingsFields = updatedSettingsFields.copy()
156+
currentSettingsFields = settingsAfterClear.copy()
131157
// Update media capabilities after settings are updated
132-
setBackendMode(updatedSettingsFields.backendType)
158+
setBackendMode(settingsAfterClear.backendType)
133159
if (module == null) {
134160
addSystemMessage(systemPromptMessage)
135161
}
@@ -175,13 +201,18 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L
175201
}
176202
}
177203

178-
private fun checkForClearChatHistory(updatedSettingsFields: ModuleSettings) {
204+
private fun checkForClearChatHistory(updatedSettingsFields: ModuleSettings): ModuleSettings {
179205
if (updatedSettingsFields.isClearChatHistory) {
180206
_messages.clear()
181207
demoSharedPreferences.removeExistingMessages()
182-
demoSharedPreferences.saveModuleSettings(updatedSettingsFields.copy(isClearChatHistory = false))
208+
val clearedSettings = updatedSettingsFields.copy(isClearChatHistory = false)
209+
demoSharedPreferences.saveModuleSettings(clearedSettings)
183210
module?.resetContext()
211+
shouldAddSystemPrompt = true
212+
promptID = 0
213+
return clearedSettings
184214
}
215+
return updatedSettingsFields
185216
}
186217

187218
private fun loadLocalModelAndParameters(

0 commit comments

Comments
 (0)