mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-30 02:14:43 +08:00
feat(proxy): add isFullUrl toggle for full API endpoint mode
- provider.rs/types.ts: add is_full_url field to ProviderMeta - forwarder.rs: when isFullUrl is set, use base_url directly instead of appending endpoint path; also handle query passthrough and strip beta=true when transforming to /v1/chat/completions - EndpointField.tsx: add Link2 icon toggle button for full URL mode - ClaudeFormFields.tsx: pass through isFullUrl/onFullUrlChange props - ProviderForm.tsx: manage localIsFullUrl state, persist to meta on save - useProviderActions.ts: block switching to isFullUrl or openai_chat providers when proxy is not running, show warning toast - App.tsx: pass isProxyRunning to useProviderActions - i18n: add fullUrlEnabled/fullUrlDisabled/fullUrlHint and proxyRequiredForSwitch translations for zh/en/ja
This commit is contained in:
@@ -240,6 +240,9 @@ pub struct ProviderMeta {
|
||||
/// - "ANTHROPIC_API_KEY": 少数供应商需要原生 API Key
|
||||
#[serde(rename = "apiKeyField", skip_serializing_if = "Option::is_none")]
|
||||
pub api_key_field: Option<String>,
|
||||
/// 是否将 base_url 视为完整 API 端点(不拼接 endpoint 路径)
|
||||
#[serde(rename = "isFullUrl", skip_serializing_if = "Option::is_none")]
|
||||
pub is_full_url: Option<bool>,
|
||||
}
|
||||
|
||||
impl ProviderManager {
|
||||
|
||||
@@ -749,15 +749,55 @@ impl RequestForwarder {
|
||||
// 检查是否需要格式转换
|
||||
let needs_transform = adapter.needs_transform(provider);
|
||||
|
||||
let effective_endpoint =
|
||||
if needs_transform && adapter.name() == "Claude" && endpoint == "/v1/messages" {
|
||||
"/v1/chat/completions"
|
||||
// 检查 isFullUrl 模式:直接使用 base_url 作为完整 API 端点
|
||||
let is_full_url = provider
|
||||
.meta
|
||||
.as_ref()
|
||||
.and_then(|m| m.is_full_url)
|
||||
.unwrap_or(false);
|
||||
|
||||
let url = if is_full_url {
|
||||
// 全链接模式:直接使用 base_url,将客户端 query 追加
|
||||
let query = endpoint.split_once('?').map(|(_, q)| q);
|
||||
match query {
|
||||
Some(q) if !q.is_empty() => {
|
||||
if base_url.contains('?') {
|
||||
format!("{base_url}&{q}")
|
||||
} else {
|
||||
format!("{base_url}?{q}")
|
||||
}
|
||||
}
|
||||
_ => base_url.clone(),
|
||||
}
|
||||
} else {
|
||||
// 正常模式:endpoint 可能带 query string,需拆分路径和参数
|
||||
let effective_endpoint: String = if needs_transform && adapter.name() == "Claude" {
|
||||
let (path, query) = match endpoint.split_once('?') {
|
||||
Some((p, q)) => (p, Some(q)),
|
||||
None => (endpoint, None),
|
||||
};
|
||||
if path == "/v1/messages" || path == "/claude/v1/messages" {
|
||||
// 转换到 chat/completions 时剥离 beta=true(Anthropic 专有参数)
|
||||
let filtered = query.map(|q| {
|
||||
q.split('&')
|
||||
.filter(|p| !p.starts_with("beta="))
|
||||
.collect::<Vec<_>>()
|
||||
.join("&")
|
||||
});
|
||||
match filtered.as_deref() {
|
||||
Some(q) if !q.is_empty() => format!("/v1/chat/completions?{q}"),
|
||||
_ => "/v1/chat/completions".to_string(),
|
||||
}
|
||||
} else {
|
||||
endpoint.to_string()
|
||||
}
|
||||
} else {
|
||||
endpoint
|
||||
endpoint.to_string()
|
||||
};
|
||||
|
||||
// 使用适配器构建 URL
|
||||
let url = adapter.build_url(&base_url, effective_endpoint);
|
||||
// 使用适配器构建 URL
|
||||
adapter.build_url(&base_url, &effective_endpoint)
|
||||
};
|
||||
|
||||
// 应用模型映射(独立于格式转换)
|
||||
let (mapped_body, _original_model, _mapped_model) =
|
||||
|
||||
Reference in New Issue
Block a user