- 设置页新增模型下拉选择,内置参考映射兜底 - TraeModelProvider 在线拉取账号可用模型(/api/remote/v1/models) - 选中模型持久化,作为反代缺省模型 - 常用 OpenAI/Claude 模型名自动映射到 Trae 内部模型 - 修复探针测试请求体混入反斜杠导致 JSON 无效的问题 - 版本升至 1.7.5
This commit is contained in:
parent
8a9d9432fe
commit
0241840f9c
@ -16,8 +16,8 @@ android {
|
||||
applicationId = "com.rainy.token"
|
||||
minSdk = 31
|
||||
targetSdk = 35
|
||||
versionCode = 24
|
||||
versionName = "1.7.4"
|
||||
versionCode = 25
|
||||
versionName = "1.7.5"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@ -35,6 +35,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
||||
class TraeChatProxy @Inject constructor(
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val credentialRepository: CredentialRepository,
|
||||
private val modelProvider: TraeModelProvider,
|
||||
) {
|
||||
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
@ -228,6 +229,13 @@ class TraeChatProxy @Inject constructor(
|
||||
return null
|
||||
}
|
||||
|
||||
/** 外部模型名 -> Trae 内部模型名;空/auto 用设置页选择的默认模型。 */
|
||||
private fun normalizeModel(raw: String?): String {
|
||||
val id = raw?.trim()?.takeIf { it.isNotBlank() } ?: return modelProvider.selectedModel
|
||||
if (id.equals("auto", ignoreCase = true)) return modelProvider.selectedModel
|
||||
return MODEL_ALIASES[id.lowercase()] ?: id
|
||||
}
|
||||
|
||||
private fun buildUpstreamBody(raw: String, credential: Credential.TraeCredential): String {
|
||||
val src = try {
|
||||
json.parseToJsonElement(raw) as? JsonObject
|
||||
@ -235,8 +243,8 @@ class TraeChatProxy @Inject constructor(
|
||||
null
|
||||
} ?: return raw
|
||||
|
||||
val model = (src["model"] as? JsonPrimitive)?.contentOrNull?.takeIf { it.isNotBlank() }
|
||||
?: "glm-5.2"
|
||||
val rawModel = (src["model"] as? JsonPrimitive)?.contentOrNull?.takeIf { it.isNotBlank() }
|
||||
val model = normalizeModel(rawModel)
|
||||
val messages = convertNativeMessages(src["messages"])
|
||||
val sessionId = UUID.randomUUID().toString().replace("-", "")
|
||||
|
||||
@ -255,4 +263,50 @@ class TraeChatProxy @Inject constructor(
|
||||
}
|
||||
}.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** OpenAI/Claude 常用名 -> Trae CN 内部模型名(参考 trae2api-cn)。 */
|
||||
private val MODEL_ALIASES = mapOf(
|
||||
"auto" to "glm-5.2",
|
||||
"gpt-4o" to "DeepSeek-V4-Pro",
|
||||
"gpt-4o-latest" to "DeepSeek-V4-Pro",
|
||||
"gpt-4.1" to "DeepSeek-V4-Pro",
|
||||
"deepseek-v3" to "DeepSeek-V4-Pro",
|
||||
"deepseek-r1" to "DeepSeek-V4-Pro",
|
||||
"gpt-4o-mini" to "DeepSeek-V4-Flash",
|
||||
"claude-opus-4-7" to "glm-5.2",
|
||||
"claude-opus-4-6" to "glm-5.2",
|
||||
"claude-opus-4-5" to "glm-5.2",
|
||||
"claude-sonnet-4-6" to "glm-5.2",
|
||||
"claude-sonnet-4-5" to "glm-5.2",
|
||||
"claude-sonnet-4" to "glm-5.2",
|
||||
"claude-3.7-sonnet" to "glm-5.2",
|
||||
"claude-3-7-sonnet" to "glm-5.2",
|
||||
"claude-3.5-sonnet" to "glm-5.2",
|
||||
"claude-haiku-4-5" to "glm-5.1",
|
||||
"deepseek-v4-flash-official" to "DeepSeek-V4-Flash-Official",
|
||||
"deepseek-v4-pro-official" to "DeepSeek-V4-Pro-Official",
|
||||
"doubao-seed-evolving" to "Doubao-Seed-Evolving",
|
||||
"deepseek-v4-pro" to "DeepSeek-V4-Pro",
|
||||
"deepseek-v4-flash" to "DeepSeek-V4-Flash",
|
||||
"seed-2.1-pro" to "Doubao-Seed-2.1-Pro",
|
||||
"seed-2.1-turbo" to "Doubao-Seed-2.1-Turbo",
|
||||
"seed-code" to "Doubao-Seed-Code",
|
||||
"seed-evolving" to "Doubao-Seed-Evolving",
|
||||
"qwen3.7-plus" to "qwen-3.7-plus",
|
||||
"kimi-k2.6" to "kimi-k2.6",
|
||||
"kimi-k3" to "kimi-k3",
|
||||
"kimi-k2.7-code" to "kimi-k2.7-code",
|
||||
"kimi-k2" to "kimi-k2",
|
||||
"kimi-k2.5" to "kimi-k2.5",
|
||||
"minimax-m3" to "minimax-m3",
|
||||
"minimax-m2.7" to "minimax-m2.7",
|
||||
"minimax-m2.1" to "minimax-m2.1",
|
||||
"mimo-v2.5" to "mimo-v2.5",
|
||||
"mimo-v2.5-pro" to "mimo-v2.5-pro",
|
||||
"minimax-m25" to "minimax-m25",
|
||||
"qwen36-35b" to "qwen36-35b",
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,161 @@
|
||||
package com.rainy.token.data.proxy
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.rainy.token.data.repository.CredentialRepository
|
||||
import com.rainy.token.domain.model.Credential
|
||||
import com.rainy.token.domain.service.ServiceType
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.contentOrNull
|
||||
import okhttp3.Headers.Companion.toHeaders
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
||||
/**
|
||||
* Trae 模型列表:内置参考映射 + 在线拉取账号可用模型 + 记住用户选择。
|
||||
* 选择结果同时供设置页测试和 [TraeChatProxy] 作为缺省模型使用。
|
||||
*/
|
||||
@Singleton
|
||||
class TraeModelProvider @Inject constructor(
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val credentialRepository: CredentialRepository,
|
||||
@ApplicationContext private val context: Context,
|
||||
) {
|
||||
|
||||
data class TraeModel(val id: String, val label: String? = null)
|
||||
|
||||
private val prefs: SharedPreferences =
|
||||
context.getSharedPreferences("rainytoken_proxy", Context.MODE_PRIVATE)
|
||||
|
||||
private val _models = MutableStateFlow(defaultModels())
|
||||
val models: StateFlow<List<TraeModel>> = _models.asStateFlow()
|
||||
|
||||
/** 当前默认模型(用户在设置页选择的 Trae 模型名)。 */
|
||||
var selectedModel: String = prefs.getString(KEY_MODEL, "glm-5.2") ?: "glm-5.2"
|
||||
private set
|
||||
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
|
||||
fun setSelectedModel(id: String) {
|
||||
if (id.isBlank()) return
|
||||
selectedModel = id
|
||||
prefs.edit().putString(KEY_MODEL, id).apply()
|
||||
}
|
||||
|
||||
/** 拉取账号在线模型列表;失败时保留内置列表并返回 false。 */
|
||||
suspend fun refreshFor(forcedRegion: ProviderRegion?): Boolean = withContext(Dispatchers.IO) {
|
||||
val credential = credentialRepository.get(ServiceType.TRAE, null)
|
||||
?: return@withContext false
|
||||
if (credential !is Credential.TraeCredential) return@withContext false
|
||||
val jwt = credential.jwt.trim().takeIf { it.isNotBlank() } ?: return@withContext false
|
||||
|
||||
val effectiveRegion = forcedRegion ?: runCatching {
|
||||
ProviderRegion.valueOf(credential.region.uppercase())
|
||||
}.getOrNull()
|
||||
val intl = effectiveRegion == ProviderRegion.INTL
|
||||
val base = if (intl) "https://a0ai-api-sg.byteintlapi.com" else "https://trae-api-cn.mchost.guru"
|
||||
val origin = if (intl) "https://solo.trae.ai" else "https://solo.trae.cn"
|
||||
val url = base + "/api/remote/v1/models" +
|
||||
"?functions=solo_agent_remote%2Csolo_work_remote%2Csolo_design_remote" +
|
||||
"&show_custom_model=true"
|
||||
|
||||
val headers = linkedMapOf(
|
||||
"Authorization" to "Cloud-IDE-JWT $jwt",
|
||||
"Content-Type" to "application/json",
|
||||
"X-Trae-Client-Type" to "web",
|
||||
"X-Preferenced-Language" to "zh-CN",
|
||||
"x-user-region" to if (intl) "SG" else "CN",
|
||||
"Origin" to origin,
|
||||
"Referer" to origin + "/",
|
||||
"User-Agent" to (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
|
||||
"(KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"
|
||||
),
|
||||
)
|
||||
val request = Request.Builder().url(url).headers(headers.toHeaders()).get().build()
|
||||
val parsed = try {
|
||||
okHttpClient.newCall(request).execute().use { resp ->
|
||||
if (!resp.isSuccessful) return@use null
|
||||
val body = resp.body?.string() ?: return@use null
|
||||
parseModelList(body)
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
if (parsed.isNullOrEmpty()) return@withContext false
|
||||
_models.value = parsed
|
||||
true
|
||||
}
|
||||
|
||||
private fun parseModelList(body: String): List<TraeModel>? {
|
||||
val root = runCatching { json.parseToJsonElement(body) as? JsonObject }.getOrNull()
|
||||
?: return null
|
||||
val list = (root["data"] as? JsonObject)?.get("list") as? JsonArray ?: return null
|
||||
val seen = LinkedHashMap<String, TraeModel>()
|
||||
for (groupEl in list) {
|
||||
val group = groupEl as? JsonObject ?: continue
|
||||
val models = group["models"] as? JsonArray ?: continue
|
||||
for (rawEl in models) {
|
||||
val raw = rawEl as? JsonObject ?: continue
|
||||
val id = (raw["name"] as? JsonPrimitive)?.contentOrNull?.trim()
|
||||
?.takeIf { it.isNotEmpty() } ?: continue
|
||||
val label = (raw["display_name"] as? JsonPrimitive)?.contentOrNull
|
||||
?: (raw["display_model_name"] as? JsonPrimitive)?.contentOrNull
|
||||
?: id
|
||||
seen[id] = TraeModel(id, label)
|
||||
}
|
||||
}
|
||||
return seen.values.toList().ifEmpty { null }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_MODEL = "trae_default_model"
|
||||
|
||||
/** 内置兜底模型(参考 trae2api-cn 的模型映射 /v1/models 列表)。 */
|
||||
fun defaultModels(): List<TraeModel> = listOf(
|
||||
TraeModel("glm-5.2", "GLM-5.2"),
|
||||
TraeModel("glm-5.3", "GLM-5.3"),
|
||||
TraeModel("glm-5.1", "GLM-5.1"),
|
||||
TraeModel("glm-5", "GLM-5"),
|
||||
TraeModel("glm-4.7", "GLM-4.7"),
|
||||
TraeModel("glm-4.6", "GLM-4.6"),
|
||||
TraeModel("DeepSeek-V4-Pro", "DeepSeek-V4-Pro"),
|
||||
TraeModel("DeepSeek-V4-Pro-Official", "DeepSeek-V4-Pro 正式版"),
|
||||
TraeModel("DeepSeek-V4-Flash", "DeepSeek-V4-Flash"),
|
||||
TraeModel("DeepSeek-V4-Flash-Official", "DeepSeek-V4-Flash 正式版"),
|
||||
TraeModel("Doubao-Seed-2.1-Pro", "Doubao-Seed-2.1-Pro"),
|
||||
TraeModel("Doubao-Seed-2.1-Turbo", "Doubao-Seed-2.1-Turbo"),
|
||||
TraeModel("Doubao-Seed-Code", "Doubao-Seed-Code"),
|
||||
TraeModel("Doubao-Seed-Evolving", "Doubao-Seed-Evolving"),
|
||||
TraeModel("qwen-3.7-plus", "qwen-3.7-plus"),
|
||||
TraeModel("qwen-3.6-plus", "qwen-3.6-plus"),
|
||||
TraeModel("qwen3.8-max", "qwen3.8-max"),
|
||||
TraeModel("qwen-3.5", "qwen-3.5"),
|
||||
TraeModel("qwen3-coder", "qwen3-coder"),
|
||||
TraeModel("kimi-k2.6", "kimi-k2.6"),
|
||||
TraeModel("kimi-k3", "kimi-k3"),
|
||||
TraeModel("kimi-k2.7-code", "kimi-k2.7-code"),
|
||||
TraeModel("kimi-k2", "kimi-k2"),
|
||||
TraeModel("kimi-k2.5", "kimi-k2.5"),
|
||||
TraeModel("minimax-m3", "minimax-m3"),
|
||||
TraeModel("minimax-m2.7", "minimax-m2.7"),
|
||||
TraeModel("minimax-m2.1", "minimax-m2.1"),
|
||||
TraeModel("mimo-v2.5-pro", "mimo-v2.5-pro"),
|
||||
TraeModel("mimo-v2.5", "mimo-v2.5"),
|
||||
TraeModel("minimax-m25", "minimax-m25"),
|
||||
TraeModel("qwen36-35b", "qwen36-35b"),
|
||||
TraeModel("work", "Work(200K 档)"),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,7 @@ import com.rainy.token.data.proxy.KtorLocalProxyServer
|
||||
import com.rainy.token.data.proxy.LocalProxyServer
|
||||
import com.rainy.token.data.proxy.Sub2ApiChatProxy
|
||||
import com.rainy.token.data.proxy.TraeChatProxy
|
||||
import com.rainy.token.data.proxy.TraeModelProvider
|
||||
import com.rainy.token.data.proxy.WorkBuddyChatProxy
|
||||
import com.rainy.token.data.repository.WorkBuddyRepository
|
||||
import dagger.Module
|
||||
@ -250,8 +251,9 @@ object NetworkModule {
|
||||
@Singleton
|
||||
fun provideTraeChatProxy(
|
||||
okHttpClient: OkHttpClient,
|
||||
credentialRepository: CredentialRepository
|
||||
): TraeChatProxy = TraeChatProxy(okHttpClient, credentialRepository)
|
||||
credentialRepository: CredentialRepository,
|
||||
traeModelProvider: TraeModelProvider,
|
||||
): TraeChatProxy = TraeChatProxy(okHttpClient, credentialRepository, traeModelProvider)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
||||
@ -33,6 +33,8 @@ import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@ -60,6 +62,7 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.rainy.token.domain.model.CredentialStatus
|
||||
import com.rainy.token.data.proxy.TraeModelProvider
|
||||
import com.rainy.token.domain.service.ServiceType
|
||||
import com.rainy.token.ui.components.ServiceIcon
|
||||
import com.rainy.token.ui.components.StatusChip
|
||||
@ -105,6 +108,8 @@ fun SettingsScreen(
|
||||
val proxyError by viewModel.proxyError.collectAsStateWithLifecycle()
|
||||
val proxyDebug by viewModel.proxyDebug.collectAsStateWithLifecycle()
|
||||
val proxyDebugRaw by viewModel.proxyDebugRaw.collectAsStateWithLifecycle()
|
||||
val proxyModels by viewModel.proxyModels.collectAsStateWithLifecycle()
|
||||
val proxyModel by viewModel.proxyModel.collectAsStateWithLifecycle()
|
||||
var showLanguageDialog by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
@ -182,6 +187,10 @@ fun SettingsScreen(
|
||||
error = proxyError,
|
||||
debug = proxyDebug,
|
||||
debugRaw = proxyDebugRaw,
|
||||
models = proxyModels,
|
||||
selectedModel = proxyModel,
|
||||
onSelectModel = viewModel::selectProxyModel,
|
||||
onRefreshModels = viewModel::refreshProxyModels,
|
||||
onToggle = viewModel::setProxyEnabled,
|
||||
onTestTrae = viewModel::testTraeStream,
|
||||
onTestWorkBuddy = viewModel::testWorkBuddyStream
|
||||
@ -216,11 +225,16 @@ private fun ProxyGatewayCard(
|
||||
error: String?,
|
||||
debug: String?,
|
||||
debugRaw: String?,
|
||||
models: List<TraeModelProvider.TraeModel>,
|
||||
selectedModel: String,
|
||||
onSelectModel: (String) -> Unit,
|
||||
onRefreshModels: () -> Unit,
|
||||
onToggle: (Boolean) -> Unit,
|
||||
onTestTrae: () -> Unit,
|
||||
onTestWorkBuddy: () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var modelMenuExpanded by remember { mutableStateOf(false) }
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
@ -270,6 +284,39 @@ private fun ProxyGatewayCard(
|
||||
Text("测试 WorkBuddy 流")
|
||||
}
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "模型",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = InkMuted
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Box {
|
||||
TextButton(onClick = { modelMenuExpanded = true }) {
|
||||
Text(selectedModel + " ▾")
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = modelMenuExpanded,
|
||||
onDismissRequest = { modelMenuExpanded = false }
|
||||
) {
|
||||
models.forEach { m ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(m.label ?: m.id) },
|
||||
onClick = {
|
||||
onSelectModel(m.id)
|
||||
modelMenuExpanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
TextButton(onClick = onRefreshModels) {
|
||||
Text("刷新")
|
||||
}
|
||||
}
|
||||
if (debug != null) {
|
||||
Spacer(modifier = Modifier.padding(top = 8.dp))
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
|
||||
@ -7,6 +7,7 @@ import com.rainy.token.data.proxy.ProviderRegion
|
||||
import com.rainy.token.data.proxy.ProxyUpstreamStream
|
||||
import com.rainy.token.data.proxy.ProxyServerConfig
|
||||
import com.rainy.token.data.proxy.TraeChatProxy
|
||||
import com.rainy.token.data.proxy.TraeModelProvider
|
||||
import com.rainy.token.data.proxy.WorkBuddyChatProxy
|
||||
import com.rainy.token.data.repository.CredentialRepository
|
||||
import com.rainy.token.domain.model.CredentialStatus
|
||||
@ -38,7 +39,8 @@ class SettingsViewModel @Inject constructor(
|
||||
private val credentialRepository: CredentialRepository,
|
||||
private val localProxyServer: LocalProxyServer,
|
||||
private val traeChatProxy: TraeChatProxy,
|
||||
private val workBuddyChatProxy: WorkBuddyChatProxy
|
||||
private val workBuddyChatProxy: WorkBuddyChatProxy,
|
||||
private val traeModelProvider: TraeModelProvider,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(SettingsUiState())
|
||||
@ -74,12 +76,34 @@ class SettingsViewModel @Inject constructor(
|
||||
private val _proxyDebugRaw = MutableStateFlow<String?>(null)
|
||||
val proxyDebugRaw: StateFlow<String?> = _proxyDebugRaw.asStateFlow()
|
||||
|
||||
/** Trae 可用模型列表(内置兜底 + 在线拉取账号模型)。 */
|
||||
val proxyModels: StateFlow<List<TraeModelProvider.TraeModel>> = traeModelProvider.models
|
||||
|
||||
/** 当前选择的 Trae 默认模型。 */
|
||||
private val _proxyModel = MutableStateFlow(traeModelProvider.selectedModel)
|
||||
val proxyModel: StateFlow<String> = _proxyModel.asStateFlow()
|
||||
|
||||
/** 切换 Trae 默认模型并持久化。 */
|
||||
fun selectProxyModel(id: String) {
|
||||
traeModelProvider.setSelectedModel(id)
|
||||
_proxyModel.value = id
|
||||
}
|
||||
|
||||
/** 拉取当前账号可用的 Trae 模型列表。 */
|
||||
fun refreshProxyModels() {
|
||||
viewModelScope.launch {
|
||||
val ok = traeModelProvider.refreshFor(ProviderRegion.CN)
|
||||
if (!ok) _proxyDebug.value = "模型列表更新失败(当前显示内置列表)"
|
||||
}
|
||||
}
|
||||
|
||||
/** 用 Trae CN 默认账号发一条 stream=true 测试。 */
|
||||
fun testTraeStream() {
|
||||
viewModelScope.launch {
|
||||
_proxyDebug.value = "正在请求 Trae CN 流..."
|
||||
_proxyDebugRaw.value = null
|
||||
val body = """{\"model\":\"glm-5.2\",\"stream\":true,\"messages\":[{\"role\":\"user\",\"content\":\"只回复OK两个字\"}],\"max_tokens\":100}\"""
|
||||
val model = traeModelProvider.selectedModel
|
||||
val body = """{"model":"$model","stream":true,"messages":[{"role":"user","content":"只回复OK两个字"}],"max_tokens":100}"""
|
||||
try {
|
||||
val stream = traeChatProxy.openStreamingChat(body, null, ProviderRegion.CN)
|
||||
if (stream == null) {
|
||||
@ -108,7 +132,7 @@ class SettingsViewModel @Inject constructor(
|
||||
viewModelScope.launch {
|
||||
_proxyDebug.value = "正在请求 WorkBuddy CN 流..."
|
||||
_proxyDebugRaw.value = null
|
||||
val body = """{\"model\":\"glm-5.2\",\"stream\":true,\"messages\":[{\"role\":\"user\",\"content\":\"只回复OK两个字\"}],\"max_tokens\":100}\"""
|
||||
val body = """{"model":"glm-5.2","stream":true,"messages":[{"role":"user","content":"只回复OK两个字"}],"max_tokens":100}"""
|
||||
try {
|
||||
val stream = workBuddyChatProxy.openStreamingChat(body, null, ProviderRegion.CN)
|
||||
if (stream == null) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user