Hi ! currently getting a ConnectTimeout error when using the async client with files SDK. Only started appearing 5 days ago. No code changes have happened before the error started appearing. Adding in a simple reproduction.
Environment details
- Programming language: Python
- OS: Ubuntu
- Language runtime version: Python3.9
- Package version: google-genai==1.4.0
Steps to reproduce
- Upload a PDF file to the /upload endpoint.
- Call /generate with URIs retrieved from /upload endpoint
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import JSONResponse, StreamingResponse
from sse_starlette.sse import ServerSentEvent, EventSourceResponse
from typing import List, AsyncGenerator
import os
import tempfile
import shutil
from pathlib import Path
from google import genai
from google.genai import types
from pydantic import BaseModel
import asyncio
import time
import json
app = FastAPI()
# Configure Gemini clients
client = genai.Client(api_key="your_key")
class FileURI(BaseModel):
uri: str
mime_type: str
class ContentRequest(BaseModel):
uris: List[FileURI]
user_input: str
async def upload_single_file(file: UploadFile, chat_id: str) -> types.File:
# Create a temporary directory structure matching S3 path
temp_dir = tempfile.mkdtemp()
temp_path = os.path.join(temp_dir, "files", chat_id)
os.makedirs(temp_path, exist_ok=True)
file_path = os.path.join(temp_path, file.filename)
try:
# Save the file temporarily
with open(file_path, 'wb') as f:
content = await file.read()
f.write(content)
await file.seek(0)
result = client.files.upload(
file=file_path,
config=types.UploadFileConfig(
display_name=file.filename,
mime_type=file.content_type
)
)
return result
finally:
# Clean up temporary directory
shutil.rmtree(temp_dir)
@app.post("/upload/")
async def upload_files(files: List[UploadFile] = File(...)):
"""
Upload multiple files to Gemini and return their URIs
"""
try:
uris = []
# Generate a unique chat ID for this batch of uploads
chat_id = str(hash(str(files) + str(time.time())))
for file in files:
uploaded_file = await upload_single_file(file, chat_id)
uris.append({
"uri": uploaded_file.uri,
"mime_type": uploaded_file.mime_type
})
return JSONResponse(
content={"uris": uris},
status_code=200
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
async def generate_content_stream(request: ContentRequest) -> AsyncGenerator[ServerSentEvent, None]:
"""
Generator function that streams response chunks from Gemini
"""
try:
file_parts = []
for uri in request.uris:
file_parts.append(
types.Part.from_uri(
file_uri=uri.uri,
mime_type=uri.mime_type
)
)
# Prepare the content list with user input and files
contents = [
types.Content(
parts=[
# go through URIs and add them to the content
*file_parts,
types.Part(
text=request.user_input
)
]
)
]
# Get the stream iterator from the async client
response_iterator = await client.aio.models.generate_content_stream(
model='gemini-2.0-flash',
contents=contents
)
# Now iterate through the stream
async for chunk in response_iterator:
if chunk.text:
print(chunk.text)
yield ServerSentEvent(data=chunk.text)
# Send a completion event
yield ServerSentEvent(data="[DONE]")
except Exception as e:
print(e)
yield ServerSentEvent(data=json.dumps({"error": str(e)}))
yield ServerSentEvent(data="[DONE]")
@app.post("/generate/")
async def generate_content(request: ContentRequest):
"""
Generate content based on provided URIs and user input using Gemini
"""
return EventSourceResponse(
generate_content_stream(request)
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)