✨ Feature: Add feature: Support socks5 proxy
Browse files- README.md +1 -0
- README_CN.md +1 -0
- main.py +54 -7
- requirements.txt +1 -0
README.md
CHANGED
|
@@ -101,6 +101,7 @@ providers:
|
|
| 101 |
gemini-1.5-pro: 10 # Model gemini-1.5-pro timeout is 10 seconds
|
| 102 |
gemini-1.5-flash: 10 # Model gemini-1.5-flash timeout is 10 seconds
|
| 103 |
default: 10 # Model does not have a timeout set, use the default timeout of 10 seconds, when requesting a model not in model_timeout, the timeout is also 10 seconds, if default is not set, uni-api will use the default timeout set by the environment variable TIMEOUT, the default timeout is 100 seconds
|
|
|
|
| 104 |
|
| 105 |
- provider: vertex
|
| 106 |
project_id: gen-lang-client-xxxxxxxxxxxxxx # Description: Your Google Cloud project ID. Format: String, usually composed of lowercase letters, numbers, and hyphens. How to obtain: You can find your project ID in the project selector of the Google Cloud Console.
|
|
|
|
| 101 |
gemini-1.5-pro: 10 # Model gemini-1.5-pro timeout is 10 seconds
|
| 102 |
gemini-1.5-flash: 10 # Model gemini-1.5-flash timeout is 10 seconds
|
| 103 |
default: 10 # Model does not have a timeout set, use the default timeout of 10 seconds, when requesting a model not in model_timeout, the timeout is also 10 seconds, if default is not set, uni-api will use the default timeout set by the environment variable TIMEOUT, the default timeout is 100 seconds
|
| 104 |
+
proxy: socks5://[username]:[password]@[ip]:[port] # Proxy address, optional. Supports socks5 and http proxies, default is not used.
|
| 105 |
|
| 106 |
- provider: vertex
|
| 107 |
project_id: gen-lang-client-xxxxxxxxxxxxxx # Description: Your Google Cloud project ID. Format: String, usually composed of lowercase letters, numbers, and hyphens. How to obtain: You can find your project ID in the project selector of the Google Cloud Console.
|
README_CN.md
CHANGED
|
@@ -101,6 +101,7 @@ providers:
|
|
| 101 |
gemini-1.5-pro: 10 # 模型 gemini-1.5-pro 的超时时间为 10 秒
|
| 102 |
gemini-1.5-flash: 10 # 模型 gemini-1.5-flash 的超时时间为 10 秒
|
| 103 |
default: 10 # 模型没有设置超时时间,使用默认的超时时间 10 秒,当请求的不在 model_timeout 里面的模型时,超时时间默认是 10 秒,不设置 default,uni-api 会使用全局配置的模型超时时间。
|
|
|
|
| 104 |
|
| 105 |
- provider: vertex
|
| 106 |
project_id: gen-lang-client-xxxxxxxxxxxxxx # 描述: 您的Google Cloud项目ID。格式: 字符串,通常由小写字母、数字和连字符组成。获取方式: 在Google Cloud Console的项目选择器中可以找到您的项目ID。
|
|
|
|
| 101 |
gemini-1.5-pro: 10 # 模型 gemini-1.5-pro 的超时时间为 10 秒
|
| 102 |
gemini-1.5-flash: 10 # 模型 gemini-1.5-flash 的超时时间为 10 秒
|
| 103 |
default: 10 # 模型没有设置超时时间,使用默认的超时时间 10 秒,当请求的不在 model_timeout 里面的模型时,超时时间默认是 10 秒,不设置 default,uni-api 会使用全局配置的模型超时时间。
|
| 104 |
+
proxy: socks5://[用户名]:[密码]@[IP地址]:[端口] # 代理地址,选填。支持 socks5 和 http 代理,默认不使用代理。
|
| 105 |
|
| 106 |
- provider: vertex
|
| 107 |
project_id: gen-lang-client-xxxxxxxxxxxxxx # 描述: 您的Google Cloud项目ID。格式: 字符串,通常由小写字母、数字和连字符组成。获取方式: 在Google Cloud Console的项目选择器中可以找到您的项目ID。
|
main.py
CHANGED
|
@@ -600,7 +600,7 @@ class ClientManager:
|
|
| 600 |
self.default_config = default_config
|
| 601 |
|
| 602 |
@asynccontextmanager
|
| 603 |
-
async def get_client(self, timeout_value):
|
| 604 |
# 直接获取或创建客户端,不使用锁
|
| 605 |
timeout_value = int(timeout_value)
|
| 606 |
if timeout_value not in self.clients:
|
|
@@ -610,11 +610,42 @@ class ClientManager:
|
|
| 610 |
write=30.0,
|
| 611 |
pool=self.pool_size
|
| 612 |
)
|
| 613 |
-
|
| 614 |
-
|
| 615 |
-
|
| 616 |
-
**self.default_config
|
| 617 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 618 |
|
| 619 |
try:
|
| 620 |
yield self.clients[timeout_value]
|
|
@@ -795,8 +826,24 @@ async def process_request(request: Union[RequestModel, ImageGenerationRequest, A
|
|
| 795 |
timeout_value = app.state.timeouts.get("default", DEFAULT_TIMEOUT)
|
| 796 |
# print("timeout_value", timeout_value)
|
| 797 |
|
|
|
|
|
|
|
|
|
|
| 798 |
try:
|
| 799 |
-
async with app.state.client_manager.get_client(timeout_value) as client:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 800 |
if request.stream:
|
| 801 |
generator = fetch_response_stream(client, url, headers, payload, engine, original_model)
|
| 802 |
wrapped_generator, first_response_time = await error_handling_wrapper(generator, channel_id)
|
|
|
|
| 600 |
self.default_config = default_config
|
| 601 |
|
| 602 |
@asynccontextmanager
|
| 603 |
+
async def get_client(self, timeout_value, proxy=None):
|
| 604 |
# 直接获取或创建客户端,不使用锁
|
| 605 |
timeout_value = int(timeout_value)
|
| 606 |
if timeout_value not in self.clients:
|
|
|
|
| 610 |
write=30.0,
|
| 611 |
pool=self.pool_size
|
| 612 |
)
|
| 613 |
+
limits = httpx.Limits(max_connections=self.pool_size)
|
| 614 |
+
|
| 615 |
+
client_config = {
|
| 616 |
+
**self.default_config,
|
| 617 |
+
"timeout": timeout,
|
| 618 |
+
"limits": limits
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
if proxy:
|
| 622 |
+
# 解析代理URL
|
| 623 |
+
from urllib.parse import urlparse
|
| 624 |
+
parsed = urlparse(proxy)
|
| 625 |
+
|
| 626 |
+
# 修改这里: 将 socks5h 转换为 socks5
|
| 627 |
+
scheme = parsed.scheme.rstrip('h')
|
| 628 |
+
# print("scheme", scheme)
|
| 629 |
+
|
| 630 |
+
if scheme == 'socks5':
|
| 631 |
+
try:
|
| 632 |
+
from httpx_socks import AsyncProxyTransport
|
| 633 |
+
# 使用修改后的scheme创建代理URL
|
| 634 |
+
proxy = proxy.replace('socks5h://', 'socks5://')
|
| 635 |
+
# 创建SOCKS5代理传输
|
| 636 |
+
transport = AsyncProxyTransport.from_url(proxy)
|
| 637 |
+
client_config["transport"] = transport
|
| 638 |
+
except ImportError:
|
| 639 |
+
logger.error("httpx-socks package is required for SOCKS proxy support")
|
| 640 |
+
raise ImportError("Please install httpx-socks package for SOCKS proxy support: pip install httpx-socks")
|
| 641 |
+
else:
|
| 642 |
+
# 对于HTTP/HTTPS代理使用原有方式
|
| 643 |
+
client_config["proxies"] = {
|
| 644 |
+
"http://": proxy,
|
| 645 |
+
"https://": proxy
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
self.clients[timeout_value] = httpx.AsyncClient(**client_config)
|
| 649 |
|
| 650 |
try:
|
| 651 |
yield self.clients[timeout_value]
|
|
|
|
| 826 |
timeout_value = app.state.timeouts.get("default", DEFAULT_TIMEOUT)
|
| 827 |
# print("timeout_value", timeout_value)
|
| 828 |
|
| 829 |
+
proxy = safe_get(provider, "preferences", "proxy", default=None)
|
| 830 |
+
# print("proxy", proxy)
|
| 831 |
+
|
| 832 |
try:
|
| 833 |
+
async with app.state.client_manager.get_client(timeout_value, proxy) as client:
|
| 834 |
+
# 打印client配置信息
|
| 835 |
+
# logger.info(f"Client config - Timeout: {client.timeout}")
|
| 836 |
+
# logger.info(f"Client config - Headers: {client.headers}")
|
| 837 |
+
# if hasattr(client, '_transport'):
|
| 838 |
+
# if hasattr(client._transport, 'proxy_url'):
|
| 839 |
+
# logger.info(f"Client config - Proxy: {client._transport.proxy_url}")
|
| 840 |
+
# elif hasattr(client._transport, 'proxies'):
|
| 841 |
+
# logger.info(f"Client config - Proxies: {client._transport.proxies}")
|
| 842 |
+
# else:
|
| 843 |
+
# logger.info("Client config - No proxy configured")
|
| 844 |
+
# else:
|
| 845 |
+
# logger.info("Client config - No transport configured")
|
| 846 |
+
# logger.info(f"Client config - Follow Redirects: {client.follow_redirects}")
|
| 847 |
if request.stream:
|
| 848 |
generator = fetch_response_stream(client, url, headers, payload, engine, original_model)
|
| 849 |
wrapped_generator, first_response_time = await error_handling_wrapper(generator, channel_id)
|
requirements.txt
CHANGED
|
@@ -9,5 +9,6 @@ sqlalchemy
|
|
| 9 |
watchfiles
|
| 10 |
ruamel.yaml
|
| 11 |
httpx[http2]
|
|
|
|
| 12 |
cryptography
|
| 13 |
python-multipart
|
|
|
|
| 9 |
watchfiles
|
| 10 |
ruamel.yaml
|
| 11 |
httpx[http2]
|
| 12 |
+
httpx-socks
|
| 13 |
cryptography
|
| 14 |
python-multipart
|