Gemini APIキー取得支援ツール(ソースコードと説明と利用ガイド)

プログラム利用ガイド

1. このプログラムの利用シーン

Google Gemini APIを使用するプロジェクトで、APIキーの取得から設定まで一括して行いたい場合に利用できます。

2. 主な機能

3. 基本的な使い方

  1. プログラムの実行:

    コマンドプロンプトまたはPowerShellで「python ファイル名.py」を実行します。

  2. 環境変数名の選択:

    保存する環境変数名を選択します(1: GEMINI_API_KEY、2: GOOGLE_API_KEY、3: カスタム名)。

  3. 保存先ファイルの選択:

    APIキーを保存するファイルを選択します(1: .env、2: .env.development、3: .env.production、4: カスタムパス)。

  4. ブラウザの起動:

    ブラウザの開き方を選択し(1: 既定モード、2: 新しいタブ、3: 新しいウィンドウ)、Enterキーでブラウザが起動します。

  5. APIキーの取得:

    ブラウザでGoogleアカウントにログインし、「API キーを作成」をクリックしてAPIキーをコピーします。

  6. APIキーの入力:

    コンソールでAPIキーを貼り付けます(画面には表示されません)。

  7. 保存の確認:

    「y」を入力してAPIキーをファイルに保存します。

4. 便利な機能

Python開発環境,ライブラリ類

ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。

Python 3.12 のインストール

インストール済みの場合は実行不要。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。

REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul

関連する外部ページ

Python の公式ページ: https://www.python.org/

AI エディタ Windsurf のインストール

Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。

winget install --scope machine Codeium.Windsurf -e --silent

関連する外部ページ

Windsurf の公式ページ: https://windsurf.com/

Gemini APIキー取得支援ツール

概要

本プログラムは、Google AI StudioのGemini APIキーを取得し、環境変数ファイル(.env)に保存する作業を支援するツールである。Windows環境での実行を前提とし、ブラウザによるAPIキー発行ページへのアクセスから、取得したキーの安全な保存まで、一連の作業を支援する。

主要技術

webbrowserモジュール

Python標準ライブラリのwebbrowserモジュールを使用し、ブラウザ制御を実現する。open()、open_new()、open_new_tab()の各関数により、ユーザーの選択に応じた方法でブラウザウィンドウを開く。

getpassモジュール

getpass.getpass()関数[2]により、APIキー入力時のエコーバックを無効化する。これにより、画面上にAPIキーが表示されることを防ぎ、セキュリティを確保する。

技術的特徴

柔軟な環境変数検出

正規表現パターンにより、.envファイル内の環境変数を検出する。export文の有無、変数名前後の空白、等号前後の空白に対応し、シェルスクリプト形式とdotenv形式の両方をサポートする。

安全なファイル更新

既存の.envファイルを更新する際、shutilモジュール[4]を用いてバックアップファイル(.env.bak)を作成する。

APIキーのマスク表示

取得したAPIキーを画面表示する際、先頭8文字と末尾4文字のみを表示し、中間部分をマスクする。短いキーの場合は全体をアスタリスクで置換し、情報漏洩を防ぐ。

実装の特色

複数の環境設定ファイル対応

開発環境と本番環境の分離を考慮し、.env、.env.development、.env.productionの各ファイル形式に対応する。カスタムファイル名の指定も可能である。

対話的インターフェース

環境変数名、保存先ファイル、ブラウザ起動方法を対話的に選択できる。既存のAPIキーが存在する場合は、使用または上書きの選択肢を提供する。

ソースコード


"""Gemini APIキー取得支援ツール

特徴技術名: webbrowserモジュール
出典: Python Software Foundation. (2025). webbrowser — Convenient web-browser controller. Python 3.13.5 documentation. https://docs.python.org/3/library/webbrowser.html

前提: 本ツールは Windows 環境での実行を前提とする。

特徴技術および学習済モデルの利用制限: Python標準ライブラリはPython Software Foundation License (PSFL)の下で提供され、商用利用を含めて自由に使用可能。学習済みモデルは使用していない。

特徴機能: 既定ブラウザの起動制御
webbrowserモジュールはプラットフォーム独立であるが、本ツールでは Windows の既定ブラウザを用いて Gemini のAPIキー発行ページを開く。

学習済みモデル: 使用していない

方式設計:
- 関連利用技術:
 - getpassモジュール: 入力時のエコー無効化(環境により無効化できない場合がある)
 - pathlibモジュール: オブジェクト指向パス操作とテキスト読み書き
 - reモジュール: .env内の環境変数行の検出(export有無や空白を許容)
 - shutilモジュール: .envのバックアップ作成
- 入力と出力:
 入力:
 • 環境変数名の選択(GEMINI_API_KEY/GOOGLE_API_KEY/カスタム)
 • 保存先ファイルの選択(.env/.env.development/.env.production/カスタム)
 • ブラウザの開き方の選択(既定/新しいタブ/新しいウィンドウ)
 • コンソールでのAPIキー入力(getpass)
 出力:
 • Windowsの既定ブラウザでGemini APIキーページを表示
 • マスクしたAPIキーの一部表示
 • .envへの保存と保存先の絶対パス表示
 • 保存後のWindows PowerShell向け読み込み例の表示
- 処理手順:
 1. 環境変数名と保存先ファイルを選択する
 2. 既存APIキーを検出し(export形式と通常形式に対応)、使用または上書きを選択する
 3. ブラウザ起動方式を選択し、APIキー発行ページを開く
 4. ページの案内に従いAPIキーを取得する
 5. getpassでAPIキーを入力する
 6. .envをバックアップし、既存の対象行を除去してから新しいキーを保存する
 7. 保存結果とWindows向け読み込みガイダンスを表示する
- 前処理: 既存.envファイルの読み込みとAPIキーの存在確認
- 後処理: 保存結果の表示と読み込みガイダンス表示
- 追加処理: APIキーの部分マスク表示による情報露出の抑制

- 調整を必要とする設定値:
 - 変数名: 保存する環境変数名(GEMINI_API_KEY/GOOGLE_API_KEY/カスタム)
 - filename: 保存先ファイル名(.env/.env.development/.env.production/カスタム)
 - ブラウザ起動モード: 既定/新しいタブ/新しいウィンドウ

将来方策: 既存の.envファイルを読み込み、同一APIキーの存在確認を行う機能は実装済みである。

その他の重要事項:
- getpassは可能な場合に入力のエコーを無効化するが、環境によっては無効化できず入力が表示される場合がある。
- webbrowser.open系の戻り値は成否を示す。環境によりブラウザが開かない場合がある。

前準備: なし(標準ライブラリのみ使用)
"""

import webbrowser
from pathlib import Path
import getpass
import re
import shutil


# 設定定数
DEFAULT_ENV_FILE = '.env'
DEFAULT_ENV_CHOICES = ['.env', '.env.development', '.env.production']
DEFAULT_KEY_CHOICES = ['GEMINI_API_KEY', 'GOOGLE_API_KEY']
GEMINI_API_URL = 'https://aistudio.google.com/app/apikey'


def on_input_abort(default=None):
   """入力中断時の共通処理。defaultが与えられた場合は既定値を返し、なければ安全終了する。"""
   if default is not None:
       print('入力が中断されたため既定値を用いる')
       return default
   print('入力が中断されたため処理を終了する')
   raise SystemExit(1)


def safe_input(prompt, default=None):
   return input(prompt)


def prompt_choice(header_lines, options_map, default_key):
   """数値メニューの表示と入力処理を共通化する。キーと対応値を返す。"""
   for line in header_lines:
       print(line)
   prompt = f"選択 ({'/'.join(options_map.keys())}, 既定: {default_key}): "
   key = safe_input(prompt, default=default_key).strip() or default_key
   return key, options_map.get(key)


def wait_enter(prompt):
   """Enterキー待ちの共通処理。"""
   safe_input(prompt)


def build_key_pattern(var_name):
   """envファイル行のパターンを生成する。先頭の空白、先頭の 'export ' の有無、'=' の前後の空白を許容する。"""
   pat = r'^\s*(?:export\s+)?' + re.escape(var_name) + r'\s*='
   return re.compile(pat)


def sanitize_var_name(name):
   """環境変数名を検証・サニタイズする。無効な場合は既定名にフォールバックするための情報を返す。"""
   n = (name or '').strip()
   # 先頭の 'export' を除去(あれば)
   lowered = n.lower()
   if lowered.startswith('export'):
       parts = n.split(None, 1)
       n = parts[1] if len(parts) == 2 else ''
   # '=' を含む名称は不正(Windows仕様)
   if '=' in n:
       return (DEFAULT_KEY_CHOICES[0], True, "変数名に'='は使用できない")
   # POSIX慣用: 先頭は英字またはアンダースコア、その後は英数字とアンダースコアのみ
   if not re.match(r'^[A-Za-z_][A-Za-z0-9_]*$', n):
       if n == '':
           return (DEFAULT_KEY_CHOICES[0], True, '空の変数名')
       return (DEFAULT_KEY_CHOICES[0], True, '許可文字は英字・数字・アンダースコア。先頭は英字またはアンダースコア')
   return (n, False, '')


def check_api_key(filename=DEFAULT_ENV_FILE, var_name='GEMINI_API_KEY'):
   """既存のAPIキーを確認する。
   .env ファイルから、先頭が "[export ]<VAR_NAME>=" の最初の行を探索し、等号以降の値(前後空白は除去)を返す。
   見つからなければ None を返す。
   """
   file_path = Path(filename)
   if not file_path.exists():
       return None

   try:
       content = file_path.read_text(encoding='utf-8')
       pattern = build_key_pattern(var_name)
       for line in content.splitlines():
           if pattern.match(line):
               value = line.split('=', 1)[1].strip()
               if len(value) >= 2 and value[0] == value[-1] and value[0] in '"\'':
                   value = value[1:-1].strip()
               if value:
                   return value
       return None
   except Exception as e:
       print(f'ファイル読み込みエラー: {e}')
       return None


def open_api_page(mode='default'):
   """Gemini の API キー発行ページを Windows の既定ブラウザで開く。
   mode: 'default' | 'new_tab' | 'new_window'
   webbrowser の戻り値(True/False)を返す。
   """
   print('ブラウザでGeminiのAPIキー発行ページを開きます...')
   funcs = {'new_tab': webbrowser.open_new_tab, 'new_window': webbrowser.open_new}
   return funcs.get(mode, webbrowser.open)(GEMINI_API_URL)


def get_api_key():
   """ユーザーからAPIキーを取得する。
   getpass.getpass を用いて入力を受け付ける。環境によってはエコーを無効化できない場合がある。
   """
   print('コピーしたAPIキーを貼り付けてください')
   api_key = getpass.getpass('APIキー: ').strip()
   return api_key


def save_api_key(api_key, filename=DEFAULT_ENV_FILE, var_name='GEMINI_API_KEY'):
   """APIキーをファイルに保存する(上書きモード)。
   既存ファイルがある場合は、"[export ]<VAR_NAME>=" で始まる行を除去し、その他の行は保持する。
   保存前にバックアップを <filename>.bak として作成する。
   """
   try:
       file_path = Path(filename)

       existing_lines = []
       if file_path.exists():
           # バックアップ作成
           backup_path = Path(str(file_path) + '.bak')
           try:
               shutil.copyfile(file_path, backup_path)
               print(f'バックアップを作成した: {backup_path}')
           except Exception as be:
               print(f'バックアップ作成に失敗した: {be}')

           content = file_path.read_text(encoding='utf-8')
           pattern = build_key_pattern(var_name)
           for line in content.splitlines():
               if not pattern.match(line):
                   existing_lines.append(line + '\n')

       # 新しいAPIキーを書き出し
       content = ''.join(existing_lines)
       if content and not content.endswith('\n'):
           content += '\n'
       content += f'{var_name}={api_key}\n'

       # 親ディレクトリがない場合は作成
       file_path.parent.mkdir(parents=True, exist_ok=True)
       file_path.write_text(content, encoding='utf-8', newline='\n')
       print(f'APIキーを {file_path.resolve()} に保存した')
       return True
   except Exception as e:
       print(f'保存エラー: {e}')
       return False


def mask_key(key, head=8, tail=4):
   """APIキーのマスク表示を作成する。キー長が短い場合は全体をマスクする。"""
   if not key:
       return ''
   # キーが短い場合は全体をマスク
   if len(key) <= head + tail + 3:  # 最低3文字分のマスクを確保
       return '*' * len(key)
   return f'{key[:8]}...{key[-4:]}'


def choose_env_file():
   """保存先のenvファイルを選択する。"""
   header = ['保存先ファイルを選択する']
   header += [f'{i}. {name}' for i, name in enumerate(DEFAULT_ENV_CHOICES, 1)]
   header += ['4. カスタムパスを指定する']
   options = {'1': DEFAULT_ENV_CHOICES[0], '2': DEFAULT_ENV_CHOICES[1], '3': DEFAULT_ENV_CHOICES[2], '4': None}
   key, value = prompt_choice(header, options, default_key='1')
   if key in ('1', '2', '3'):
       return value
   else:
       custom = safe_input('保存先ファイル名を入力: ', default=DEFAULT_ENV_FILE).strip()
       return custom or DEFAULT_ENV_FILE


def choose_var_name():
   """保存する環境変数名を選択する。"""
   header = ['保存する環境変数名を選択する']
   header += [f'{i}. {name}' for i, name in enumerate(DEFAULT_KEY_CHOICES, 1)]
   header += ['3. カスタム名を指定する']
   options = {'1': DEFAULT_KEY_CHOICES[0], '2': DEFAULT_KEY_CHOICES[1], '3': None}
   key, value = prompt_choice(header, options, default_key='1')

   if key in ('1', '2'):
       return value
   else:
       custom = safe_input('変数名を入力(例: GEMINI_API_KEY): ', default=DEFAULT_KEY_CHOICES[0]).strip()
       var_name, is_fallback, reason = sanitize_var_name(custom)
       if is_fallback:
           print(f"無効な環境変数名のため既定名にフォールバック: 入力='{custom}' 理由={reason} → 使用名='{var_name}'")
       return var_name


def choose_browser_mode():
   """ブラウザの開き方を選択する。"""
   header = ['ブラウザの開き方を選択する', '1. 既定モードで開く', '2. 新しいタブで開く', '3. 新しいウィンドウで開く']
   options = {'1': 'default', '2': 'new_tab', '3': 'new_window'}
   _, value = prompt_choice(header, options, default_key='1')
   return value or 'default'


def show_post_save_guidance(filepath):
   """保存後の参考情報を表示する(Windows)。"""
   print('\n=== 利用の参考情報(Windows) ===')
   resolved = str(Path(filepath).resolve())
   print(f'保存パス: {resolved}')
   print('- Windows PowerShell の例:')
   print(f'  Get-Content "{resolved}" | ForEach-Object {{')
   print("    if ($_ -match '^(?<k>[^#=]+)\\s*=\\s*(?<v>.*)$') { [System.Environment]::SetEnvironmentVariable($matches.k.Trim(), $matches.v.Trim()) }")
   print('  }')
   print('======================\n')


def main():
   print('=== Gemini APIキー取得支援ツール ===\n')

   # 変数名と保存先ファイルを選択
   var_name = choose_var_name()
   env_file = choose_env_file()

   # 既存のAPIキーを確認
   existing_key = check_api_key(env_file, var_name)

   if existing_key:
       print(f'既存のAPIキーが見つかった: {mask_key(existing_key)}')
       print('1. 既存のAPIキーを使用する')
       print('2. 新しいAPIキーで上書きする')
       choice = input('選択 (1/2, 既定: 1): ').strip() or '1'

       if choice == '1':
           print('既存のAPIキーを使用する')
           print('\n処理を終了する')
           return
       elif choice != '2':
           print('無効な選択であるため処理を終了する')
           return

   # ブラウザを開く
   mode = choose_browser_mode()
   input('Enterキーでブラウザを開く...')
   opened = open_api_page(mode)
   if not opened:
       print('ブラウザを開けなかった可能性がある。URL を手動で開くこと: ' + GEMINI_API_URL)

   # 手動操作の指示を表示する。画面上の文言は変更される可能性があるため、ページの案内に従って操作すること。(旧show_instructionsの仕様)
   print('\n=== 手動操作の手順 ===')
   print('1. ブラウザでGoogleアカウントにログインする')
   print("2. 'API キーを作成(Create API key)' をクリック")
   print('3. 既存のプロジェクトを選択し、「既存のプロジェクトで API キーを作成」をクリック')
   print('4. 表示されたAPIキーをコピーする')
   print('=====================================\n')

   # APIキー取得の確認
   input('APIキーをコピーしたらEnterキーを押す...')

   # APIキーを取得
   api_key = get_api_key()

   if api_key:
       print(f'\n取得したAPIキー: {mask_key(api_key)}')

       # ファイルに保存
       save_choice = input('\nファイルに保存しますか? (y/n): ').strip().lower()
       if save_choice == 'y':
           saved = save_api_key(api_key, env_file, var_name)
           if saved:
               show_post_save_guidance(env_file)
   else:
       print('APIキーが入力されなかった')

   print('\n処理を終了する')


if __name__ == '__main__':
   try:
       main()
   except (KeyboardInterrupt, EOFError):
       print('\n処理を中断しました。プログラムを終了します。')