支持多个大模型配置,可添加、选择、切换模型
This commit is contained in:
@@ -40,17 +40,20 @@ class MainActivity : AppCompatActivity() {
|
||||
private lateinit var promptSelector: Spinner
|
||||
private lateinit var promptNameText: TextView
|
||||
private lateinit var promptContentText: TextView
|
||||
private lateinit var headerModelSelector: Spinner
|
||||
|
||||
// Data classes matching SecondActivity
|
||||
data class HeaderConfig(val key: String, val value: String)
|
||||
data class PromptConfig(val id: String, val title: String, val content: String, val expanded: Boolean = false)
|
||||
data class ButtonConfig(val id: String, val label: String, val action: String, val apiUrl: String? = null, val apiMethod: String? = null, val apiBodyTemplate: String? = null, val expanded: Boolean = false)
|
||||
data class LLMConfig(val baseUrl: String, val apiKey: String, val model: String)
|
||||
data class LLMConfig(val name: String, val baseUrl: String, val apiKey: String, val model: String)
|
||||
data class SettingsData(
|
||||
val llmConfig: LLMConfig?,
|
||||
val llmConfigs: List<LLMConfig>?,
|
||||
val selectedLlmIndex: Int?,
|
||||
val headerConfigs: List<HeaderConfig>?,
|
||||
val promptConfigs: List<PromptConfig>?,
|
||||
val buttonConfigs: List<ButtonConfig>?
|
||||
val buttonConfigs: List<ButtonConfig>?,
|
||||
val llmConfig: LLMConfig? = null
|
||||
)
|
||||
|
||||
@SuppressLint("MissingInflatedId", "CutPasteId", "SetTextI18n")
|
||||
@@ -71,12 +74,11 @@ class MainActivity : AppCompatActivity() {
|
||||
outputTextView = findViewById<EditText>(R.id.outputTextView)
|
||||
val btnCopyResult = findViewById<Button>(R.id.btnCopyResult)
|
||||
val headerTitle = findViewById<TextView>(R.id.headerTitle)
|
||||
val headerModelName = findViewById<TextView>(R.id.headerModelName)
|
||||
headerModelSelector = findViewById<Spinner>(R.id.headerModelSelector)
|
||||
Log.d("MainActivity", "onCreate: Views initialized")
|
||||
|
||||
headerTitle.text = "AI优化"
|
||||
val savedModel = loadModelFromConfig()
|
||||
headerModelName.text = if (savedModel.isNotBlank()) savedModel else "GPT-4o"
|
||||
loadModelsFromConfig()
|
||||
|
||||
// Initialize quick action buttons
|
||||
initQuickButtons()
|
||||
@@ -129,21 +131,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val sharedPrefs = getSharedPreferences("APIConfigs", Context.MODE_PRIVATE)
|
||||
val json = sharedPrefs.getString("configs", null)
|
||||
|
||||
var baseUrl = "https://open.bigmodel.cn/api/paas/v4"
|
||||
var apiKey = ""
|
||||
var model = "glm-4.7-flash"
|
||||
|
||||
if (json != null) {
|
||||
val settings = Gson().fromJson(json, SettingsData::class.java)
|
||||
settings.llmConfig?.let {
|
||||
if (it.baseUrl.isNotBlank()) baseUrl = it.baseUrl
|
||||
if (it.apiKey.isNotBlank()) apiKey = it.apiKey
|
||||
if (it.model.isNotBlank()) model = it.model
|
||||
}
|
||||
}
|
||||
val llmConfig = getSelectedModelConfig()
|
||||
val baseUrl = llmConfig.baseUrl.ifEmpty { "https://open.bigmodel.cn/api/paas/v4" }
|
||||
val apiKey = llmConfig.apiKey
|
||||
val model = llmConfig.model.ifEmpty { "glm-4.7-flash" }
|
||||
|
||||
val messagesJson = JSONArray().apply {
|
||||
put(JSONObject().apply {
|
||||
@@ -261,22 +252,110 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadModelFromConfig(): String {
|
||||
return try {
|
||||
private fun loadModelsFromConfig() {
|
||||
try {
|
||||
val sharedPrefs = getSharedPreferences("APIConfigs", Context.MODE_PRIVATE)
|
||||
val json = sharedPrefs.getString("configs", null)
|
||||
|
||||
var models = mutableListOf<LLMConfig>()
|
||||
var selectedIndex = 0
|
||||
|
||||
if (json != null) {
|
||||
val settings = Gson().fromJson(json, SettingsData::class.java)
|
||||
settings.llmConfig?.model?.takeIf { it.isNotBlank() } ?: ""
|
||||
} else {
|
||||
""
|
||||
try {
|
||||
val settings = Gson().fromJson(json, SettingsData::class.java)
|
||||
models = settings.llmConfigs?.toMutableList() ?: mutableListOf()
|
||||
selectedIndex = settings.selectedLlmIndex ?: 0
|
||||
|
||||
if (models.isEmpty()) {
|
||||
settings.llmConfig?.let { legacy ->
|
||||
models.add(LLMConfig(
|
||||
name = "默认配置",
|
||||
baseUrl = legacy.baseUrl,
|
||||
apiKey = legacy.apiKey,
|
||||
model = legacy.model
|
||||
))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainActivity", "Error parsing settings, using defaults", e)
|
||||
}
|
||||
}
|
||||
|
||||
if (models.isEmpty()) {
|
||||
models.add(LLMConfig(
|
||||
name = "默认配置",
|
||||
baseUrl = "https://open.bigmodel.cn/api/paas/v4",
|
||||
apiKey = "",
|
||||
model = "glm-4.7-flash"
|
||||
))
|
||||
}
|
||||
|
||||
if (selectedIndex >= models.size) {
|
||||
selectedIndex = 0
|
||||
}
|
||||
|
||||
val names = models.map { it.name.ifEmpty { "未命名" } }
|
||||
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, names)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
headerModelSelector.adapter = adapter
|
||||
headerModelSelector.setSelection(selectedIndex)
|
||||
|
||||
headerModelSelector.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: android.widget.AdapterView<*>, view: android.view.View?, position: Int, id: Long) {
|
||||
Log.d("MainActivity", "Model selected: ${models[position].name}")
|
||||
}
|
||||
override fun onNothingSelected(parent: android.widget.AdapterView<*>) {}
|
||||
}
|
||||
|
||||
Log.d("MainActivity", "Loaded ${models.size} model configs")
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainActivity", "Error loading model from config", e)
|
||||
""
|
||||
Log.e("MainActivity", "Error loading models from config", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectedModelConfig(): LLMConfig {
|
||||
val sharedPrefs = getSharedPreferences("APIConfigs", Context.MODE_PRIVATE)
|
||||
val json = sharedPrefs.getString("configs", null)
|
||||
|
||||
var models = mutableListOf<LLMConfig>()
|
||||
var selectedIndex = headerModelSelector.selectedItemPosition
|
||||
|
||||
if (json != null) {
|
||||
try {
|
||||
val settings = Gson().fromJson(json, SettingsData::class.java)
|
||||
models = settings.llmConfigs?.toMutableList() ?: mutableListOf()
|
||||
|
||||
if (models.isEmpty()) {
|
||||
settings.llmConfig?.let { legacy ->
|
||||
models.add(LLMConfig(
|
||||
name = "默认配置",
|
||||
baseUrl = legacy.baseUrl,
|
||||
apiKey = legacy.apiKey,
|
||||
model = legacy.model
|
||||
))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainActivity", "Error parsing settings", e)
|
||||
}
|
||||
}
|
||||
|
||||
if (models.isEmpty()) {
|
||||
return LLMConfig(
|
||||
name = "默认配置",
|
||||
baseUrl = "https://open.bigmodel.cn/api/paas/v4",
|
||||
apiKey = "",
|
||||
model = "glm-4.7-flash"
|
||||
)
|
||||
}
|
||||
|
||||
if (selectedIndex >= models.size) {
|
||||
selectedIndex = 0
|
||||
}
|
||||
|
||||
return models[selectedIndex]
|
||||
}
|
||||
|
||||
private fun loadPromptsFromConfig() {
|
||||
Log.d("MainActivity", "loadPromptsFromConfig: Starting")
|
||||
try {
|
||||
|
||||
@@ -46,10 +46,14 @@ data class ButtonConfig(val id: String, val label: String, val action: String, v
|
||||
class SecondActivity : AppCompatActivity() {
|
||||
|
||||
// View references
|
||||
private lateinit var spModelSelector: Spinner
|
||||
private lateinit var llModelList: LinearLayout
|
||||
private lateinit var btnAddModel: Button
|
||||
private lateinit var etBaseUrl: EditText
|
||||
private lateinit var etApiKey: EditText
|
||||
private lateinit var btnToggleApiKey: ImageButton
|
||||
private lateinit var etModel: EditText
|
||||
private lateinit var etModelName: EditText
|
||||
private lateinit var btnTestConnection: Button
|
||||
private lateinit var tvTestStatus: TextView
|
||||
private lateinit var llHeadersList: LinearLayout
|
||||
@@ -78,6 +82,8 @@ class SecondActivity : AppCompatActivity() {
|
||||
private lateinit var btnToggleNoteApiKey: ImageButton
|
||||
|
||||
// Data storage
|
||||
private var llmConfigs = mutableListOf<LLMConfig>()
|
||||
private var selectedLlmIndex = 0
|
||||
private var headerConfigs = mutableListOf<HeaderConfig>()
|
||||
private var promptConfigs = mutableListOf<PromptConfig>()
|
||||
private var buttonConfigs = mutableListOf<ButtonConfig>()
|
||||
@@ -119,9 +125,7 @@ class SecondActivity : AppCompatActivity() {
|
||||
// Home button functionality
|
||||
findViewById<Button>(R.id.btnHome).setOnClickListener {
|
||||
Log.d("SecondActivity", "Home button clicked")
|
||||
// Create intent to go back to MainActivity
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
// Clear the activity stack to start fresh
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
startActivity(intent)
|
||||
finish()
|
||||
@@ -153,6 +157,9 @@ class SecondActivity : AppCompatActivity() {
|
||||
etApiKey = findViewById(R.id.etApiKey)
|
||||
btnToggleApiKey = findViewById(R.id.btnToggleApiKey)
|
||||
etModel = findViewById(R.id.etModel)
|
||||
etModelName = findViewById(R.id.etModelName)
|
||||
spModelSelector = findViewById(R.id.spModelSelector)
|
||||
btnAddModel = findViewById(R.id.btnAddModel)
|
||||
btnTestConnection = findViewById(R.id.btnTestConnection)
|
||||
tvTestStatus = findViewById(R.id.tvTestStatus)
|
||||
|
||||
@@ -189,14 +196,12 @@ class SecondActivity : AppCompatActivity() {
|
||||
Log.d("SecondActivity", "API key toggle clicked")
|
||||
val isPassword = etApiKey.transformationMethod is PasswordTransformationMethod
|
||||
etApiKey.transformationMethod = if (isPassword) null else PasswordTransformationMethod()
|
||||
// Move cursor to end
|
||||
etApiKey.setSelection(etApiKey.text.length)
|
||||
|
||||
// Update icon based on state
|
||||
if (isPassword) {
|
||||
btnToggleApiKey.setImageResource(android.R.drawable.ic_menu_view) // Show eye
|
||||
btnToggleApiKey.setImageResource(android.R.drawable.ic_menu_view)
|
||||
} else {
|
||||
btnToggleApiKey.setImageResource(android.R.drawable.ic_lock_idle_lock) // Show lock
|
||||
btnToggleApiKey.setImageResource(android.R.drawable.ic_lock_idle_lock)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,10 +211,10 @@ class SecondActivity : AppCompatActivity() {
|
||||
val isExpanded = layoutHeaderContent.visibility == View.VISIBLE
|
||||
if (isExpanded) {
|
||||
layoutHeaderContent.visibility = View.GONE
|
||||
ivHeaderArrow.rotation = 0f // Point right
|
||||
ivHeaderArrow.rotation = 0f
|
||||
} else {
|
||||
layoutHeaderContent.visibility = View.VISIBLE
|
||||
ivHeaderArrow.rotation = 90f // Point down
|
||||
ivHeaderArrow.rotation = 90f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,10 +224,10 @@ class SecondActivity : AppCompatActivity() {
|
||||
val isExpanded = layoutPromptContent.visibility == View.VISIBLE
|
||||
if (isExpanded) {
|
||||
layoutPromptContent.visibility = View.GONE
|
||||
ivPromptArrow.rotation = 0f // Point right
|
||||
ivPromptArrow.rotation = 0f
|
||||
} else {
|
||||
layoutPromptContent.visibility = View.VISIBLE
|
||||
ivPromptArrow.rotation = 90f // Point down
|
||||
ivPromptArrow.rotation = 90f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,14 +258,12 @@ class SecondActivity : AppCompatActivity() {
|
||||
|
||||
private fun loadConfigurations() {
|
||||
Log.d("SecondActivity", "loadConfigurations: Starting")
|
||||
// Load shared preferences
|
||||
val sharedPrefs = getSharedPreferences("APIConfigs", Context.MODE_PRIVATE)
|
||||
val json = sharedPrefs.getString("configs", null)
|
||||
Log.d("SecondActivity", "loadConfigurations: JSON loaded: ${json?.substring(0, minOf(json.length, 100))}")
|
||||
|
||||
if (json != null) {
|
||||
try {
|
||||
// Try to load as new format first
|
||||
Log.d("SecondActivity", "loadConfigurations: Trying to parse as SettingsData")
|
||||
val settings = Gson().fromJson(json, SettingsData::class.java)
|
||||
Log.d("SecondActivity", "loadConfigurations: SettingsData parsed successfully")
|
||||
@@ -268,12 +271,27 @@ class SecondActivity : AppCompatActivity() {
|
||||
promptConfigs = settings.promptConfigs?.toMutableList() ?: mutableListOf()
|
||||
buttonConfigs = settings.buttonConfigs?.toMutableList() ?: mutableListOf()
|
||||
|
||||
// Load LLM config
|
||||
etBaseUrl.setText(settings.llmConfig?.baseUrl ?: "https://api.openai.com/v1")
|
||||
etApiKey.setText(settings.llmConfig?.apiKey ?: "")
|
||||
etModel.setText(settings.llmConfig?.model ?: "gpt-4o")
|
||||
llmConfigs = settings.llmConfigs?.toMutableList() ?: mutableListOf()
|
||||
selectedLlmIndex = settings.selectedLlmIndex ?: 0
|
||||
|
||||
if (llmConfigs.isEmpty()) {
|
||||
val legacyBaseUrl = settings.llmConfig?.baseUrl ?: "https://api.openai.com/v1"
|
||||
val legacyApiKey = settings.llmConfig?.apiKey ?: ""
|
||||
val legacyModel = settings.llmConfig?.model ?: "gpt-4o"
|
||||
llmConfigs.add(LLMConfig(
|
||||
name = "默认配置",
|
||||
baseUrl = legacyBaseUrl,
|
||||
apiKey = legacyApiKey,
|
||||
model = legacyModel
|
||||
))
|
||||
}
|
||||
|
||||
if (selectedLlmIndex >= llmConfigs.size) {
|
||||
selectedLlmIndex = 0
|
||||
}
|
||||
|
||||
loadSelectedModelToFields()
|
||||
|
||||
// Load Note API config
|
||||
settings.noteApiConfig?.let { noteConfig ->
|
||||
val apiTypes = listOf("Flomo", "Notion", "Joplin", "Custom")
|
||||
val typeIndex = apiTypes.indexOf(noteConfig.apiType)
|
||||
@@ -284,12 +302,10 @@ class SecondActivity : AppCompatActivity() {
|
||||
etNoteApiKey.setText(noteConfig.apiKey)
|
||||
}
|
||||
|
||||
// Update API key visibility based on whether it has text
|
||||
updateApiKeyVisibility()
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("SecondActivity", "loadConfigurations: Error parsing SettingsData", e)
|
||||
// If new format fails, try to load old format for migration
|
||||
try {
|
||||
Log.d("SecondActivity", "loadConfigurations: Trying to parse as List<APIConfig>")
|
||||
val type = object : TypeToken<List<APIConfig>>() {}.type
|
||||
@@ -303,14 +319,12 @@ class SecondActivity : AppCompatActivity() {
|
||||
}
|
||||
} catch (e2: Exception) {
|
||||
Log.e("SecondActivity", "loadConfigurations: Error parsing List<APIConfig>", e2)
|
||||
// If both fail, use defaults
|
||||
etBaseUrl.setText("https://api.openai.com/v1")
|
||||
etModel.setText("gpt-4o")
|
||||
updateApiKeyVisibility()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No saved config, use defaults
|
||||
Log.d("SecondActivity", "loadConfigurations: No saved config, using defaults")
|
||||
etBaseUrl.setText("https://api.openai.com/v1")
|
||||
etModel.setText("gpt-4o")
|
||||
@@ -319,18 +333,59 @@ class SecondActivity : AppCompatActivity() {
|
||||
Log.d("SecondActivity", "loadConfigurations: Completed")
|
||||
}
|
||||
|
||||
private fun loadSelectedModelToFields() {
|
||||
if (llmConfigs.isNotEmpty() && selectedLlmIndex < llmConfigs.size) {
|
||||
val config = llmConfigs[selectedLlmIndex]
|
||||
etBaseUrl.setText(config.baseUrl)
|
||||
etApiKey.setText(config.apiKey)
|
||||
etModel.setText(config.model)
|
||||
etModelName.setText(config.name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateApiKeyVisibility() {
|
||||
val isEmpty = etApiKey.text.toString().isEmpty()
|
||||
etApiKey.transformationMethod = if (isEmpty) null else PasswordTransformationMethod()
|
||||
// Keep cursor at end
|
||||
etApiKey.setSelection(etApiKey.text.length)
|
||||
}
|
||||
|
||||
private fun refreshModelSelector() {
|
||||
val names = llmConfigs.map { it.name.ifEmpty { "未命名" } }.toMutableList()
|
||||
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, names)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
spModelSelector.adapter = adapter
|
||||
}
|
||||
|
||||
private fun setupUI() {
|
||||
refreshModelSelector()
|
||||
|
||||
spModelSelector.setOnItemSelectedListener(object : android.widget.AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: android.widget.AdapterView<*>, view: android.view.View?, position: Int, id: Long) {
|
||||
selectedLlmIndex = position
|
||||
loadSelectedModelToFields()
|
||||
}
|
||||
override fun onNothingSelected(parent: android.widget.AdapterView<*>) {}
|
||||
})
|
||||
|
||||
btnAddModel.setOnClickListener {
|
||||
val newName = "新配置 ${llmConfigs.size + 1}"
|
||||
val newConfig = LLMConfig(
|
||||
name = newName,
|
||||
baseUrl = etBaseUrl.text.toString().ifEmpty { "https://api.openai.com/v1" },
|
||||
apiKey = "",
|
||||
model = "gpt-4o"
|
||||
)
|
||||
llmConfigs.add(newConfig)
|
||||
selectedLlmIndex = llmConfigs.size - 1
|
||||
loadSelectedModelToFields()
|
||||
refreshModelSelector()
|
||||
spModelSelector.setSelection(selectedLlmIndex)
|
||||
}
|
||||
|
||||
// Setup headers
|
||||
llHeadersList.removeAllViews()
|
||||
if (headerConfigs.isEmpty()) {
|
||||
addHeaderEntry() // Add one empty entry by default
|
||||
addHeaderEntry()
|
||||
} else {
|
||||
for (header in headerConfigs) {
|
||||
addHeaderEntry(header.key, header.value)
|
||||
@@ -340,7 +395,7 @@ class SecondActivity : AppCompatActivity() {
|
||||
// Setup prompts
|
||||
llPromptList.removeAllViews()
|
||||
if (promptConfigs.isEmpty()) {
|
||||
addPromptEntry() // Add one empty entry by default
|
||||
addPromptEntry()
|
||||
} else {
|
||||
for (prompt in promptConfigs) {
|
||||
addPromptEntry(prompt.title, prompt.content)
|
||||
@@ -358,10 +413,8 @@ class SecondActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setupTheme() {
|
||||
// Get saved theme mode
|
||||
val themeMode = ThemeManager.getThemeMode(this)
|
||||
|
||||
// Set the correct radio button
|
||||
when (themeMode) {
|
||||
ThemeManager.THEME_FOLLOW_SYSTEM -> rbThemeFollowSystem.isChecked = true
|
||||
ThemeManager.THEME_LIGHT -> rbThemeLight.isChecked = true
|
||||
@@ -369,7 +422,6 @@ class SecondActivity : AppCompatActivity() {
|
||||
else -> rbThemeFollowSystem.isChecked = true
|
||||
}
|
||||
|
||||
// Set up radio group listener
|
||||
rgThemeMode.setOnCheckedChangeListener { _, checkedId ->
|
||||
val newMode = when (checkedId) {
|
||||
R.id.rbThemeFollowSystem -> ThemeManager.THEME_FOLLOW_SYSTEM
|
||||
@@ -378,11 +430,8 @@ class SecondActivity : AppCompatActivity() {
|
||||
else -> ThemeManager.THEME_FOLLOW_SYSTEM
|
||||
}
|
||||
|
||||
// Save and apply the new theme
|
||||
ThemeManager.setThemeMode(this, newMode)
|
||||
Log.d("SecondActivity", "Theme mode changed to: ${ThemeManager.getThemeModeName(newMode)}")
|
||||
|
||||
// Recreate activity to apply theme changes
|
||||
recreate()
|
||||
}
|
||||
}
|
||||
@@ -418,10 +467,15 @@ class SecondActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
val client = OkHttpClient()
|
||||
val request = Request.Builder()
|
||||
val requestBuilder = Request.Builder()
|
||||
.url("$baseUrl/chat/completions")
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.addHeader("Authorization", "Bearer $apiKey")
|
||||
|
||||
if (apiKey.isNotBlank()) {
|
||||
requestBuilder.addHeader("Authorization", "Bearer $apiKey")
|
||||
}
|
||||
|
||||
val request = requestBuilder
|
||||
.post(requestBody.toString().toRequestBody("application/json".toMediaType()))
|
||||
.build()
|
||||
|
||||
@@ -496,7 +550,24 @@ class SecondActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun saveConfigurations() {
|
||||
// Update header configs from UI
|
||||
if (llmConfigs.isNotEmpty() && selectedLlmIndex < llmConfigs.size) {
|
||||
val currentConfig = llmConfigs[selectedLlmIndex]
|
||||
llmConfigs[selectedLlmIndex] = currentConfig.copy(
|
||||
name = etModelName.text.toString().ifEmpty { "未命名" },
|
||||
baseUrl = etBaseUrl.text.toString(),
|
||||
apiKey = etApiKey.text.toString(),
|
||||
model = etModel.text.toString()
|
||||
)
|
||||
} else {
|
||||
llmConfigs.add(LLMConfig(
|
||||
name = etModelName.text.toString().ifEmpty { "默认配置" },
|
||||
baseUrl = etBaseUrl.text.toString(),
|
||||
apiKey = etApiKey.text.toString(),
|
||||
model = etModel.text.toString()
|
||||
))
|
||||
selectedLlmIndex = 0
|
||||
}
|
||||
|
||||
headerConfigs.clear()
|
||||
for (i in 0 until llHeadersList.childCount) {
|
||||
val view = llHeadersList.getChildAt(i)
|
||||
@@ -507,7 +578,6 @@ class SecondActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// Update prompt configs from UI
|
||||
promptConfigs.clear()
|
||||
for (i in 0 until llPromptList.childCount) {
|
||||
val view = llPromptList.getChildAt(i)
|
||||
@@ -518,27 +588,17 @@ class SecondActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Buttons are removed from this UI as per new design.
|
||||
// We keep the list empty for data compatibility.
|
||||
buttonConfigs.clear()
|
||||
|
||||
// Save LLM config
|
||||
val llmConfig = LLMConfig(
|
||||
baseUrl = etBaseUrl.text.toString(),
|
||||
apiKey = etApiKey.text.toString(),
|
||||
model = etModel.text.toString()
|
||||
)
|
||||
|
||||
// Save Note API config
|
||||
val noteApiConfig = NoteApiConfig(
|
||||
apiType = spNoteApiType.selectedItem.toString(),
|
||||
apiUrl = etNoteApiUrl.text.toString(),
|
||||
apiKey = etNoteApiKey.text.toString()
|
||||
)
|
||||
|
||||
// Save everything
|
||||
val settingsData = SettingsData(
|
||||
llmConfig = llmConfig,
|
||||
llmConfigs = llmConfigs,
|
||||
selectedLlmIndex = selectedLlmIndex,
|
||||
headerConfigs = headerConfigs,
|
||||
promptConfigs = promptConfigs,
|
||||
buttonConfigs = buttonConfigs,
|
||||
@@ -549,7 +609,6 @@ class SecondActivity : AppCompatActivity() {
|
||||
val sharedPrefs = getSharedPreferences("APIConfigs", Context.MODE_PRIVATE)
|
||||
sharedPrefs.edit().putString("configs", json).apply()
|
||||
|
||||
// Also update the legacy APIConfig for backward compatibility
|
||||
apiConfig = APIConfig(
|
||||
System.currentTimeMillis(),
|
||||
"llm-config",
|
||||
@@ -572,6 +631,7 @@ class SecondActivity : AppCompatActivity() {
|
||||
|
||||
// New data classes for settings structure
|
||||
data class LLMConfig(
|
||||
val name: String,
|
||||
val baseUrl: String,
|
||||
val apiKey: String,
|
||||
val model: String
|
||||
@@ -584,10 +644,12 @@ class SecondActivity : AppCompatActivity() {
|
||||
)
|
||||
|
||||
data class SettingsData(
|
||||
val llmConfig: LLMConfig?,
|
||||
val llmConfigs: List<LLMConfig>?,
|
||||
val selectedLlmIndex: Int?,
|
||||
val headerConfigs: List<HeaderConfig>?,
|
||||
val promptConfigs: List<PromptConfig>?,
|
||||
val buttonConfigs: List<ButtonConfig>?,
|
||||
val noteApiConfig: NoteApiConfig?
|
||||
val noteApiConfig: NoteApiConfig?,
|
||||
val llmConfig: LLMConfig? = null
|
||||
)
|
||||
}
|
||||
@@ -32,27 +32,12 @@
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"/>
|
||||
|
||||
<LinearLayout
|
||||
<Spinner
|
||||
android:id="@+id/headerModelSelector"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="2dp">
|
||||
|
||||
<View
|
||||
android:layout_width="6dp"
|
||||
android:layout_height="6dp"
|
||||
android:background="@drawable/indicator_dot"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headerModelName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="GPT-4o"
|
||||
android:textSize="11sp"
|
||||
android:textColor="@color/primary"
|
||||
android:layout_marginStart="5dp"/>
|
||||
</LinearLayout>
|
||||
android:layout_marginTop="2dp"
|
||||
android:spinnerMode="dropdown"/>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
|
||||
@@ -126,6 +126,64 @@
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<!-- Base URL -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="配置名称"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etModelName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/edittext_border"
|
||||
android:hint="默认配置"
|
||||
android:inputType="text"
|
||||
android:padding="12dp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textColorHint="@color/text_hint"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 模型选择器 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spModelSelector"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/edittext_border"
|
||||
android:spinnerMode="dropdown"
|
||||
android:padding="12dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnAddModel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="+ 添加"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/white"
|
||||
android:background="@drawable/button_primary_bg"
|
||||
android:minWidth="0dp"
|
||||
android:minHeight="0dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Base URL -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user