🦬

Emacs から ChatGPT を呼び出す例

2023/03/13に公開

外部コマンドを用意する

https://github.com/alexrudall/ruby-openai

~/bin/ai
#!/usr/bin/env ruby

require "openai"

OpenAI.configure do |config|
  config.access_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
end

user_text = ARGV.first

client = OpenAI::Client.new
response = client.chat(
  parameters: {
    model: "gpt-4o",
    messages: [
      # お好みで
      # { role: "system", content: "あなたは評判のコピーライターで上手に教えるのが得意です" },
      { role: "user", content: user_text },
    ],
  })

puts response.dig("choices", 0, "message", "content")

範囲選択を投げる

(defun my-ai-region (start end)
  "選択範囲を ChatGPT に投げる"
  (interactive "r")
  (let* ((text (buffer-substring start end))
         (command (format "ai %s" (shell-quote-argument text))))
    (save-excursion (insert (shell-command-to-string command)))))

;; (global-set-key (kbd "C-j t") 'my-ai-region)

プロンプトを毎回書くならこれでもよいが、次第に「〜を日本語に翻訳してください」などと毎回書くのが面倒になってくる。

メニュー化する

(require 'transient)

(defun my-ai-call (prompt)
  (interactive)
  (let* ((text (buffer-substring (region-beginning) (region-end)))
         (command (concat "ai" " " (shell-quote-argument (format prompt text)))))
    (save-excursion (insert (shell-command-to-string command)))))

(transient-define-prefix my-ai-menu ()
  "選択範囲を ChatGPT に投げる"
  [
   ["校正"
    ("k" "校正"         (lambda () (interactive) (my-ai-call "%s\n上の文章を校正してください")))
    ("b" "ビジネス文書" (lambda () (interactive) (my-ai-call "%s\n上の文章をビジネス文章として校正してください")))
    ]
   ["コード変換"
    ("r" "Ruby"         (lambda () (interactive) (my-ai-call "%s\n上のコードをRubyに変換してください")))
    ("p" "Python"       (lambda () (interactive) (my-ai-call "%s\n上のコードをPythonに変換してください")))
    ]
   ["翻訳"
    ("e" "→英語"       (lambda () (interactive) (my-ai-call "「%s」を英語に翻訳してください")))
    ("j" "→日本語"     (lambda () (interactive) (my-ai-call "「%s」を日本語に翻訳してください")))
    ]
   ["その他"
    ("t" "対話"         (lambda () (interactive) (my-ai-call "%s")))
    ]
   ])

;; (global-set-key (kbd "C-j t") 'my-ai-menu)

選択範囲に対して何をしてもらいたいかを選択する。

Discussion