添加Google file upload api
* 添加Google file upload api * WIP : 增加Gemini 上传接口 --------- Merge request URL: https://g-ldyi2063.coding.net/p/dev/d/modalDeploy/git/merge/4741 Co-authored-by: shuohigh@gmail.com
This commit is contained in:
parent
225a003d45
commit
dc7b140c2d
|
|
@ -1,4 +1,4 @@
|
||||||
MODAL_ENVIRONMENT=test
|
MODAL_ENVIRONMENT=dev
|
||||||
modal_app_name=bowong-ai-video
|
modal_app_name=bowong-ai-video
|
||||||
S3_mount_dir=/mntS3
|
S3_mount_dir=/mntS3
|
||||||
S3_bucket_name=modal-media-cache
|
S3_bucket_name=modal-media-cache
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from sentry_sdk.integrations.loguru import LoguruIntegration, LoggingLevels
|
||||||
from sentry_sdk.integrations.fastapi import FastApiIntegration
|
from sentry_sdk.integrations.fastapi import FastApiIntegration
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from .utils.KVCache import KVCache
|
from .utils.KVCache import KVCache
|
||||||
from .router import ffmpeg, cache, comfyui
|
from .router import ffmpeg, cache, comfyui, google
|
||||||
from .config import WorkerConfig
|
from .config import WorkerConfig
|
||||||
|
|
||||||
config = WorkerConfig()
|
config = WorkerConfig()
|
||||||
|
|
@ -82,3 +82,4 @@ async def scalar():
|
||||||
web_app.include_router(ffmpeg.router)
|
web_app.include_router(ffmpeg.router)
|
||||||
web_app.include_router(cache.router)
|
web_app.include_router(cache.router)
|
||||||
web_app.include_router(comfyui.router)
|
web_app.include_router(comfyui.router)
|
||||||
|
web_app.include_router(google.router)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
import os
|
||||||
|
from typing import Annotated, Optional
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
import httpx
|
||||||
|
from fastapi import APIRouter, UploadFile, Header, HTTPException
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from starlette import status
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
|
from BowongModalFunctions.config import WorkerConfig
|
||||||
|
|
||||||
|
config = WorkerConfig
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/google", tags=["google"])
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleAPIKeyHeaders(BaseModel):
|
||||||
|
x_google_api_key: Optional[str] = Field(description="Google API Key", default=None)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/upload",
|
||||||
|
summary="上传文件到Google File",
|
||||||
|
description="上传文件到Google File, 换取Google File URI, 不同Google API Key之间的URI不互通, 最多可为每个项目存储 20 GB 的文件,每个文件的大小上限为 2 GB。文件会存储 48 小时")
|
||||||
|
async def upload_file_multipart(file: UploadFile,
|
||||||
|
headers: Annotated[GoogleAPIKeyHeaders, Header()]):
|
||||||
|
google_api_key = headers.x_google_api_key or os.environ.get("GOOGLE_API_KEY")
|
||||||
|
if not google_api_key:
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing Google API Key")
|
||||||
|
content_length = file.size
|
||||||
|
content_type = file.content_type
|
||||||
|
if content_type not in ['video/mp4', 'video/mpeg', 'video/mov', 'video/avi', 'video/x-flv', 'video/mpg',
|
||||||
|
'video/webm', 'video/wmv', 'video/3gpp']:
|
||||||
|
raise HTTPException(status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
|
||||||
|
logger.info(f"Uploading name = {file.filename}, size = {content_length}, type = {content_type} to google file")
|
||||||
|
with httpx.Client() as client:
|
||||||
|
pre_upload_response = client.post(
|
||||||
|
url=f"https://generativelanguage.googleapis.com/upload/v1beta/files?key={google_api_key}",
|
||||||
|
headers={
|
||||||
|
"X-Goog-Upload-Protocol": "resumable",
|
||||||
|
"X-Goog-Upload-Command": "start",
|
||||||
|
"X-Goog-Upload-Header-Content-Length": str(content_length),
|
||||||
|
"X-Goog-Upload-Header-Content-Type": content_type
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
"file": {
|
||||||
|
"display_name": file.filename.split(".")[0],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
pre_upload_response.raise_for_status()
|
||||||
|
|
||||||
|
upload_url = pre_upload_response.headers.get("X-Goog-Upload-Url")
|
||||||
|
|
||||||
|
upload_response = client.post(url=upload_url, content=file.file.read(), headers={
|
||||||
|
"X-Goog-Upload-Offset": "0",
|
||||||
|
"X-Goog-Upload-Command": "upload, finalize",
|
||||||
|
"Content-Type": content_type
|
||||||
|
})
|
||||||
|
upload_response.raise_for_status()
|
||||||
|
|
||||||
|
return JSONResponse(content=upload_response.json(), status_code=upload_response.status_code)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/status", summary="获取已上传文件的处理状态")
|
||||||
|
async def uploaded_file_status(filename: str,
|
||||||
|
headers: Annotated[GoogleAPIKeyHeaders, Header()]):
|
||||||
|
google_api_key = headers.x_google_api_key or os.environ.get("GOOGLE_API_KEY")
|
||||||
|
if not google_api_key:
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing Google API Key")
|
||||||
|
with httpx.Client() as client:
|
||||||
|
response = client.get(
|
||||||
|
url=f"https://generativelanguage.googleapis.com/v1beta/files/{filename}?key={google_api_key}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return JSONResponse(content=response.json(), status_code=response.status_code)
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete('/delete', summary="删除已上传的文件")
|
||||||
|
async def delete_file(filename: str, headers: Annotated[GoogleAPIKeyHeaders, Header()]):
|
||||||
|
google_api_key = headers.x_google_api_key or os.environ.get("GOOGLE_API_KEY")
|
||||||
|
if not google_api_key:
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing Google API Key")
|
||||||
|
with httpx.Client() as client:
|
||||||
|
response = client.delete(
|
||||||
|
url=f"https://generativelanguage.googleapis.com/v1beta/files/{filename}?key={google_api_key}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return JSONResponse(content=response.json(), status_code=response.status_code)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/list', summary="列出已上传的文件")
|
||||||
|
async def list_files(headers: Annotated[GoogleAPIKeyHeaders, Header()]):
|
||||||
|
google_api_key = headers.x_google_api_key or os.environ.get("GOOGLE_API_KEY")
|
||||||
|
if not google_api_key:
|
||||||
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing Google API Key")
|
||||||
|
with httpx.Client() as client:
|
||||||
|
response = client.get(
|
||||||
|
url=f"https://generativelanguage.googleapis.com/v1beta/files?key={google_api_key}")
|
||||||
|
response.raise_for_status()
|
||||||
|
return JSONResponse(content=response.json(), status_code=response.status_code)
|
||||||
|
|
@ -13,6 +13,9 @@ fastapi_image = (
|
||||||
app = modal.App(
|
app = modal.App(
|
||||||
name="web_app",
|
name="web_app",
|
||||||
image=fastapi_image,
|
image=fastapi_image,
|
||||||
|
secrets=[
|
||||||
|
modal.Secret.from_name('google-secret')
|
||||||
|
],
|
||||||
include_source=False)
|
include_source=False)
|
||||||
|
|
||||||
with fastapi_image.imports():
|
with fastapi_image.imports():
|
||||||
|
|
@ -21,6 +24,7 @@ with fastapi_image.imports():
|
||||||
|
|
||||||
config = WorkerConfig()
|
config = WorkerConfig()
|
||||||
|
|
||||||
|
|
||||||
@app.function(scaledown_window=60,
|
@app.function(scaledown_window=60,
|
||||||
secrets=[
|
secrets=[
|
||||||
modal.Secret.from_name("cf-kv-secret", environment_name='dev'),
|
modal.Secret.from_name("cf-kv-secret", environment_name='dev'),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue