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


プログラム利用ガイド
1. このプログラムの利用シーン
OpenAI APIのAPIキーを取得・設定するためのツールです。APIキーの取得からローカル環境への保存まで、一連の作業を対話式で案内し,APIキーのファイル保存等を行います。
2. 主な機能
- 自動ブラウザ起動: OpenAIのAPIキー発行ページを自動的に開き、取得手順を案内します。
- セキュアな入力: APIキー入力時に画面表示を無効化し、第三者による盗み見を防ぎます。
- 柔軟な保存設定: 以下の項目をカスタマイズできます。
- 環境変数名: OPENAI_API_KEYまたは任意のカスタム名
- 保存先ファイル: .env、.env.development、.env.production、または任意のパス
- ブラウザ起動方式: 既定モード、新しいタブ、新しいウィンドウから選択
- 既存キーの保護: 既存のAPIキーを検出し、誤った上書きを防ぎます。
- 自動バックアップ: 既存の.envファイルを.bakファイルとしてバックアップします。
- 利用ガイダンス: 保存後に環境変数の読み込み例を表示します。
3. 基本的な使い方
- ツールの起動:
コマンドラインでプログラムを実行します。対話式メニューが表示されます。
- 設定の選択:
環境変数名、保存先ファイル、ブラウザ起動方式をメニューから選択します。既定値のまま進むことも可能です。
- APIキーの取得:
ブラウザが自動的に開くので、OpenAIにログインし、案内に従ってAPIキーを作成・コピーします。
- APIキーの入力:
コピーしたAPIキーをツールに貼り付けます。入力内容は画面に表示されません。
- 保存の実行:
確認メッセージの後、APIキーが指定した.envファイルに保存され、利用例が表示されます。
4. 便利な機能
- 既存キーの確認: 保存済みのAPIキーがある場合、マスク表示で確認し、使用継続か上書きかを選択できます。
- 入力中断対応: Ctrl+Cでの中断時にも適切に処理を終了し、データの不整合を防ぎます。
- 環境変数名の検証: 無効な変数名を入力した場合、自動的に安全な既定名にフォールバックします。
- エラー時の代替案提示: ブラウザが開かない場合は手動でのURL表示など、問題発生時の対処法を案内します。
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/
OpenAI APIキー取得支援プログラム
概要
このプログラムは、OpenAI APIキーの取得と設定ファイルへの保存を支援するツールである。ブラウザでのAPIキー取得ページの自動表示と、APIキーの設定ファイル保存の機能を持つ。
主要技術
webbrowserモジュール
webbrowserモジュールは、ブラウザ制御機能を持つ[1]。デフォルトブラウザを自動検出し、指定されたURLを開く機能を持つ。
getpassモジュール
Pythonのgetpassモジュールは、パスワードやAPIキーなどを画面に表示せずに入力するためのものである[2]。
実装の特色
セキュリティ配慮の実装
APIキーの入力時にgetpass.getpass()を使用し、入力内容の画面表示を防止している。既存APIキーの表示時には部分マスク表示により、セキュリティを維持する。
既存設定の保護機能
既存の.envファイルからAPIキーを検出し、ユーザーに上書き確認を求める機能を実装している。.envファイル内のOPENAI_API_KEY行のみを更新する。
参考文献
[1] Python Software Foundation. (2025). webbrowser — Convenient web-browser controller. https://docs.python.org/3/library/webbrowser.html
[2] Python Software Foundation. (2025). getpass — Portable password input. https://docs.python.org/3/library/getpass.html
ソースコード
"""
OpenAI APIキー取得支援プログラム
特徴技術名: webbrowserモジュール
出典: Python Software Foundation. (2025). webbrowser — Convenient web-browser controller. Python 3.13.5 documentation. https://docs.python.org/3/library/webbrowser.html
特徴機能: プラットフォーム独立のブラウザ制御
webbrowserモジュールは、デフォルトブラウザを自動的に検出して使用する機能を提供する。
学習済みモデル: 使用していない
方式設計:
- 関連利用技術:
- getpassモジュール: パスワード入力時のエコー無効化によるセキュアな入力機能
- pathlibモジュール: オブジェクト指向ファイルパス操作とファイル読み書き機能
- reモジュール: .env内の環境変数行の検出(export有無や空白を許容)
- shutilモジュール: .envのバックアップ作成
- 入力と出力:
入力:
• 環境変数名の選択(OPENAI_API_KEY/カスタム)
• 保存先ファイルの選択(.env/.env.development/.env.production/カスタム)
• ブラウザの開き方の選択(既定/新しいタブ/新しいウィンドウ)
• ユーザーによる選択操作(ブラウザでのAPIキー取得、コンソールでのAPIキー入力)
出力: ブラウザでのOpenAI APIキーページ表示、APIキーの.envファイル保存、保存後のガイダンス表示
- 処理手順:
1. 環境変数名と保存先ファイルを選択する
2. 既存APIキーの確認と選択肢提示
3. ブラウザでOpenAI APIキーページを開く
4. ユーザーによる手動でのAPIキー取得
5. getpassを使用したセキュアなAPIキー入力
6. .envをバックアップし、APIキーの.envファイルへの保存
7. 保存後の確認メッセージと利用ガイダンス表示
- 前処理: 既存.envファイルの読み込みとAPIキー存在確認
- 後処理: APIキー保存後の確認メッセージ表示
- 追加処理: APIキーの部分マスク表示によるセキュリティ配慮、バックアップ作成
- 調整を必要とする設定値:
- var_name: 保存する環境変数名(OPENAI_API_KEY/カスタム)
- filename: APIキーを保存するファイル名(デフォルト: .env)
- browser_mode: ブラウザ起動モード(既定/新しいタブ/新しいウィンドウ)
将来方策: 既存の.envファイルの読み込みと同一APIキーの存在確認は現行実装で対応済み
その他の重要事項:
- getpassモジュールによりAPIキー入力時の画面表示を防止
- バックアップ作成機能により既存ファイルの安全性を確保
- 入力中断処理でユーザビリティを向上
前準備: なし(標準ライブラリのみ使用)
"""
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 = ['OPENAI_API_KEY']
OPENAI_API_URL = 'https://platform.openai.com/api-keys'
def safe_input(prompt, default=None):
"""入力中断時の共通処理"""
try:
return input(prompt)
except (KeyboardInterrupt, EOFError):
if default is not None:
print('入力が中断されたため既定値を用いる')
return default
print('入力が中断されたため処理を終了する')
raise SystemExit(1)
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 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='OPENAI_API_KEY'):
"""既存のAPIキーを確認する"""
file_path = Path(filename)
if not file_path.exists():
return None
try:
content = file_path.read_text(encoding='utf-8')
lines = content.splitlines()
for line in lines:
line = line.strip()
if line.startswith(f'{var_name}='):
api_key = line.split('=', 1)[1]
if api_key:
return api_key
return None
except Exception as e:
print(f'ファイル読み込みエラー: {e}')
return None
def open_api_page(mode='default'):
"""OpenAIのAPIキーページを開く"""
print('ブラウザでOpenAIのAPIキーページを開きます...')
funcs = {'new_tab': webbrowser.open_new_tab, 'new_window': webbrowser.open_new}
opened = funcs.get(mode, webbrowser.open)(OPENAI_API_URL)
if not opened:
print('ブラウザを開けなかった可能性がある。URLを手動で開くこと: ' + OPENAI_API_URL)
return opened
def show_instructions():
"""手動操作の指示を表示"""
print('\n=== 手動操作の手順 ===')
print('1. ブラウザでOpenAIにログインしてください')
print("2. 'Create new secret key'ボタンをクリック")
print('3. キーの名前を入力(任意)')
print("4. 'Create secret key'をクリック")
print('5. 表示されたAPIキーをコピーしてください')
print(' ※ このキーは一度しか表示されません!')
print('=====================================\n')
def get_api_key():
"""ユーザーからAPIキーを取得"""
print('コピーしたAPIキーを貼り付けてください')
api_key = getpass.getpass('APIキー: ')
return api_key.strip()
def save_api_key(api_key, filename=DEFAULT_ENV_FILE, var_name='OPENAI_API_KEY'):
"""APIキーをファイルに保存(上書きモード)"""
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')
for line in content.splitlines():
if not line.strip().startswith(f'{var_name}='):
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 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 += ['2. カスタム名を指定する']
options = {'1': DEFAULT_KEY_CHOICES[0], '2': None}
key, value = prompt_choice(header, options, default_key='1')
if key == '1':
return value
else:
custom = safe_input('変数名を入力(例: OPENAI_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, var_name):
"""保存後の参考情報を表示する"""
print('\n=== 利用の参考情報 ===')
resolved = str(Path(filepath).resolve())
print(f'保存パス: {resolved}')
print(f'環境変数名: {var_name}')
print('- 使用例:')
print(f' export $(grep -v "^#" {filepath} | xargs)')
print('======================\n')
def main():
print('=== OpenAI 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キーが見つかりました: {existing_key[:8]}...{existing_key[-4:]}')
print('1. 既存のAPIキーを使用する')
print('2. 新しいAPIキーで上書きする')
choice = safe_input('選択 (1/2, 既定: 1): ', default='1').strip() or '1'
if choice == '1':
print('既存のAPIキーを使用します')
print('\n処理を終了します')
return
elif choice != '2':
print('無効な選択です')
print('\n処理を終了します')
return
# ブラウザを開く
mode = choose_browser_mode()
wait_enter('Enterキーを押すとブラウザが開きます...')
open_api_page(mode)
# 手順を表示
show_instructions()
# APIキー取得の確認
wait_enter('APIキーをコピーしたらEnterキーを押してください...')
# APIキーを取得
api_key = get_api_key()
if api_key:
print(f'\n取得したAPIキー: {api_key[:8]}...{api_key[-4:]}')
# ファイルに保存
save_choice = safe_input('\nファイルに保存しますか? (y/n, 既定: y): ', default='y').strip().lower()
if save_choice in ('y', ''):
saved = save_api_key(api_key, env_file, var_name)
if saved:
show_post_save_guidance(env_file, var_name)
else:
print('APIキーが入力されませんでした')
print('\n処理を終了します')
if __name__ == '__main__':
try:
main()
except (KeyboardInterrupt, EOFError):
print('\n処理を中断しました。プログラムを終了します。')