Open3

Gemini Files API メモ

yuheitomiyuheitomi

Python および TypeScript 向けの SDK が提供されているが、ここでは RESTful API を使用した方法を記述する(理由は後述)。具体的な手順は以下の 2 ステップで構成される。

  1. アップロード用のプリサインド URL の取得
  2. 取得した URL を使用したファイルのアップロード

取得するアップロード用 URL には Gemini API Key が含まれて返されるが、ファイルのアップロード時には API Key を削除しても問題ない。ただし、ステップ 1(URL 取得)とステップ 2(ファイルアップロード)のリクエストは、同一のオリジン(ホスト)から実行する必要がある。異なるオリジンを使用すると CORS エラーが発生する可能性がある。

yuheitomiyuheitomi

Presigned url を取得してからアップロードするサンプル。

export interface GoogleUploadFile {
  name: string;
  displayName: string;
  mimeType: string;
  sizeBytes: string;
  createTime: string;
  updateTime: string;
  expirationTime: string;
  sha256Hash: string;
  uri: string;
  state: string;
  source: string;
}

export interface GoogleUploadResponse {
  file: GoogleUploadFile;
}

const GOOGLE_API_ENDPOINT = "https://generativelanguage.googleapis.com/upload/v1beta/files";

export async function getGoogleUploadUrl({
  name,
  type,
  size,
}: {
  name: string;
  type: string;
  size: number;
}): Promise<string> {
  const GOOGLE_UPLOAD_URL = `${GOOGLE_API_ENDPOINT}?key=${process.env.GOOGLE_GENERATIVE_AI_API_KEY}`;

  const initResponse = await fetch(GOOGLE_UPLOAD_URL, {
    method: "POST",
    headers: {
      "X-Goog-Upload-Protocol": "resumable",
      "X-Goog-Upload-Command": "start",
      "X-Goog-Upload-Header-Content-Length": size.toString(),
      "X-Goog-Upload-Header-Content-Type": type,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      file: {
        display_name: name,
      },
    }),
  });
  if (!initResponse.ok) {
    const errorText = await initResponse.text();
    throw new Error(`Failed to initiate upload: ${errorText}`);
  }

  // Get the upload URL from the response headers
  const uploadUrl = initResponse.headers.get("x-goog-upload-url");
  if (!uploadUrl) {
    throw new Error("No upload URL received from Google API");
  }
  const urlObj = new URL(uploadUrl);
  urlObj.searchParams.delete("key"); // Remove the API key from the URL
  const uploadUrlWithoutKey = urlObj.toString();
  console.log("Upload URL received:", uploadUrlWithoutKey);
  return uploadUrlWithoutKey;
}

export async function uploadToGoogle(url: string, file: File) {
  const uploadResponse = await fetch(url, {
    method: "PUT",
    headers: {
      "Content-Type": file.type,
      "Content-Length": file.size.toString(),
      "X-Goog-Upload-Offset": "0",
      "X-Goog-Upload-Command": "upload, finalize",
      "Access-Control-Allow-Origin": "*",
    },
    body: file,
  });

  if (!uploadResponse.ok) {
    const errorText = await uploadResponse.text();
    console.error(`Failed to upload file: ${errorText}`);
    return;
  }

  const responseData = (await uploadResponse.json()) as GoogleUploadResponse;
  console.log(responseData);
  return { success: true, file: responseData.file };
}