Closed6

GeminiのAPIを利用するまでの流れ

keitaknkeitakn

概要

PythonでGeminiのAPIを実行する為に必要な手順を記載します。

keitaknkeitakn

事前準備

GoogleCloudのプロジェクト作成

デフォルトのプロジェクトでも良いが専用のプロジェクトを作ったほうが分かりやすいので対応する。

Google AI StudioでAPIキーを発行

以下にアクセスしてAPIキーを発行する。

https://ai.google.dev/

以下のように先ほど作成したGoogleCloudのProjectを選択する。

作成すると以下のように動作確認用のコマンドが出てくるのでこれでAPIの動作確認をする。

curl \
  -H 'Content-Type: application/json' \
  -d '{"contents":[{"parts":[{"text":"Explain how AI works"}]}]}' \
  -X POST 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=YOUR_API_KEY'

以下のようなレスポンスが返ってくれば正常にAPIキーの発行が出来ている。

{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "## Understanding AI: A Simplified Breakdown\n\nArtificial intelligence (AI) is a broad field that encompasses a wide range of technologies and techniques. Here's a simplified explanation:\n\n**1. AI's Goal: Mimicking Human Intelligence**\n\nAI aims to create systems that can perform tasks that typically require human intelligence, such as:\n\n* **Learning and adapting:** AI systems can learn from data and improve their performance over time.\n* **Problem-solving:** AI can analyze information and find solutions to complex problems.\n* **Decision-making:** AI systems can make decisions based on data and reasoning.\n* **Understanding and responding to language:** AI can understand and generate natural language, like English or Spanish.\n* **Recognizing patterns and objects:** AI can identify patterns and objects in images, videos, and sounds.\n\n**2. How AI Learns: Machine Learning**\n\nMachine learning is a subset of AI that focuses on enabling systems to learn from data without explicit programming. This is done through algorithms that:\n\n* **Train on data:** These algorithms are fed large datasets of labeled examples to learn patterns and relationships.\n* **Make predictions:** Based on the learned patterns, the algorithms can make predictions or decisions on new, unseen data.\n\n**3. Different Types of Machine Learning:**\n\n* **Supervised learning:** Algorithms learn from labeled data, where each example has a known outcome.\n* **Unsupervised learning:** Algorithms learn from unlabeled data, identifying patterns and structures on their own.\n* **Reinforcement learning:** Algorithms learn through trial and error, receiving feedback and rewards for their actions.\n\n**4. Beyond Machine Learning: Other AI Techniques**\n\n* **Deep learning:** A powerful subset of machine learning that uses artificial neural networks with multiple layers to learn complex patterns from data.\n* **Natural language processing (NLP):** This focuses on enabling computers to understand and generate human language.\n* **Computer vision:** This allows computers to \"see\" and interpret images and videos.\n\n**5. AI Applications:**\n\nAI is used in numerous fields, including:\n\n* **Healthcare:** Diagnosis, treatment planning, drug discovery.\n* **Finance:** Fraud detection, risk assessment, personalized investing.\n* **Transportation:** Self-driving cars, traffic optimization.\n* **E-commerce:** Personalized recommendations, customer service.\n* **Education:** Personalized learning, automated grading.\n\n**Important Note:** AI is a rapidly evolving field. This explanation provides a basic understanding but is not exhaustive. There are many other aspects and nuances to explore.\n\n**In short, AI seeks to emulate human intelligence through data-driven learning and problem-solving techniques. Its applications are constantly expanding, transforming various industries and aspects of our lives.** \n"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "NEGLIGIBLE"
        }
      ]
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 4,
    "candidatesTokenCount": 562,
    "totalTokenCount": 566
  }
}
keitaknkeitakn

Vertex AI SDKからGemini APIを利用する

REST APIからだと動画ファイル等の容量制限が厳しいのでGoogleCloudStorage内の動画ファイルを解析する為にPythonからGemini APIを利用する。

packageの追加

以下の2つのpackageを追加。

rye add google-cloud-storage google-generativeai

GoogleCloud内での対応

GoogleCloudStorageの作成

東京region(asia-northeast1)でバケットの作成を行う。

オブジェクトは非公開(デフォルトで非公開)で普通に作成すれば問題ない。
(はじめての場合は課金手段の登録を要求されます)

Vertex AIの有効化

Vertex AIを有効化する。

regionを東京region(asia-northeast1)にしておく。

ServiceAccountの作成

以下からServiceAccountを作成。

https://console.cloud.google.com/iam-admin/serviceaccounts

以下の権限があればOKです。

JSON形式のServiceAccountキーをダウンロードしておきます。

環境変数の設定

以下の環境変数を設定。

export GOOGLE_CLOUD_CREDENTIALS=JSON形式のServiceAccountキーをBase64エンコードした値
export GOOGLE_CLOUD_PROJECT_ID=GoogleCloudのProject名
export GOOGLE_CLOUD_REGION="asia-northeast1"

GOOGLE_CLOUD_CREDENTIALS に関しての説明

よくある例だと GOOGLE_APPLICATION_CREDENTIALS にJSON形式のファイルへのパスを設定している例が見えますがこの方法だと本番環境のサーバー内等のJSONファイルを配置する方法を考える必要があるので少し面倒だと思いJSONファイル自体をBase64エンコードして環境変数で管理する方法を思いつきました。

以下のようにダウンロードしたJSONファイルをBase64エンコードします。

base64 -i your-service-account-secret.json

得られた値を GOOGLE_CLOUD_CREDENTIALS に設定します。

動画ファイルを検証する為のクラスを作成

以下のようなクラスを用意します。

これは video_url として受け取った動画ファイルを解析するクラスです。

response_mime_type を指定してJSONで値が返ってくるように調整しています。

import os
import json
import base64
from domain.repository.video_repository_interface import (
    VideoRepositoryInterface,
    AnalysisVideoDto,
    AnalysisVideoResult,
)
from google.cloud import storage
from google.oauth2 import service_account
import vertexai
from vertexai.generative_models import GenerativeModel, Part


class GeminiVideoRepository(VideoRepositoryInterface):
    def __init__(self) -> None:
        encoded_service_account_key = os.getenv("GOOGLE_CLOUD_CREDENTIALS")
        if encoded_service_account_key is None:
            raise Exception("GOOGLE_CLOUD_CREDENTIALS is not set.")

        decoded_service_account_key = base64.b64decode(
            encoded_service_account_key
        ).decode("utf-8")
        service_account_info = json.loads(decoded_service_account_key)

        self.google_cloud_storage_client = storage.Client.from_service_account_info(
            service_account_info
        )

        self.credentials = service_account.Credentials.from_service_account_info(
            # service_account_info の型チェックは難しいので type: ignore で回避している
            service_account_info  # type: ignore
        )

        vertexai.init(
            project=os.getenv("GOOGLE_CLOUD_PROJECT_ID"),
            location=os.getenv("GOOGLE_CLOUD_REGION"),
            credentials=self.credentials,
        )

    async def video_analysis(self, dto: AnalysisVideoDto) -> AnalysisVideoResult:
        model = GenerativeModel(
            "gemini-1.5-flash-001",
        )

        video = Part.from_uri(
            // video/quicktime とハードコードされていますが `video_url` の拡張子から判定すべきです
            mime_type="video/quicktime",
            uri=dto["video_url"],
        )

        contents = [
            video,
            """
            # Instruction
            動画の内容を確認して要約の作成をお願いします。
            
            # 制約条件
            - 以下のJSON形式で返すようにお願いします。
              - {"summary": "動画の要約文章をここに設定"}
                - "summary" には動画の要約文章を設定します。
            - ハルシネーションを起こさないでください。
            """,
        ]

        generation_config = {
            "response_mime_type": "application/json",
        }

        response = await model.generate_content_async(
            contents,
            generation_config=generation_config,
        )

        response_content = response.text

        result: AnalysisVideoResult = json.loads(response_content)

        return result

以下のような形でレスポンスが返ってきます。

{'summary': '動画は、飼い主らしき人物が「ねこちゃん、こっちおいで」と呼びかける様子から始まります。ねこちゃんは最初は振り返り、その後飼い主の方へ歩み寄ります。しかし、飼い主はねこちゃんを呼ぶのをやめてしまい、ねこちゃんは少し寂しそうな表情を見せます。最終的にねこちゃんは飼い主の元へ寄り添い、動画は終了します。'}

今後、Gemini以外のLLMで実装する可能性もあるので VideoRepositoryInterface というインターフェースを用意して、それを実装する形にしています。

from typing import Protocol, TypedDict


class AnalysisVideoDto(TypedDict):
    video_url: str


class AnalysisVideoResult(TypedDict):
    summary: str


class VideoRepositoryInterface(Protocol):
    async def video_analysis(self, dto: AnalysisVideoDto) -> AnalysisVideoResult: ...
keitaknkeitakn

今後の改善

動画の内容を要約するという曖昧なプロンプトなので出力内容にかなりばらつきがあります。

プロンプトの内容を改善して何を抽出するのか?の目的をしっかりと言語化する事で目的の情報を取れるようになると思います。

このスクラップは2024/08/20にクローズされました