From c015fcf5f0cd80a6cdba02d7a9ae24991c92b454 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Mon, 18 Aug 2025 16:40:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0opus=E5=BC=80=E5=90=AF?= =?UTF-8?q?=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands/relay_adapters.rs | 113 +++++++++++++++++++---- src/components/RelayStationManager.tsx | 75 +++++++++++---- src/components/Terminal.tsx | 81 ++++++++-------- src/lib/api.ts | 21 +++-- 4 files changed, 201 insertions(+), 89 deletions(-) diff --git a/src-tauri/src/commands/relay_adapters.rs b/src-tauri/src/commands/relay_adapters.rs index 15e32ae..66a6b44 100644 --- a/src-tauri/src/commands/relay_adapters.rs +++ b/src-tauri/src/commands/relay_adapters.rs @@ -1002,6 +1002,7 @@ pub struct PackycodeUserQuota { pub plan_expires_at: String, // 计划过期时间 pub username: Option, // 用户名 pub email: Option, // 邮箱 + pub opus_enabled: Option, // 是否启用Opus模型 } /// 获取 PackyCode 用户信息(额度等) @@ -1044,23 +1045,37 @@ pub async fn packycode_get_user_quota(station_id: String, db: State<'_, AgentDb> "https://www.packycode.com/api/backend/users/info" }; - // 创建 HTTP 客户端 + // 创建 HTTP 客户端 - 禁用系统代理 let client = Client::builder() - .timeout(Duration::from_secs(10)) + .timeout(Duration::from_secs(30)) + .no_proxy() // 禁用所有代理 .build() .map_err(|e| format!("创建 HTTP 客户端失败: {}", e))?; - // 发送请求 + log::info!("正在请求 PackyCode 用户信息: {}", url); + log::debug!("使用 Token: {}...", &station.system_token[..10.min(station.system_token.len())]); + + // 发送请求 - 只使用必要的请求头 let response = client .get(url) .header("Authorization", format!("Bearer {}", station.system_token)) - .header("User-Agent", "Apifox/1.0.0 (https://apifox.com)") + .header("User-Agent", "Claudia") .header("Accept", "*/*") - .header("Host", if url.contains("share.packycode.com") { "share.packycode.com" } else { "www.packycode.com" }) - .header("Connection", "keep-alive") .send() .await - .map_err(|e| format!("请求失败: {}", e))?; + .map_err(|e| { + log::error!("请求 PackyCode API 失败: {}", e); + // 提供更详细的错误信息 + if e.is_connect() { + format!("网络连接失败: {}", e) + } else if e.is_timeout() { + format!("请求超时: {}", e) + } else if e.is_request() { + format!("请求错误: {}", e) + } else { + format!("请求失败: {}", e) + } + })?; // 检查响应状态 if !response.status().is_success() { @@ -1082,28 +1097,86 @@ pub async fn packycode_get_user_quota(station_id: String, db: State<'_, AgentDb> // 提取额度信息 let quota = PackycodeUserQuota { daily_budget_usd: response_data.get("daily_budget_usd") - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) + .and_then(|v| { + if v.is_string() { + v.as_str().and_then(|s| s.parse::().ok()) + } else if v.is_f64() { + v.as_f64() + } else if v.is_i64() { + v.as_i64().map(|i| i as f64) + } else { + None + } + }) .unwrap_or(0.0), daily_spent_usd: response_data.get("daily_spent_usd") - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) + .and_then(|v| { + if v.is_null() { + Some(0.0) + } else if v.is_string() { + v.as_str().and_then(|s| s.parse::().ok()) + } else if v.is_f64() { + v.as_f64() + } else if v.is_i64() { + v.as_i64().map(|i| i as f64) + } else { + None + } + }) .unwrap_or(0.0), monthly_budget_usd: response_data.get("monthly_budget_usd") - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) + .and_then(|v| { + if v.is_string() { + v.as_str().and_then(|s| s.parse::().ok()) + } else if v.is_f64() { + v.as_f64() + } else if v.is_i64() { + v.as_i64().map(|i| i as f64) + } else { + None + } + }) .unwrap_or(0.0), monthly_spent_usd: response_data.get("monthly_spent_usd") - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) + .and_then(|v| { + if v.is_null() { + Some(0.0) + } else if v.is_string() { + v.as_str().and_then(|s| s.parse::().ok()) + } else if v.is_f64() { + v.as_f64() + } else if v.is_i64() { + v.as_i64().map(|i| i as f64) + } else { + None + } + }) .unwrap_or(0.0), balance_usd: response_data.get("balance_usd") - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) + .and_then(|v| { + if v.is_string() { + v.as_str().and_then(|s| s.parse::().ok()) + } else if v.is_f64() { + v.as_f64() + } else if v.is_i64() { + v.as_i64().map(|i| i as f64) + } else { + None + } + }) .unwrap_or(0.0), total_spent_usd: response_data.get("total_spent_usd") - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) + .and_then(|v| { + if v.is_string() { + v.as_str().and_then(|s| s.parse::().ok()) + } else if v.is_f64() { + v.as_f64() + } else if v.is_i64() { + v.as_i64().map(|i| i as f64) + } else { + None + } + }) .unwrap_or(0.0), plan_type: response_data.get("plan_type") .and_then(|v| v.as_str()) @@ -1119,6 +1192,8 @@ pub async fn packycode_get_user_quota(station_id: String, db: State<'_, AgentDb> email: response_data.get("email") .and_then(|v| v.as_str()) .map(|s| s.to_string()), + opus_enabled: response_data.get("opus_enabled") + .and_then(|v| v.as_bool()), }; Ok(quota) diff --git a/src/components/RelayStationManager.tsx b/src/components/RelayStationManager.tsx index 211cad3..04f0fbb 100644 --- a/src/components/RelayStationManager.tsx +++ b/src/components/RelayStationManager.tsx @@ -357,6 +357,11 @@ const RelayStationManager: React.FC = ({ onBack }) => {quotaData[station.id].plan_type.toUpperCase()} + {quotaData[station.id].opus_enabled && ( + + Opus + + )} {quotaData[station.id].plan_expires_at && ( @@ -369,7 +374,7 @@ const RelayStationManager: React.FC = ({ onBack }) =>
账户余额: - ${quotaData[station.id].balance_usd.toFixed(2)} + ${Number(quotaData[station.id].balance_usd).toFixed(2)}
@@ -378,21 +383,36 @@ const RelayStationManager: React.FC = ({ onBack }) =>
日额度:
- quotaData[station.id].daily_budget_usd * 0.8 ? 'text-orange-600' : 'text-green-600'}> - ${quotaData[station.id].daily_spent_usd.toFixed(2)} - - / - ${quotaData[station.id].daily_budget_usd.toFixed(2)} + {(() => { + const daily_spent = Number(quotaData[station.id].daily_spent_usd || 0); + const daily_budget = Number(quotaData[station.id].daily_budget_usd); + return ( + <> + daily_budget * 0.8 ? 'text-orange-600' : 'text-green-600'}> + ${daily_spent.toFixed(2)} + + / + ${daily_budget.toFixed(2)} + + ); + })()}
0.8 - ? 'bg-orange-500' - : 'bg-green-500' + (() => { + const daily_spent = Number(quotaData[station.id].daily_spent_usd || 0); + const daily_budget = Number(quotaData[station.id].daily_budget_usd); + return daily_spent / daily_budget > 0.8; + })() ? 'bg-orange-500' : 'bg-green-500' }`} - style={{ width: `${Math.min((quotaData[station.id].daily_spent_usd / quotaData[station.id].daily_budget_usd) * 100, 100)}%` }} + style={{ width: `${Math.min( + (() => { + const daily_spent = Number(quotaData[station.id].daily_spent_usd || 0); + const daily_budget = Number(quotaData[station.id].daily_budget_usd); + return (daily_spent / daily_budget) * 100; + })(), 100)}%` }} />
@@ -402,28 +422,43 @@ const RelayStationManager: React.FC = ({ onBack }) =>
月额度:
- quotaData[station.id].monthly_budget_usd * 0.8 ? 'text-orange-600' : 'text-green-600'}> - ${quotaData[station.id].monthly_spent_usd.toFixed(2)} - - / - ${quotaData[station.id].monthly_budget_usd.toFixed(2)} + {(() => { + const monthly_spent = Number(quotaData[station.id].monthly_spent_usd || 0); + const monthly_budget = Number(quotaData[station.id].monthly_budget_usd); + return ( + <> + monthly_budget * 0.8 ? 'text-orange-600' : 'text-green-600'}> + ${monthly_spent.toFixed(2)} + + / + ${monthly_budget.toFixed(2)} + + ); + })()}
0.8 - ? 'bg-orange-500' - : 'bg-green-500' + (() => { + const monthly_spent = Number(quotaData[station.id].monthly_spent_usd || 0); + const monthly_budget = Number(quotaData[station.id].monthly_budget_usd); + return monthly_spent / monthly_budget > 0.8; + })() ? 'bg-orange-500' : 'bg-green-500' }`} - style={{ width: `${Math.min((quotaData[station.id].monthly_spent_usd / quotaData[station.id].monthly_budget_usd) * 100, 100)}%` }} + style={{ width: `${Math.min( + (() => { + const monthly_spent = Number(quotaData[station.id].monthly_spent_usd || 0); + const monthly_budget = Number(quotaData[station.id].monthly_budget_usd); + return (monthly_spent / monthly_budget) * 100; + })(), 100)}%` }} />
{/* 总消费 */}
- 总消费: ${quotaData[station.id].total_spent_usd.toFixed(2)} + 总消费: ${Number(quotaData[station.id].total_spent_usd).toFixed(2)}
- +
{onToggleMaximize && (