diff --git a/app/components/settings.tsx b/app/components/settings.tsx
index 881c12caeb3..628bc673f64 100644
--- a/app/components/settings.tsx
+++ b/app/components/settings.tsx
@@ -86,6 +86,7 @@ import { getClientConfig } from "../config/client";
import { useSyncStore } from "../store/sync";
import { nanoid } from "nanoid";
import { useMaskStore } from "../store/mask";
+import { PROXY_MODES, ProxyMode } from "../store/access";
import { ProviderType } from "../utils/cloud";
import { TTSConfigList } from "./tts-config";
import { RealtimeConfigList } from "./realtime-chat/realtime-config";
@@ -737,6 +738,66 @@ export function Settings() {
>
);
+ const desktopProxyConfigComponent = clientConfig?.isApp && (
+ <>
+
+
+
+
+ {accessStore.proxyMode !== "system" && (
+ <>
+
+
+ accessStore.update(
+ (access) => (access.proxyHost = e.currentTarget.value),
+ )
+ }
+ >
+
+
+
+
+ accessStore.update(
+ (access) => (access.proxyPort = e.currentTarget.value),
+ )
+ }
+ >
+
+ >
+ )}
+ >
+ );
const openAIConfigComponent = accessStore.provider ===
ServiceProvider.OpenAI && (
@@ -1459,44 +1520,44 @@ export function Settings() {
>
);
- const ai302ConfigComponent = accessStore.provider === ServiceProvider["302.AI"] && (
+ const ai302ConfigComponent = accessStore.provider ===
+ ServiceProvider["302.AI"] && (
<>
+
+ accessStore.update(
+ (access) => (access.ai302Url = e.currentTarget.value),
+ )
}
- >
-
- accessStore.update(
- (access) => (access.ai302Url = e.currentTarget.value),
- )
- }
- >
-
-
- {
- accessStore.update(
- (access) => (access.ai302ApiKey = e.currentTarget.value),
- );
- }}
- />
-
- >
+ >
+
+
+ {
+ accessStore.update(
+ (access) => (access.ai302ApiKey = e.currentTarget.value),
+ );
+ }}
+ />
+
+ >
);
return (
@@ -1868,6 +1929,7 @@ export function Settings() {
)}
>
)}
+ {desktopProxyConfigComponent}
{!shouldHideBalanceQuery && !clientConfig?.isApp ? (
{
method: method.toUpperCase(),
url,
headers,
+ proxy_url: getDesktopProxyUrl(),
// TODO FormData
body:
typeof body === "string"
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 8a11c3b6f98..9cabbc4b702 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -38,7 +38,7 @@ tauri = { version = "1.5.4", features = [ "http-all",
] }
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
percent-encoding = "2.3.1"
-reqwest = "0.11.18"
+reqwest = { version = "0.11.18", features = ["socks"] }
futures-util = "0.3.30"
bytes = "1.7.2"
diff --git a/src-tauri/src/stream.rs b/src-tauri/src/stream.rs
index 8320db3e48a..45ea39369b0 100644
--- a/src-tauri/src/stream.rs
+++ b/src-tauri/src/stream.rs
@@ -6,7 +6,7 @@ use std::error::Error;
use std::sync::atomic::{AtomicU32, Ordering};
use std::collections::HashMap;
use futures_util::{StreamExt};
-use reqwest::Client;
+use reqwest::{Client, Proxy};
use reqwest::header::{HeaderName, HeaderMap};
static REQUEST_COUNTER: AtomicU32 = AtomicU32::new(0);
@@ -38,6 +38,7 @@ pub async fn stream_fetch(
url: String,
headers: HashMap,
body: Vec,
+ proxy_url: Option,
) -> Result {
let event_name = "stream-response";
@@ -54,10 +55,21 @@ pub async fn stream_fetch(
// println!("headers: {:?}", _headers);
let method = method.parse::().map_err(|err| format!("failed to parse method: {}", err))?;
- let client = Client::builder()
+ let mut builder = Client::builder()
.default_headers(_headers)
.redirect(reqwest::redirect::Policy::limited(3))
- .connect_timeout(Duration::new(3, 0))
+ .connect_timeout(Duration::new(3, 0));
+
+ if let Some(ref pu) = proxy_url {
+ let pu = pu.trim().to_string();
+ if !pu.is_empty() {
+ let proxy = Proxy::all(&pu)
+ .map_err(|err| format!("failed to parse proxy url: {}", err))?;
+ builder = builder.no_proxy().proxy(proxy);
+ }
+ }
+
+ let client = builder
.build()
.map_err(|err| format!("failed to generate client: {}", err))?;