macOSでプリントスプーラー型
AIチャット自動送信ツールを
作った話
(ChatSpooler)

AIチャットで複数の質問を連続送信したいとき、手動でひとつずつ送るのは面倒です。プリンターが印刷ジョブを順番に処理するように、文章をキューに積んで自動送信するツールを作りました。

関連記事

1. なぜ作ったのか

AIに複数の関連質問をする際、前の回答を読んでから次の質問を考えるより、先に全部の質問を準備して順番に送信したい場面があります。しかし手動で送信していると、送信タイミングを忘れたり、質問の順序が混乱したりします。

プリンターのスプーラーのように、送信したい文章を事前にキューに蓄積し、設定した間隔で自動送信する仕組みがあれば便利だと考えました。

2. 開発環境と基本構想

開発はmacOS環境で行いました。PythonのtkinterでGUIを作成し、macOS特有のAPI1を活用して他のアプリケーションを制御します。

基本的な構想は以下の通りです。送信したい文章を入力してキューに追加し、指定した間隔で順番に送信する。送信先のアプリケーションを自動で特定し、バックグラウンドで動作する。

2.1. コードとインストール

インストールは、VS Codeのターミナルで以下を実行しました。

# 仮想環境を作成
python3 -m venv myenv

# 仮想環境を有効化
source myenv/bin/activate

# 必要なパッケージをインストール 
pip install pyautogui pyperclip pyobjcCode language: PHP (php)

Pythonコードは、1つのファイルです(後に、分割しました)。

2.2. Windows版とmacOS版の違い

当初はWindows向けにwin32guiのコードを参考にしましたが、開発環境がmacOSだったため、macOS専用のライブラリに変更する必要がありました。Windowsのwin32guiに相当するmacOSの機能として、pyobjcライブラリとQuartzフレームワーク2を使用しました。これらはmacOSのネイティブAPIにPythonからアクセスできるライブラリです。

アプリケーション一覧の取得にはNSWorkspaceを使用し、ウィンドウ操作にはCGWindowListCopyWindowInfoを活用しました。

3. 送信方式の検討と実装

テキスト送信には3つの方式を実装しました。これは、うまくいかないときのためですが、最終的にはどれも動作しました。基本的には、AppleScript方式を使っています。

3.1. AppleScript方式

AppleScriptはmacOSの自動化スクリプト言語3です。アプリケーションを直接制御できるため、最も確実な方法といえます。アプリケーションを直接制御できるため、最も確実な方法といえます。

script = f'tell application "{app_name}" to activate'
subprocess.run(['osascript', '-e', script])
Code language: JavaScript (javascript)

アプリケーションをアクティブ化した後、System Eventsを使ってキーストロークを送信します。

3.2. クリップボード方式

クリップボードに文章をコピーし、Cmd+Vでペーストする方式です。日本語や特殊文字を確実に送信でき、動作速度も高速です。

pyperclip.copy(text)
# AppleScriptでCmd+V実行
paste_script = '''
tell application "System Events"
    key code 9 using command down
end tell
'''
Code language: PHP (php)

3.3. pyautogui方式

pyautoguiライブラリを使用した直接入力方式4です。汎用性は高いものの、日本語入力や特殊文字の処理で問題が発生する場合があります。

4. macOSでの課題と解決策

4.1. キーボードショートカットの違い

WindowsとmacOSではキーボードショートカットが異なります。ペースト操作はCtrl+VからCmd+Vに変更する必要がありました。

# Windows
pyautogui.hotkey('ctrl', 'v')

# macOS  
pyautogui.hotkey('cmd', 'v')
Code language: PHP (php)

4.2. チャット送信の特殊性

一般的なアプリケーションではReturnキーで改行ですが、多くのチャットアプリではCmd+Returnで送信5します。この違いを把握せずに実装すると、文章が改行されるだけで送信されません。

AppleScriptのキーコードを使用して正確に指定しました。

# key code 36 = Return
# key code 36 using command down = Cmd+Return
paste_script = '''
tell application "System Events"
    key code 36 using command down
end tell
'''
Code language: PHP (php)

4.3. 親指シフト入力の影響

Lacaille等の親指シフト入力ソフト6を使用している環境では、英字キーの入力結果が変わります。vキーを押すと「」が入力され、Cmd+Vが正しく動作しませんでした。

この問題はAppleScriptのキーコード指定で解決しました。キーコードは物理的なキーを直接指定するため、入力メソッドの影響を受けません。

# 物理的なVキー(キーコード9)を指定
key code 9 using command down
Code language: PHP (php)

5. デバッグの重要性

開発過程で関数が呼ばれているにも関わらず、内部の処理が実行されない問題が発生しました。詳細なログ出力を追加してデバッグした結果、関数の重複定義やインデントエラーが原因と判明しました。

print(f"=== 送信開始 ===")
print(f"送信方式: {method}")
print(f"対象アプリ: {target_app}")
Code language: PHP (php)

複雑なシステムでは、どこで処理が止まっているかを特定するため、各ステップでログを出力することが重要です。

6. アプリケーション権限の設定

macOSでは、他のアプリケーションを制御するために明示的な権限設定が必要です。「システム環境設定」の「セキュリティとプライバシー」で、「アクセシビリティ」と「入力監視」の許可7を設定します。

この設定なしでは、キーストロークの送信やアプリケーションの制御ができません。

7. 実装の詳細

7.1. GUI設計

tkinterを使用してシンプルなGUIを作成しました。送信先アプリの選択、文章入力エリア、キュー表示、設定項目を配置しています。

送信先の指定は2つの方法を用意しました。アプリケーション一覧から選択する方法と、最前面のアプリを自動取得する方法です。

7.2. キュー管理

PythonのQueueクラス8を使用してFIFO(先入先出)のキューを実装しました。文章を追加、削除、並び替えできる機能も含んでいます。

self.message_queue = Queue()
self.message_queue.put(text)  # キューに追加
text = self.message_queue.get_nowait()  # キューから取得
Code language: PHP (php)

7.3. 送信ループ

別スレッドで送信処理を実行し、メインのGUIスレッドをブロックしないように設計しました。設定した間隔でキューから文章を取得し、順番に送信します。

def queue_sending_loop(self):
    while self.is_running and not self.message_queue.empty():
        text = self.message_queue.get_nowait()
        self.send_text(text)
        # 設定した間隔で待機
        time.sleep(interval)
Code language: PHP (php)

8. 完成したツールの特徴

最終的に、3つの送信方式に対応したGUIツールが完成しました。キューに複数の文章を追加し、設定した間隔で自動送信できます。送信先アプリの自動特定機能により、使いやすさを向上させました。

緊急停止機能として、マウスを画面左上角に移動するpyautoguiの標準機能も活用しています。

動作確認はClaude(Web版)、Chrome、Safari等で行い、正常に送信できることを確認しました。

9. 実用性を高める機能改善

基本的な自動送信機能が完成した後、実際の使用を想定してさらなる改善を行いました。

9.1. キューごとの個別待機時間設定

AIへの質問内容によって回答に要する時間は大きく異なります。簡単な質問なら数秒で回答が返ってきますが、複雑な分析や長文生成を求める質問では1分以上かかる場合もあります。

一律の待機時間では非効率的なため、キューの各アイテムに個別の待機時間を設定できる機能を実装しました。文章入力時に待機時間を指定し、送信後はその時間だけ待機してから次の文章を送信します。

queue_item = {
    'text': text,
    'wait_time': wait_time,  # 個別の待機時間
    'status': '待機中'
}Code language: PHP (php)

これにより、「基本情報を教えて(10秒待機)」→「詳細な分析をお願いします(60秒待機)」→「具体例を3つ挙げてください(30秒待機)」といった効率的な質問設計が可能になりました。

9.2. 送信履歴と再送信機能

開発や学習において、同じ質問を再度投げかけたい場面は頻繁にあります。過去の質問を手動で再入力するのは非効率的です。

送信完了した全ての文章を履歴として保存し、ワンクリックで再送信できる機能を追加しました。履歴には送信時刻、内容、待機時間が記録され、個別の再送信だけでなく、全履歴の一括再キューにも対応しています。

history_item = {
    'text': text,
    'wait_time': wait_time,
    'timestamp': datetime.now().strftime("%H:%M:%S")
}
self.sent_history.append(history_item)Code language: PHP (php)

9.3. ユーザビリティの向上

文章入力エリアでCmd+Returnを押すことで、マウスを使わずにキューへの追加ができるようになりました。また、AppleScriptを送信方式のデフォルトに設定し、初心者でも確実に動作する環境を提供しています。

self.text_area.bind('<Command-Return>', self.add_to_queue_shortcut)Code language: PHP (php)

キーバインドにはreturn 'break'を設定し、イベントの伝播を停止することで意図しない改行を防いでいます。

10. 技術的な学び

macOS環境でのアプリケーション間連携には、AppleScriptとpyobjcが強力なツールです。WindowsのWin32 APIとは異なるアプローチが必要ですが、より直感的で安定した制御が可能でした。

特にAppleScriptは、macOSの標準的な自動化手段として、アプリケーション制御において優れた互換性を示しました。物理的なキーコード指定により、入力メソッドの影響を回避できる点も重要な発見でした。

GUIアプリケーションの開発では、別スレッドでの処理とメインスレッドの役割分担が重要です。送信処理を別スレッドで実行することで、ユーザーインターフェースの応答性を維持できました。

11. まとめ

macOS環境でのPythonアプリケーション開発において、pyobjc、AppleScript、pyautoguiを組み合わせたマルチモーダルなアプローチが有効であることを確認しました。プリントスプーラー型のキュー管理により、AIチャットでの連続質問を効率化するツールを実現できました。

  1. macOSでPythonからネイティブAPIにアクセスするには、PyObjCブリッジが必要です。これによりObjective-CのAPIをPythonから直接呼び出せます。 – PyObjC Documentation
  2. QuartzはmacOSのグラフィックス・ウィンドウシステムの基盤となるフレームワークです。ウィンドウ情報の取得や画面制御に使用されます。 – Quartz Services Reference
  3. AppleScriptは1993年にAppleが開発したスクリプト言語で、macOSアプリケーション間の連携や自動化に特化しています。 – AppleScript Language Guide
  4. pyautoguiはクロスプラットフォームのGUI自動化ライブラリで、マウスやキーボードの操作を自動化できます。画面の左上角に移動すると緊急停止する安全機能があります。 – PyAutoGUI Documentation
  5. Slack、Discord、Teams、WebベースのAIチャットサービスなど、多くのモダンなチャットアプリケーションで採用されているショートカットです。 – Slack Keyboard Shortcuts
  6. 親指シフトは日本語入力の効率化を図る配列方式で、LacailleはmacOS用の親指シフト入力ソフトウェアです。通常のQWERTY配列とは異なるキー配置になります。 – Lacaille – 親指シフト入力
  7. macOS Mojave以降では、他のアプリケーションを制御するために明示的なプライバシー許可が必要になりました。これはセキュリティ強化の一環です。 – macOS Security and Privacy Guide
  8. Queueクラスはスレッドセーフなキューの実装で、マルチスレッド環境でのデータ交換に適しています。FIFO、LIFO、優先度付きキューなど複数の種類があります。 – Python Queue Documentation