mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-06 16:16:37 +08:00
Merge pull request #360 from minguncle:feat-support-aliyunoss
Feat support aliyunoss
This commit is contained in:
@@ -48,6 +48,13 @@ PICGO_API_URL=https://www.picgo.net/api/1/upload
|
|||||||
CLOUDFLARE_IMGBED_URL=https://xxxxxxx.pages.dev/upload
|
CLOUDFLARE_IMGBED_URL=https://xxxxxxx.pages.dev/upload
|
||||||
CLOUDFLARE_IMGBED_AUTH_CODE=xxxxxxxxx
|
CLOUDFLARE_IMGBED_AUTH_CODE=xxxxxxxxx
|
||||||
CLOUDFLARE_IMGBED_UPLOAD_FOLDER=
|
CLOUDFLARE_IMGBED_UPLOAD_FOLDER=
|
||||||
|
# 阿里云OSS配置
|
||||||
|
OSS_ENDPOINT=oss-cn-shanghai.aliyuncs.com
|
||||||
|
OSS_ENDPOINT_INNER=oss-cn-shanghai-internal.aliyuncs.com
|
||||||
|
OSS_ACCESS_KEY=LTAI5txxxxxxxxxxxxxxxx
|
||||||
|
OSS_ACCESS_KEY_SECRET=yXxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
OSS_BUCKET_NAME=your-bucket-name
|
||||||
|
OSS_REGION=cn-shanghai
|
||||||
##########################################################################
|
##########################################################################
|
||||||
#########################stream_optimizer 相关配置########################
|
#########################stream_optimizer 相关配置########################
|
||||||
STREAM_OPTIMIZER_ENABLED=false
|
STREAM_OPTIMIZER_ENABLED=false
|
||||||
|
|||||||
@@ -98,6 +98,13 @@ class Settings(BaseSettings):
|
|||||||
CLOUDFLARE_IMGBED_URL: str = ""
|
CLOUDFLARE_IMGBED_URL: str = ""
|
||||||
CLOUDFLARE_IMGBED_AUTH_CODE: str = ""
|
CLOUDFLARE_IMGBED_AUTH_CODE: str = ""
|
||||||
CLOUDFLARE_IMGBED_UPLOAD_FOLDER: str = ""
|
CLOUDFLARE_IMGBED_UPLOAD_FOLDER: str = ""
|
||||||
|
# 阿里云OSS配置
|
||||||
|
OSS_ENDPOINT: str = ""
|
||||||
|
OSS_ENDPOINT_INNER: str = ""
|
||||||
|
OSS_ACCESS_KEY: str = ""
|
||||||
|
OSS_ACCESS_KEY_SECRET: str = ""
|
||||||
|
OSS_BUCKET_NAME: str = ""
|
||||||
|
OSS_REGION: str = ""
|
||||||
|
|
||||||
# 流式输出优化器配置
|
# 流式输出优化器配置
|
||||||
STREAM_OPTIMIZER_ENABLED: bool = False
|
STREAM_OPTIMIZER_ENABLED: bool = False
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ DEFAULT_CREATE_IMAGE_MODEL = "imagen-3.0-generate-002"
|
|||||||
VALID_IMAGE_RATIOS = ["1:1", "3:4", "4:3", "9:16", "16:9"]
|
VALID_IMAGE_RATIOS = ["1:1", "3:4", "4:3", "9:16", "16:9"]
|
||||||
|
|
||||||
# 上传提供商
|
# 上传提供商
|
||||||
UPLOAD_PROVIDERS = ["smms", "picgo", "cloudflare_imgbed"]
|
UPLOAD_PROVIDERS = ["smms", "picgo", "cloudflare_imgbed", "aliyun_oss"]
|
||||||
DEFAULT_UPLOAD_PROVIDER = "smms"
|
DEFAULT_UPLOAD_PROVIDER = "smms"
|
||||||
|
|
||||||
# 流式输出相关常量
|
# 流式输出相关常量
|
||||||
|
|||||||
@@ -304,6 +304,16 @@ def _extract_image_data(part: dict) -> str:
|
|||||||
auth_code=settings.CLOUDFLARE_IMGBED_AUTH_CODE,
|
auth_code=settings.CLOUDFLARE_IMGBED_AUTH_CODE,
|
||||||
upload_folder=settings.CLOUDFLARE_IMGBED_UPLOAD_FOLDER,
|
upload_folder=settings.CLOUDFLARE_IMGBED_UPLOAD_FOLDER,
|
||||||
)
|
)
|
||||||
|
elif settings.UPLOAD_PROVIDER == "aliyun_oss":
|
||||||
|
image_uploader = ImageUploaderFactory.create(
|
||||||
|
provider=settings.UPLOAD_PROVIDER,
|
||||||
|
access_key=settings.OSS_ACCESS_KEY,
|
||||||
|
access_key_secret=settings.OSS_ACCESS_KEY_SECRET,
|
||||||
|
bucket_name=settings.OSS_BUCKET_NAME,
|
||||||
|
endpoint=settings.OSS_ENDPOINT,
|
||||||
|
region=settings.OSS_REGION,
|
||||||
|
use_internal=False
|
||||||
|
)
|
||||||
current_date = time.strftime("%Y/%m/%d")
|
current_date = time.strftime("%Y/%m/%d")
|
||||||
filename = f"{current_date}/{uuid.uuid4().hex[:8]}.png"
|
filename = f"{current_date}/{uuid.uuid4().hex[:8]}.png"
|
||||||
base64_data = part["inlineData"]["data"]
|
base64_data = part["inlineData"]["data"]
|
||||||
|
|||||||
@@ -131,6 +131,16 @@ class ImageCreateService:
|
|||||||
auth_code=settings.CLOUDFLARE_IMGBED_AUTH_CODE,
|
auth_code=settings.CLOUDFLARE_IMGBED_AUTH_CODE,
|
||||||
upload_folder=settings.CLOUDFLARE_IMGBED_UPLOAD_FOLDER,
|
upload_folder=settings.CLOUDFLARE_IMGBED_UPLOAD_FOLDER,
|
||||||
)
|
)
|
||||||
|
elif settings.UPLOAD_PROVIDER == "aliyun_oss":
|
||||||
|
image_uploader = ImageUploaderFactory.create(
|
||||||
|
provider=settings.UPLOAD_PROVIDER,
|
||||||
|
access_key=settings.OSS_ACCESS_KEY,
|
||||||
|
access_key_secret=settings.OSS_ACCESS_KEY_SECRET,
|
||||||
|
bucket_name=settings.OSS_BUCKET_NAME,
|
||||||
|
endpoint=settings.OSS_ENDPOINT,
|
||||||
|
region=settings.OSS_REGION,
|
||||||
|
use_internal=False
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Unsupported upload provider: {settings.UPLOAD_PROVIDER}"
|
f"Unsupported upload provider: {settings.UPLOAD_PROVIDER}"
|
||||||
|
|||||||
@@ -1814,6 +1814,7 @@ endblock %} {% block head_extra_styles %}
|
|||||||
<option value="smms" selected>SM.MS</option>
|
<option value="smms" selected>SM.MS</option>
|
||||||
<option value="picgo">PicGo</option>
|
<option value="picgo">PicGo</option>
|
||||||
<option value="cloudflare_imgbed">Cloudflare</option>
|
<option value="cloudflare_imgbed">Cloudflare</option>
|
||||||
|
<option value="aliyun_oss">阿里云OSS</option>
|
||||||
</select>
|
</select>
|
||||||
<small class="text-gray-500 mt-1 block">图片上传服务提供商</small>
|
<small class="text-gray-500 mt-1 block">图片上传服务提供商</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -1921,6 +1922,109 @@ endblock %} {% block head_extra_styles %}
|
|||||||
>Cloudflare图床的上传文件夹路径(可选)</small
|
>Cloudflare图床的上传文件夹路径(可选)</small
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 阿里云OSS配置 -->
|
||||||
|
<!-- OSS Endpoint -->
|
||||||
|
<div class="mb-6 provider-config" data-provider="aliyun_oss">
|
||||||
|
<label
|
||||||
|
for="OSS_ENDPOINT"
|
||||||
|
class="block font-semibold mb-2 text-gray-700"
|
||||||
|
>OSS Endpoint</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="OSS_ENDPOINT"
|
||||||
|
name="OSS_ENDPOINT"
|
||||||
|
placeholder="oss-cn-shanghai.aliyuncs.com"
|
||||||
|
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||||||
|
/>
|
||||||
|
<small class="text-gray-500 mt-1 block">阿里云OSS的Endpoint地址</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- OSS Access Key -->
|
||||||
|
<div class="mb-6 provider-config" data-provider="aliyun_oss">
|
||||||
|
<label
|
||||||
|
for="OSS_ACCESS_KEY"
|
||||||
|
class="block font-semibold mb-2 text-gray-700"
|
||||||
|
>OSS Access Key</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="OSS_ACCESS_KEY"
|
||||||
|
name="OSS_ACCESS_KEY"
|
||||||
|
placeholder="LTAI5txxxxxxxxxx"
|
||||||
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed"
|
||||||
|
/>
|
||||||
|
<small class="text-gray-500 mt-1 block">阿里云OSS的Access Key ID</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- OSS Access Key Secret -->
|
||||||
|
<div class="mb-6 provider-config" data-provider="aliyun_oss">
|
||||||
|
<label
|
||||||
|
for="OSS_ACCESS_KEY_SECRET"
|
||||||
|
class="block font-semibold mb-2 text-gray-700"
|
||||||
|
>OSS Access Key Secret</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="OSS_ACCESS_KEY_SECRET"
|
||||||
|
name="OSS_ACCESS_KEY_SECRET"
|
||||||
|
placeholder="yXxxxxxxxxxxxx"
|
||||||
|
class="w-full px-4 py-3 rounded-lg sensitive-input form-input-themed"
|
||||||
|
/>
|
||||||
|
<small class="text-gray-500 mt-1 block">阿里云OSS的Access Key Secret</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- OSS Bucket Name -->
|
||||||
|
<div class="mb-6 provider-config" data-provider="aliyun_oss">
|
||||||
|
<label
|
||||||
|
for="OSS_BUCKET_NAME"
|
||||||
|
class="block font-semibold mb-2 text-gray-700"
|
||||||
|
>OSS Bucket名称</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="OSS_BUCKET_NAME"
|
||||||
|
name="OSS_BUCKET_NAME"
|
||||||
|
placeholder="your-bucket-name"
|
||||||
|
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||||||
|
/>
|
||||||
|
<small class="text-gray-500 mt-1 block">阿里云OSS的Bucket名称</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- OSS Region -->
|
||||||
|
<div class="mb-6 provider-config" data-provider="aliyun_oss">
|
||||||
|
<label
|
||||||
|
for="OSS_REGION"
|
||||||
|
class="block font-semibold mb-2 text-gray-700"
|
||||||
|
>OSS Region</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="OSS_REGION"
|
||||||
|
name="OSS_REGION"
|
||||||
|
placeholder="cn-shanghai"
|
||||||
|
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||||||
|
/>
|
||||||
|
<small class="text-gray-500 mt-1 block">阿里云OSS的Region区域</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- OSS Internal Endpoint (可选) -->
|
||||||
|
<div class="mb-6 provider-config" data-provider="aliyun_oss">
|
||||||
|
<label
|
||||||
|
for="OSS_ENDPOINT_INNER"
|
||||||
|
class="block font-semibold mb-2 text-gray-700"
|
||||||
|
>OSS内网Endpoint(可选)</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="OSS_ENDPOINT_INNER"
|
||||||
|
name="OSS_ENDPOINT_INNER"
|
||||||
|
placeholder="oss-cn-shanghai-internal.aliyuncs.com"
|
||||||
|
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||||||
|
/>
|
||||||
|
<small class="text-gray-500 mt-1 block">阿里云OSS的内网Endpoint地址(可选)</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 流式输出优化配置 -->
|
<!-- 流式输出优化配置 -->
|
||||||
|
|||||||
@@ -211,6 +211,16 @@ def is_image_upload_configured(settings: Settings) -> bool:
|
|||||||
return bool(getattr(settings, "SMMS_SECRET_TOKEN", ""))
|
return bool(getattr(settings, "SMMS_SECRET_TOKEN", ""))
|
||||||
if provider == "picgo":
|
if provider == "picgo":
|
||||||
return bool(getattr(settings, "PICGO_API_KEY", ""))
|
return bool(getattr(settings, "PICGO_API_KEY", ""))
|
||||||
|
if provider == "aliyun_oss":
|
||||||
|
return all(
|
||||||
|
[
|
||||||
|
getattr(settings, "OSS_ACCESS_KEY", ""),
|
||||||
|
getattr(settings, "OSS_ACCESS_KEY_SECRET", ""),
|
||||||
|
getattr(settings, "OSS_BUCKET_NAME", ""),
|
||||||
|
getattr(settings, "OSS_ENDPOINT", ""),
|
||||||
|
getattr(settings, "OSS_REGION", "")
|
||||||
|
]
|
||||||
|
)
|
||||||
if provider == "cloudflare_imgbed":
|
if provider == "cloudflare_imgbed":
|
||||||
return all(
|
return all(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ import requests
|
|||||||
from app.domain.image_models import ImageMetadata, ImageUploader, UploadResponse
|
from app.domain.image_models import ImageMetadata, ImageUploader, UploadResponse
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional, Any
|
from typing import Optional, Any
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
import hmac
|
||||||
|
from datetime import datetime
|
||||||
|
from urllib.parse import quote
|
||||||
|
from app.log.logger import get_image_create_logger
|
||||||
|
|
||||||
class UploadErrorType(Enum):
|
class UploadErrorType(Enum):
|
||||||
"""上传错误类型枚举"""
|
"""上传错误类型枚举"""
|
||||||
@@ -300,6 +306,191 @@ class PicGoUploader(ImageUploader):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AliyunOSSUploader(ImageUploader):
|
||||||
|
"""阿里云OSS图片上传器"""
|
||||||
|
|
||||||
|
def __init__(self, access_key: str, access_key_secret: str, bucket_name: str,
|
||||||
|
endpoint: str, region: str, use_internal: bool = False):
|
||||||
|
"""
|
||||||
|
初始化阿里云OSS上传器
|
||||||
|
|
||||||
|
Args:
|
||||||
|
access_key: OSS访问密钥ID
|
||||||
|
access_key_secret: OSS访问密钥
|
||||||
|
bucket_name: OSS存储桶名称
|
||||||
|
endpoint: OSS端点地址
|
||||||
|
region: OSS区域
|
||||||
|
use_internal: 是否使用内网端点
|
||||||
|
"""
|
||||||
|
self.access_key = access_key
|
||||||
|
self.access_key_secret = access_key_secret
|
||||||
|
self.bucket_name = bucket_name
|
||||||
|
self.endpoint = endpoint
|
||||||
|
self.region = region
|
||||||
|
self.use_internal = use_internal
|
||||||
|
self.logger = get_image_create_logger()
|
||||||
|
|
||||||
|
# 构建请求URL
|
||||||
|
if not endpoint.startswith(('http://', 'https://')):
|
||||||
|
self.base_url = f"https://{bucket_name}.{endpoint}"
|
||||||
|
else:
|
||||||
|
self.base_url = f"{endpoint}/{bucket_name}"
|
||||||
|
|
||||||
|
self.logger.info(f"Initialized AliyunOSSUploader for bucket: {bucket_name}, region: {region}")
|
||||||
|
|
||||||
|
def _sign_request(self, method: str, path: str, headers: dict, content: bytes = b'') -> dict:
|
||||||
|
"""
|
||||||
|
为OSS请求生成签名
|
||||||
|
|
||||||
|
Args:
|
||||||
|
method: HTTP方法
|
||||||
|
path: 请求路径
|
||||||
|
headers: 请求头
|
||||||
|
content: 请求内容
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含签名的请求头
|
||||||
|
"""
|
||||||
|
# 计算Content-MD5
|
||||||
|
content_md5 = base64.b64encode(hashlib.md5(content).digest()).decode('utf-8') if content else ''
|
||||||
|
|
||||||
|
# 设置日期
|
||||||
|
date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
|
|
||||||
|
# 更新headers
|
||||||
|
headers['Date'] = date
|
||||||
|
if content_md5:
|
||||||
|
headers['Content-MD5'] = content_md5
|
||||||
|
headers['Content-Type'] = headers.get('Content-Type', 'image/png')
|
||||||
|
|
||||||
|
# 构建CanonicalizedOSSHeaders
|
||||||
|
oss_headers = []
|
||||||
|
for key, value in sorted(headers.items()):
|
||||||
|
if key.lower().startswith('x-oss-'):
|
||||||
|
oss_headers.append(f"{key.lower()}:{value}")
|
||||||
|
canonicalized_oss_headers = '\n'.join(oss_headers)
|
||||||
|
if canonicalized_oss_headers:
|
||||||
|
canonicalized_oss_headers += '\n'
|
||||||
|
|
||||||
|
# 构建CanonicalizedResource
|
||||||
|
canonicalized_resource = f"/{self.bucket_name}{path}"
|
||||||
|
|
||||||
|
# 构建StringToSign
|
||||||
|
string_to_sign = f"{method}\n{content_md5}\n{headers.get('Content-Type', '')}\n{date}\n{canonicalized_oss_headers}{canonicalized_resource}"
|
||||||
|
|
||||||
|
# 计算签名
|
||||||
|
signature = base64.b64encode(
|
||||||
|
hmac.new(
|
||||||
|
self.access_key_secret.encode('utf-8'),
|
||||||
|
string_to_sign.encode('utf-8'),
|
||||||
|
hashlib.sha1
|
||||||
|
).digest()
|
||||||
|
).decode('utf-8')
|
||||||
|
|
||||||
|
# 添加Authorization头
|
||||||
|
headers['Authorization'] = f"OSS {self.access_key}:{signature}"
|
||||||
|
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def upload(self, file: bytes, filename: str) -> UploadResponse:
|
||||||
|
"""
|
||||||
|
上传图片到阿里云OSS
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file: 图片文件二进制数据
|
||||||
|
filename: 文件名(将作为OSS对象的key)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
UploadResponse: 上传响应对象
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
UploadError: 上传失败时抛出异常
|
||||||
|
"""
|
||||||
|
# 记录开始上传的日志
|
||||||
|
self.logger.info(f"Starting OSS upload for file: {filename}, size: {len(file)} bytes")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 构建对象路径
|
||||||
|
object_key = f"/{filename}"
|
||||||
|
|
||||||
|
# 准备请求头
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'image/png',
|
||||||
|
'x-oss-object-acl': 'public-read' # 设置为公共读
|
||||||
|
}
|
||||||
|
|
||||||
|
# 签名请求
|
||||||
|
signed_headers = self._sign_request('PUT', object_key, headers, file)
|
||||||
|
|
||||||
|
# 构建完整URL
|
||||||
|
upload_url = f"{self.base_url}{object_key}"
|
||||||
|
self.logger.debug(f"OSS upload URL: {upload_url}")
|
||||||
|
|
||||||
|
# 发送请求
|
||||||
|
response = requests.put(
|
||||||
|
upload_url,
|
||||||
|
data=file,
|
||||||
|
headers=signed_headers
|
||||||
|
)
|
||||||
|
|
||||||
|
# 检查响应状态
|
||||||
|
if response.status_code != 200:
|
||||||
|
error_msg = f"OSS upload failed with status {response.status_code}, response: {response.text}"
|
||||||
|
self.logger.error(f"OSS upload failed for {filename}: {error_msg}")
|
||||||
|
raise UploadError(
|
||||||
|
message=f"OSS upload failed with status {response.status_code}",
|
||||||
|
error_type=UploadErrorType.SERVER_ERROR,
|
||||||
|
status_code=response.status_code,
|
||||||
|
details={'response': response.text}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 构建访问URL
|
||||||
|
if self.endpoint.startswith(('http://', 'https://')):
|
||||||
|
access_url = f"{self.endpoint}/{self.bucket_name}{object_key}"
|
||||||
|
else:
|
||||||
|
access_url = f"https://{self.bucket_name}.{self.endpoint}{object_key}"
|
||||||
|
|
||||||
|
# 构建图片元数据
|
||||||
|
image_metadata = ImageMetadata(
|
||||||
|
width=0, # OSS PUT不返回图片尺寸
|
||||||
|
height=0,
|
||||||
|
filename=filename,
|
||||||
|
size=len(file),
|
||||||
|
url=access_url,
|
||||||
|
delete_url=None # OSS需要单独的删除操作
|
||||||
|
)
|
||||||
|
|
||||||
|
# 记录上传成功的日志
|
||||||
|
self.logger.info(f"OSS upload successful for {filename}, URL: {access_url}")
|
||||||
|
|
||||||
|
return UploadResponse(
|
||||||
|
success=True,
|
||||||
|
code="success",
|
||||||
|
message="Upload to Aliyun OSS success",
|
||||||
|
data=image_metadata
|
||||||
|
)
|
||||||
|
|
||||||
|
except requests.RequestException as e:
|
||||||
|
error_msg = f"OSS upload request failed: {str(e)}"
|
||||||
|
self.logger.error(f"OSS upload request failed for {filename}: {error_msg}")
|
||||||
|
raise UploadError(
|
||||||
|
message=error_msg,
|
||||||
|
error_type=UploadErrorType.NETWORK_ERROR,
|
||||||
|
original_error=e
|
||||||
|
)
|
||||||
|
except UploadError:
|
||||||
|
# UploadError 已经被记录了,直接重新抛出
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"OSS upload failed: {str(e)}"
|
||||||
|
self.logger.error(f"OSS upload unexpected error for {filename}: {error_msg}")
|
||||||
|
raise UploadError(
|
||||||
|
message=error_msg,
|
||||||
|
error_type=UploadErrorType.UNKNOWN,
|
||||||
|
original_error=e
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CloudFlareImgBedUploader(ImageUploader):
|
class CloudFlareImgBedUploader(ImageUploader):
|
||||||
"""CloudFlare图床上传器"""
|
"""CloudFlare图床上传器"""
|
||||||
|
|
||||||
@@ -438,4 +629,13 @@ class ImageUploaderFactory:
|
|||||||
credentials["base_url"],
|
credentials["base_url"],
|
||||||
credentials.get("upload_folder", ""),
|
credentials.get("upload_folder", ""),
|
||||||
)
|
)
|
||||||
|
elif provider == "aliyun_oss":
|
||||||
|
return AliyunOSSUploader(
|
||||||
|
credentials["access_key"],
|
||||||
|
credentials["access_key_secret"],
|
||||||
|
credentials["bucket_name"],
|
||||||
|
credentials["endpoint"],
|
||||||
|
credentials["region"],
|
||||||
|
credentials.get("use_internal", False)
|
||||||
|
)
|
||||||
raise ValueError(f"Unknown provider: {provider}")
|
raise ValueError(f"Unknown provider: {provider}")
|
||||||
|
|||||||
Reference in New Issue
Block a user