新增google cloud storage上传接口

* 新增google cloud storage上传接口

---------

Merge request URL: https://g-ldyi2063.coding.net/p/dev/d/modalDeploy/git/merge/4818?initial=true
Co-authored-by: shuohigh@gmail.com
This commit is contained in:
肖宇迪 2025-06-18 19:10:43 +08:00 committed by Coding
parent 99b303c161
commit d394d822a9
4 changed files with 59 additions and 6 deletions

View File

@ -25,6 +25,7 @@ class MediaProtocol(str, Enum):
vod = "vod" vod = "vod"
cos = "cos" cos = "cos"
hls = "hls" hls = "hls"
gs = "gs"
class MediaCacheStatus(str, Enum): class MediaCacheStatus(str, Enum):

View File

@ -1,4 +1,5 @@
import uuid import uuid
from datetime import datetime
from enum import Enum from enum import Enum
from typing import List, Union, Optional, Dict, Any from typing import List, Union, Optional, Dict, Any
@ -535,3 +536,31 @@ class MakeGridGeminiRequest(BaseFFMPEGTaskRequest):
font_size: int = Field(default=18, description="文本尺寸/像素") font_size: int = Field(default=18, description="文本尺寸/像素")
padding: int = Field(default=5, description="文本距离文本框边缘距离/像素") padding: int = Field(default=5, description="文本距离文本框边缘距离/像素")
separator: int = Field(default=12, description="分割线宽度/像素") separator: int = Field(default=12, description="分割线宽度/像素")
class GoogleUploadResponse(BaseModel):
kind: str
id: str
self_link: HttpUrl = Field(alias='selfLink')
media_link: HttpUrl = Field(alias='mediaLink')
name: str
bucket: str
generation: str
metageneration: str
content_type: str = Field(alias='contentType')
storage_class: str = Field(alias='storageClass')
size: int
md5_hash: str = Field(alias='md5Hash')
crc32c: str
etag: str
time_created: datetime = Field(alias='timeCreated')
updated: datetime
time_storage_class_updated: datetime = Field(alias='timeStorageClassUpdated')
time_finalized: datetime = Field(alias='timeFinalized')
@computed_field(description="适用于Google内部服务的URN")
@property
def urn(self) -> str:
return self.id.replace(self.bucket, "gs:/")
model_config = ConfigDict(populate_by_name=True)

View File

@ -16,7 +16,7 @@ from starlette.responses import JSONResponse
from BowongModalFunctions.config import WorkerConfig from BowongModalFunctions.config import WorkerConfig
from BowongModalFunctions.middleware.authorization import verify_token from BowongModalFunctions.middleware.authorization import verify_token
from BowongModalFunctions.models.web_model import SentryTransactionInfo, GeminiResultResponse, GeminiRequest, \ from BowongModalFunctions.models.web_model import SentryTransactionInfo, GeminiResultResponse, GeminiRequest, \
ModalTaskResponse, MakeGridGeminiRequest ModalTaskResponse, MakeGridGeminiRequest, GoogleUploadResponse
from BowongModalFunctions.utils.ModalUtils import ModalUtils from BowongModalFunctions.utils.ModalUtils import ModalUtils
from BowongModalFunctions.utils.HTTPUtils import GoogleAuthUtils from BowongModalFunctions.utils.HTTPUtils import GoogleAuthUtils
@ -92,8 +92,15 @@ async def upload_file_multipart(file: UploadFile,
@router.post("/vertex-ai/upload", summary="上传文件到Vertex AI可访问的Google cloud storage", ) @router.post("/vertex-ai/upload", summary="上传文件到Vertex AI可访问的Google cloud storage", )
async def upload_file(file: UploadFile, headers: Annotated[GoogleAuthHeaders, Header()]): async def upload_file(bucket: str, file: UploadFile,
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) headers: Annotated[GoogleAuthHeaders, Header()],
prefix: Optional[str] = None) -> GoogleUploadResponse:
key = f"{prefix}/{file.filename}" if prefix else file.filename
return await GoogleAuthUtils.google_upload_file(file_stream=file.file,
content_type=file.content_type,
google_api_key=headers.auth_token,
bucket_name=bucket, filename=key)
@router.get("/status", summary="获取已上传文件的处理状态") @router.get("/status", summary="获取已上传文件的处理状态")
async def uploaded_file_status(filename: str, async def uploaded_file_status(filename: str,

View File

@ -1,4 +1,5 @@
from typing import Union, Dict, Any, BinaryIO from typing import Union, Dict, Any, BinaryIO
from urllib.parse import urlencode, quote
import backoff import backoff
import httpx import httpx
@ -9,6 +10,8 @@ from pathlib import Path
from pydantic import BaseModel from pydantic import BaseModel
from BowongModalFunctions.models.web_model import GoogleUploadResponse
class HTTPDownloadUtils: class HTTPDownloadUtils:
# 创建一个类级别的 Semaphore 来控制并发 # 创建一个类级别的 Semaphore 来控制并发
@ -127,6 +130,19 @@ class GoogleAuthUtils:
response.raise_for_status() response.raise_for_status()
return GoogleAuthUtils.GoogleAuthResponse.model_validate_json(response.text) return GoogleAuthUtils.GoogleAuthResponse.model_validate_json(response.text)
# @staticmethod @staticmethod
# async def google_upload_file(file_stream: BinaryIO, google_api_key: str, bucket_name: str): async def google_upload_file(file_stream: BinaryIO, content_type: str, google_api_key: str, bucket_name: str,
# filename: str) -> GoogleUploadResponse:
safe_filename = quote(filename)
upload_response = httpx.post(
url=f"https://storage.googleapis.com/upload/storage/v1/b/{bucket_name}/o?uploadType=media&name={safe_filename}",
content=file_stream,
headers={
"Authorization": f"Bearer {google_api_key}",
"Content-Type": content_type
})
upload_response.raise_for_status()
# upload_url = f"gs://dy-media-storage/video/{filename}"
return GoogleUploadResponse.model_validate_json(upload_response.text)