Files
CC-Switch/src/config/geminiProviderPresets.ts
T
Dex Miller 6dd809701b Refactor/simplify proxy logs (#585)
* refactor(proxy): simplify logging for better readability

- Delete 17 verbose debug logs from handlers, streaming, and response_processor
- Convert excessive INFO logs to DEBUG level for internal processing details
- Add 2 critical INFO logs in forwarder.rs for failover scenarios:
  - Log when switching to next provider after failure
  - Log when all providers have been exhausted
- Fix clippy uninlined_format_args warning

This reduces log noise while maintaining visibility into key user-facing decisions.

* fix: replace unsafe unwrap() calls with proper error handling

- database/dao/mcp.rs: Use map_err for serde_json serialization
- database/dao/providers.rs: Use map_err for settings_config and meta serialization
- commands/misc.rs: Use expect() for compile-time regex pattern
- services/prompt.rs: Use unwrap_or_default() for SystemTime
- deeplink/provider.rs: Replace unwrap() with is_none_or pattern for Option checks

Reduces potential panic points from 26 to 1 (static regex init, safe).

* refactor(proxy): simplify verbose logging output

- Remove response JSON full output logging in response_processor
- Remove per-request INFO logs in provider_router (failover status, provider selection)
- Change model mapping log from INFO to DEBUG
- Change usage logging failure from INFO to WARN
- Remove redundant debug logs for circuit breaker operations

Reduces log noise significantly while preserving important warnings and errors.

* feat(proxy): add structured log codes for i18n support

Add error code system to proxy module logs for multi-language support:

- CB-001~006: Circuit breaker state transitions and triggers
- SRV-001~004: Proxy server lifecycle events
- FWD-001~002: Request forwarding and failover
- FO-001~005: Failover switch operations
- USG-001~002: Usage logging errors

Log format: [CODE] Chinese message
Frontend/log tools can map codes to any language.

New file: src/proxy/log_codes.rs - centralized code definitions

* chore: bump version to 3.9.1

* style: format code with prettier and rustfmt

* fix(ui): allow number inputs to be fully cleared before saving

- Convert numeric state to string type for controlled inputs
- Use isNaN() check instead of || fallback to allow 0 values
- Apply fix to ProxyPanel, CircuitBreakerConfigPanel,
  AutoFailoverConfigPanel, and ModelTestConfigPanel

* feat(pricing): support @ separator in model name matching

- Refactor model name cleaning into chained method calls
- Add @ to - replacement (e.g., gpt-5.2-codex@low → gpt-5.2-codex-low)
- Add test case for @ separator matching

* fix(proxy): improve validation and error handling in proxy config panels

- Add StopTimeout/StopFailed error types for proper stop() error reporting
- Replace silent clamp with validation-and-block in config panels
- Add listenAddress format validation in ProxyPanel
- Use log_codes constants instead of hardcoded strings
- Use once_cell::Lazy for regex precompilation

* fix(proxy): harden error handling and input validation

- Handle RwLock poisoning in settings.rs with unwrap_or_else
- Add fallback for dirs::home_dir() in config modules
- Normalize localhost to 127.0.0.1 in ProxyPanel
- Format IPv6 addresses with brackets for valid URLs
- Strict port validation with pure digit regex
- Treat NaN as validation failure in config panels
- Log warning on cost_multiplier parse failure
- Align timeoutSeconds range to [0, 300] across all panels
2026-01-11 20:50:54 +08:00

167 lines
4.3 KiB
TypeScript

import type { ProviderCategory } from "@/types";
/**
* Gemini 预设供应商的视觉主题配置
*/
export interface GeminiPresetTheme {
/** 图标类型:'gemini' | 'generic' */
icon?: "gemini" | "generic";
/** 背景色(选中状态),支持 hex 颜色 */
backgroundColor?: string;
/** 文字色(选中状态),支持 hex 颜色 */
textColor?: string;
}
export interface GeminiProviderPreset {
name: string;
websiteUrl: string;
apiKeyUrl?: string;
settingsConfig: object;
baseURL?: string;
model?: string;
description?: string;
category?: ProviderCategory;
isPartner?: boolean;
partnerPromotionKey?: string;
endpointCandidates?: string[];
theme?: GeminiPresetTheme;
// 图标配置
icon?: string; // 图标名称
iconColor?: string; // 图标颜色
}
export const geminiProviderPresets: GeminiProviderPreset[] = [
{
name: "Google Official",
websiteUrl: "https://ai.google.dev/",
apiKeyUrl: "https://aistudio.google.com/apikey",
settingsConfig: {
env: {},
},
description: "Google 官方 Gemini API (OAuth)",
category: "official",
partnerPromotionKey: "google-official",
theme: {
icon: "gemini",
backgroundColor: "#4285F4",
textColor: "#FFFFFF",
},
icon: "gemini",
iconColor: "#4285F4",
},
{
name: "PackyCode",
websiteUrl: "https://www.packyapi.com",
apiKeyUrl: "https://www.packyapi.com/register?aff=cc-switch",
settingsConfig: {
env: {
GOOGLE_GEMINI_BASE_URL: "https://www.packyapi.com",
GEMINI_MODEL: "gemini-3-pro",
},
},
baseURL: "https://www.packyapi.com",
model: "gemini-3-pro",
description: "PackyCode",
category: "third_party",
isPartner: true,
partnerPromotionKey: "packycode",
endpointCandidates: [
"https://api-slb.packyapi.com",
"https://www.packyapi.com",
],
icon: "packycode",
},
{
name: "Cubence",
websiteUrl: "https://cubence.com",
apiKeyUrl: "https://cubence.com/signup?code=CCSWITCH&source=ccs",
settingsConfig: {
env: {
GOOGLE_GEMINI_BASE_URL: "https://api.cubence.com",
GEMINI_MODEL: "gemini-3-pro",
},
},
baseURL: "https://api.cubence.com",
model: "gemini-3-pro",
description: "Cubence",
category: "third_party",
isPartner: true,
partnerPromotionKey: "cubence",
endpointCandidates: [
"https://api.cubence.com/v1",
"https://api-cf.cubence.com/v1",
"https://api-dmit.cubence.com/v1",
"https://api-bwg.cubence.com/v1",
],
icon: "cubence",
iconColor: "#000000",
},
{
name: "AIGoCode",
websiteUrl: "https://aigocode.com",
apiKeyUrl: "https://aigocode.com/invite/CC-SWITCH",
settingsConfig: {
env: {
GOOGLE_GEMINI_BASE_URL: "https://api.aigocode.com/gemini",
GEMINI_MODEL: "gemini-3-pro",
},
},
baseURL: "https://api.aigocode.com/gemini",
model: "gemini-3-pro",
description: "AIGoCode",
category: "third_party",
isPartner: true,
partnerPromotionKey: "aigocode",
endpointCandidates: ["https://api.aigocode.com/gemini"],
icon: "aigocode",
iconColor: "#5B7FFF",
},
{
name: "OpenRouter",
websiteUrl: "https://openrouter.ai",
apiKeyUrl: "https://openrouter.ai/keys",
settingsConfig: {
env: {
GOOGLE_GEMINI_BASE_URL: "https://openrouter.ai/api",
GEMINI_MODEL: "gemini-3-pro-preview",
},
},
baseURL: "https://openrouter.ai/api",
model: "gemini-3-pro",
description: "OpenRouter",
category: "aggregator",
icon: "openrouter",
iconColor: "#6566F1",
},
{
name: "自定义",
websiteUrl: "",
settingsConfig: {
env: {
GOOGLE_GEMINI_BASE_URL: "",
GEMINI_MODEL: "gemini-3-pro",
},
},
model: "gemini-3-pro",
description: "自定义 Gemini API 端点",
category: "custom",
},
];
export function getGeminiPresetByName(
name: string,
): GeminiProviderPreset | undefined {
return geminiProviderPresets.find((preset) => preset.name === name);
}
export function getGeminiPresetByUrl(
url: string,
): GeminiProviderPreset | undefined {
if (!url) return undefined;
return geminiProviderPresets.find(
(preset) =>
preset.baseURL &&
url.toLowerCase().includes(preset.baseURL.toLowerCase()),
);
}