mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-19 19:50:26 +08:00
fix: resolve rustfmt formatting and clippy warnings
- Apply cargo fmt across schema.rs, session_usage*.rs, skill.rs, usage_stats.rs - Fix clippy::for_kv_map: use messages.values() instead of (_, msg) pattern - Suppress clippy::only_used_in_recursion for intentional recursive base path - Fix prettier formatting in UsageScriptModal.tsx
This commit is contained in:
@@ -1128,9 +1128,7 @@ impl Database {
|
||||
WHERE model_id = ?1",
|
||||
rusqlite::params![model_id, input, output, cache_read, cache_creation],
|
||||
)
|
||||
.map_err(|e| {
|
||||
AppError::Database(format!("更新模型 {model_id} 定价失败: {e}"))
|
||||
})?;
|
||||
.map_err(|e| AppError::Database(format!("更新模型 {model_id} 定价失败: {e}")))?;
|
||||
}
|
||||
|
||||
log::info!("v7 -> v8 迁移完成:data_source 列、session_log_sync 表、修正 13 个模型定价");
|
||||
@@ -1457,7 +1455,14 @@ impl Database {
|
||||
"0",
|
||||
),
|
||||
// Gemini 2.0 系列
|
||||
("gemini-2.0-flash", "Gemini 2.0 Flash", "0.10", "0.40", "0.025", "0"),
|
||||
(
|
||||
"gemini-2.0-flash",
|
||||
"Gemini 2.0 Flash",
|
||||
"0.10",
|
||||
"0.40",
|
||||
"0.025",
|
||||
"0",
|
||||
),
|
||||
// StepFun 系列
|
||||
(
|
||||
"step-3.5-flash",
|
||||
@@ -1469,17 +1474,66 @@ impl Database {
|
||||
),
|
||||
// ====== 国产模型 (USD/1M tokens) ======
|
||||
// Doubao (字节跳动)
|
||||
("doubao-seed-code", "Doubao Seed Code", "0.17", "1.11", "0.02", "0"),
|
||||
(
|
||||
"doubao-seed-code",
|
||||
"Doubao Seed Code",
|
||||
"0.17",
|
||||
"1.11",
|
||||
"0.02",
|
||||
"0",
|
||||
),
|
||||
// DeepSeek 系列
|
||||
("deepseek-v3.2", "DeepSeek V3.2", "0.28", "0.42", "0.028", "0"),
|
||||
("deepseek-v3.1", "DeepSeek V3.1", "0.55", "1.67", "0.055", "0"),
|
||||
(
|
||||
"deepseek-v3.2",
|
||||
"DeepSeek V3.2",
|
||||
"0.28",
|
||||
"0.42",
|
||||
"0.028",
|
||||
"0",
|
||||
),
|
||||
(
|
||||
"deepseek-v3.1",
|
||||
"DeepSeek V3.1",
|
||||
"0.55",
|
||||
"1.67",
|
||||
"0.055",
|
||||
"0",
|
||||
),
|
||||
("deepseek-v3", "DeepSeek V3", "0.28", "1.11", "0.028", "0"),
|
||||
("deepseek-chat", "DeepSeek Chat", "0.28", "0.42", "0.028", "0"),
|
||||
("deepseek-reasoner", "DeepSeek Reasoner", "0.28", "0.42", "0.028", "0"),
|
||||
(
|
||||
"deepseek-chat",
|
||||
"DeepSeek Chat",
|
||||
"0.28",
|
||||
"0.42",
|
||||
"0.028",
|
||||
"0",
|
||||
),
|
||||
(
|
||||
"deepseek-reasoner",
|
||||
"DeepSeek Reasoner",
|
||||
"0.28",
|
||||
"0.42",
|
||||
"0.028",
|
||||
"0",
|
||||
),
|
||||
// Kimi (月之暗面)
|
||||
("kimi-k2-thinking", "Kimi K2 Thinking", "0.55", "2.20", "0.10", "0"),
|
||||
(
|
||||
"kimi-k2-thinking",
|
||||
"Kimi K2 Thinking",
|
||||
"0.55",
|
||||
"2.20",
|
||||
"0.10",
|
||||
"0",
|
||||
),
|
||||
("kimi-k2-0905", "Kimi K2", "0.55", "2.20", "0.10", "0"),
|
||||
("kimi-k2-turbo", "Kimi K2 Turbo", "1.11", "8.06", "0.14", "0"),
|
||||
(
|
||||
"kimi-k2-turbo",
|
||||
"Kimi K2 Turbo",
|
||||
"1.11",
|
||||
"8.06",
|
||||
"0.14",
|
||||
"0",
|
||||
),
|
||||
("kimi-k2.5", "Kimi K2.5", "0.60", "3.00", "0.10", "0"),
|
||||
// MiniMax 系列
|
||||
("minimax-m2.1", "MiniMax M2.1", "0.27", "0.95", "0.03", "0"),
|
||||
@@ -1496,7 +1550,14 @@ impl Database {
|
||||
("glm-4.7", "GLM-4.7", "0.39", "1.75", "0.04", "0"),
|
||||
("glm-4.6", "GLM-4.6", "0.28", "1.11", "0.03", "0"),
|
||||
// Mimo (小米)
|
||||
("mimo-v2-flash", "Mimo V2 Flash", "0.09", "0.29", "0.009", "0"),
|
||||
(
|
||||
"mimo-v2-flash",
|
||||
"Mimo V2 Flash",
|
||||
"0.09",
|
||||
"0.29",
|
||||
"0.009",
|
||||
"0",
|
||||
),
|
||||
];
|
||||
|
||||
for (model_id, display_name, input, output, cache_read, cache_creation) in pricing_data {
|
||||
|
||||
@@ -155,8 +155,8 @@ fn sync_single_file(db: &Database, file_path: &Path) -> Result<(u32, u32), AppEr
|
||||
}
|
||||
|
||||
// 从上次偏移位置开始增量解析
|
||||
let file = fs::File::open(file_path)
|
||||
.map_err(|e| AppError::Config(format!("无法打开文件: {e}")))?;
|
||||
let file =
|
||||
fs::File::open(file_path).map_err(|e| AppError::Config(format!("无法打开文件: {e}")))?;
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
let mut line_offset: i64 = 0;
|
||||
@@ -272,7 +272,7 @@ fn sync_single_file(db: &Database, file_path: &Path) -> Result<(u32, u32), AppEr
|
||||
let mut imported: u32 = 0;
|
||||
let mut skipped: u32 = 0;
|
||||
|
||||
for (_, msg) in &messages {
|
||||
for msg in messages.values() {
|
||||
// 只导入有 stop_reason 的最终条目(完整的 API 调用)
|
||||
if msg.stop_reason.is_none() {
|
||||
continue;
|
||||
@@ -383,26 +383,26 @@ fn insert_session_log_entry(
|
||||
|
||||
let pricing = find_model_pricing_for_session(&conn, &msg.model);
|
||||
let multiplier = Decimal::from(1);
|
||||
let (input_cost, output_cost, cache_read_cost, cache_creation_cost, total_cost) =
|
||||
match pricing {
|
||||
Some(p) => {
|
||||
let cost = CostCalculator::calculate(&usage, &p, multiplier);
|
||||
(
|
||||
cost.input_cost.to_string(),
|
||||
cost.output_cost.to_string(),
|
||||
cost.cache_read_cost.to_string(),
|
||||
cost.cache_creation_cost.to_string(),
|
||||
cost.total_cost.to_string(),
|
||||
)
|
||||
}
|
||||
None => (
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
),
|
||||
};
|
||||
let (input_cost, output_cost, cache_read_cost, cache_creation_cost, total_cost) = match pricing
|
||||
{
|
||||
Some(p) => {
|
||||
let cost = CostCalculator::calculate(&usage, &p, multiplier);
|
||||
(
|
||||
cost.input_cost.to_string(),
|
||||
cost.output_cost.to_string(),
|
||||
cost.cache_read_cost.to_string(),
|
||||
cost.cache_creation_cost.to_string(),
|
||||
cost.total_cost.to_string(),
|
||||
)
|
||||
}
|
||||
None => (
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
"0".to_string(),
|
||||
),
|
||||
};
|
||||
|
||||
conn.execute(
|
||||
"INSERT OR IGNORE INTO proxy_request_logs (
|
||||
|
||||
@@ -746,7 +746,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_normalize_codex_model_strip_prefix() {
|
||||
assert_eq!(normalize_codex_model("openai/gpt-5.4"), "gpt-5.4");
|
||||
assert_eq!(normalize_codex_model("azure/gpt-5.2-codex"), "gpt-5.2-codex");
|
||||
assert_eq!(
|
||||
normalize_codex_model("azure/gpt-5.2-codex"),
|
||||
"gpt-5.2-codex"
|
||||
);
|
||||
assert_eq!(normalize_codex_model("OPENAI/GPT-5.4"), "gpt-5.4");
|
||||
}
|
||||
|
||||
@@ -784,10 +787,7 @@ mod tests {
|
||||
"gpt-5.4"
|
||||
);
|
||||
// prefix + compact date
|
||||
assert_eq!(
|
||||
normalize_codex_model("openai/gpt-5.4-20260305"),
|
||||
"gpt-5.4"
|
||||
);
|
||||
assert_eq!(normalize_codex_model("openai/gpt-5.4-20260305"), "gpt-5.4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -799,7 +799,7 @@ mod tests {
|
||||
output: 50,
|
||||
});
|
||||
let current = CumulativeTokens {
|
||||
input: 110, // delta = 10
|
||||
input: 110, // delta = 10
|
||||
cached_input: 80, // delta = 80(异常:大于 input delta)
|
||||
output: 60,
|
||||
};
|
||||
|
||||
@@ -182,10 +182,7 @@ fn sync_single_gemini_file(db: &Database, file_path: &Path) -> Result<(u32, u32)
|
||||
gemini_msg_count += 1;
|
||||
|
||||
// 提取消息 ID 和模型
|
||||
let message_id = msg
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("unknown");
|
||||
let message_id = msg.get("id").and_then(|v| v.as_str()).unwrap_or("unknown");
|
||||
let model = msg
|
||||
.get("model")
|
||||
.and_then(|v| v.as_str())
|
||||
@@ -222,22 +219,10 @@ fn sync_single_gemini_file(db: &Database, file_path: &Path) -> Result<(u32, u32)
|
||||
/// 从 tokens JSON 对象中提取 token 数据
|
||||
fn parse_gemini_tokens(tokens: &serde_json::Value) -> GeminiTokens {
|
||||
GeminiTokens {
|
||||
input: tokens
|
||||
.get("input")
|
||||
.and_then(|v| v.as_u64())
|
||||
.unwrap_or(0) as u32,
|
||||
output: tokens
|
||||
.get("output")
|
||||
.and_then(|v| v.as_u64())
|
||||
.unwrap_or(0) as u32,
|
||||
cached: tokens
|
||||
.get("cached")
|
||||
.and_then(|v| v.as_u64())
|
||||
.unwrap_or(0) as u32,
|
||||
thoughts: tokens
|
||||
.get("thoughts")
|
||||
.and_then(|v| v.as_u64())
|
||||
.unwrap_or(0) as u32,
|
||||
input: tokens.get("input").and_then(|v| v.as_u64()).unwrap_or(0) as u32,
|
||||
output: tokens.get("output").and_then(|v| v.as_u64()).unwrap_or(0) as u32,
|
||||
cached: tokens.get("cached").and_then(|v| v.as_u64()).unwrap_or(0) as u32,
|
||||
thoughts: tokens.get("thoughts").and_then(|v| v.as_u64()).unwrap_or(0) as u32,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +479,9 @@ mod tests {
|
||||
assert_eq!(tokens.input, 0);
|
||||
assert_eq!(tokens.output, 0);
|
||||
// 全零(包括 cached=0)会被 sync 逻辑跳过
|
||||
assert!(tokens.input == 0 && tokens.output == 0 && tokens.thoughts == 0 && tokens.cached == 0);
|
||||
assert!(
|
||||
tokens.input == 0 && tokens.output == 0 && tokens.thoughts == 0 && tokens.cached == 0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -509,7 +496,8 @@ mod tests {
|
||||
let tokens = parse_gemini_tokens(&json);
|
||||
assert_eq!(tokens.cached, 5000);
|
||||
// 跳过条件:所有四个字段都为 0 才跳过
|
||||
let should_skip = tokens.input == 0 && tokens.output == 0 && tokens.thoughts == 0 && tokens.cached == 0;
|
||||
let should_skip =
|
||||
tokens.input == 0 && tokens.output == 0 && tokens.thoughts == 0 && tokens.cached == 0;
|
||||
assert!(!should_skip, "纯缓存命中记录不应被跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,6 +854,7 @@ impl SkillService {
|
||||
}
|
||||
|
||||
/// 递归收集目录下所有非隐藏文件
|
||||
#[allow(clippy::only_used_in_recursion)]
|
||||
fn collect_files_for_hash(base: &Path, current: &Path, files: &mut Vec<PathBuf>) -> Result<()> {
|
||||
let entries = fs::read_dir(current)
|
||||
.with_context(|| format!("读取目录失败: {}", current.display()))?;
|
||||
@@ -2737,10 +2738,7 @@ impl SkillService {
|
||||
repo_name: repo.clone(),
|
||||
repo_branch: "main".to_string(),
|
||||
installs: s.installs,
|
||||
readme_url: Some(format!(
|
||||
"https://github.com/{}/{}",
|
||||
owner, repo
|
||||
)),
|
||||
readme_url: Some(format!("https://github.com/{}/{}", owner, repo)),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -383,7 +383,10 @@ impl Database {
|
||||
|
||||
let mut rstmt = conn.prepare(&rollup_sql)?;
|
||||
let rrows = if let Some(at) = app_type {
|
||||
rstmt.query_map(params![start_ts, end_ts, bucket_seconds, at], rollup_row_mapper)?
|
||||
rstmt.query_map(
|
||||
params![start_ts, end_ts, bucket_seconds, at],
|
||||
rollup_row_mapper,
|
||||
)?
|
||||
} else {
|
||||
rstmt.query_map(params![start_ts, end_ts, bucket_seconds], rollup_row_mapper)?
|
||||
};
|
||||
@@ -757,38 +760,36 @@ impl Database {
|
||||
LEFT JOIN providers p ON l.provider_id = p.id AND l.app_type = p.app_type
|
||||
WHERE l.request_id = ?"
|
||||
);
|
||||
let result = conn.query_row(
|
||||
&detail_sql,
|
||||
[request_id],
|
||||
|row| {
|
||||
Ok(RequestLogDetail {
|
||||
request_id: row.get(0)?,
|
||||
provider_id: row.get(1)?,
|
||||
provider_name: row.get(2)?,
|
||||
app_type: row.get(3)?,
|
||||
model: row.get(4)?,
|
||||
request_model: row.get(5)?,
|
||||
cost_multiplier: row.get::<_, Option<String>>(6)?.unwrap_or_else(|| "1".to_string()),
|
||||
input_tokens: row.get::<_, i64>(7)? as u32,
|
||||
output_tokens: row.get::<_, i64>(8)? as u32,
|
||||
cache_read_tokens: row.get::<_, i64>(9)? as u32,
|
||||
cache_creation_tokens: row.get::<_, i64>(10)? as u32,
|
||||
input_cost_usd: row.get(11)?,
|
||||
output_cost_usd: row.get(12)?,
|
||||
cache_read_cost_usd: row.get(13)?,
|
||||
cache_creation_cost_usd: row.get(14)?,
|
||||
total_cost_usd: row.get(15)?,
|
||||
is_streaming: row.get::<_, i64>(16)? != 0,
|
||||
latency_ms: row.get::<_, i64>(17)? as u64,
|
||||
first_token_ms: row.get::<_, Option<i64>>(18)?.map(|v| v as u64),
|
||||
duration_ms: row.get::<_, Option<i64>>(19)?.map(|v| v as u64),
|
||||
status_code: row.get::<_, i64>(20)? as u16,
|
||||
error_message: row.get(21)?,
|
||||
created_at: row.get(22)?,
|
||||
data_source: row.get(23)?,
|
||||
})
|
||||
},
|
||||
);
|
||||
let result = conn.query_row(&detail_sql, [request_id], |row| {
|
||||
Ok(RequestLogDetail {
|
||||
request_id: row.get(0)?,
|
||||
provider_id: row.get(1)?,
|
||||
provider_name: row.get(2)?,
|
||||
app_type: row.get(3)?,
|
||||
model: row.get(4)?,
|
||||
request_model: row.get(5)?,
|
||||
cost_multiplier: row
|
||||
.get::<_, Option<String>>(6)?
|
||||
.unwrap_or_else(|| "1".to_string()),
|
||||
input_tokens: row.get::<_, i64>(7)? as u32,
|
||||
output_tokens: row.get::<_, i64>(8)? as u32,
|
||||
cache_read_tokens: row.get::<_, i64>(9)? as u32,
|
||||
cache_creation_tokens: row.get::<_, i64>(10)? as u32,
|
||||
input_cost_usd: row.get(11)?,
|
||||
output_cost_usd: row.get(12)?,
|
||||
cache_read_cost_usd: row.get(13)?,
|
||||
cache_creation_cost_usd: row.get(14)?,
|
||||
total_cost_usd: row.get(15)?,
|
||||
is_streaming: row.get::<_, i64>(16)? != 0,
|
||||
latency_ms: row.get::<_, i64>(17)? as u64,
|
||||
first_token_ms: row.get::<_, Option<i64>>(18)?.map(|v| v as u64),
|
||||
duration_ms: row.get::<_, Option<i64>>(19)?.map(|v| v as u64),
|
||||
status_code: row.get::<_, i64>(20)? as u16,
|
||||
error_message: row.get(21)?,
|
||||
created_at: row.get(22)?,
|
||||
data_source: row.get(23)?,
|
||||
})
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(mut detail) => {
|
||||
|
||||
@@ -1066,7 +1066,7 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
|
||||
...script,
|
||||
timeout:
|
||||
e.target.value === ""
|
||||
? (("" as unknown) as number)
|
||||
? ("" as unknown as number)
|
||||
: Number(e.target.value),
|
||||
})
|
||||
}
|
||||
@@ -1098,7 +1098,7 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
|
||||
...script,
|
||||
autoQueryInterval:
|
||||
e.target.value === ""
|
||||
? (("" as unknown) as number)
|
||||
? ("" as unknown as number)
|
||||
: Number(e.target.value),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user