もうLaTeX文書は生成AIに書かせよう

2024-12-23 (updated: 2024-12-24)  #LaTeX  #LuaTeX  #Lua  #生成AI 

本稿はTeX & LaTeX Advent Calendar 2024の23日目の記事です。22日目はhid_alma1026さんでした。24日目はk16shikanoさんです。


今年も師走がやってきました🎄 この時期はいつも慌ただしい傾向にありますが、今年は特に原稿の締切が重なり、執筆が追いつかない状況に陥っています😅 最近の生成AIはどうやらかなりすごいようなので、原稿の執筆を肩代わりしてもらえれば作業が大幅に効率化できそうです🚀 すごいTeXエンジンであるところのLuaTeXを使えばOpenAIのAPIを直接呼び出せるので、この記事ではそんな方法をご紹介します💡 生成AIとLuaTeXの力で効率的な執筆を目指しましょう✍️✨!


なお、時間がなかったので上記イントロ部分は生成AIに作成させました。ここから先の内容は筆者(たぶん人間のはず)が自分で執筆したものです。

Warning

一般にレポートや論文作成時には、守るべき教育機関のルールや投稿規定が存在します。生成AIの利用にあたっては、必ずそうしたルールに則るようにましょう。本稿はルール違反な形での生成AI利用を推奨するものではありません

前提

本稿の内容について、筆者は以下の環境で動作確認をしました。

  • macOS Ventura 13.5
    • Lua 5.4.7 (via Homebrew)
    • LuaRocks 3.11.1
  • TeX Live 2024
    • LuaHBTeX 1.18.0

またOpenAI APIの利用にはAPI keyが必要です。本稿ではAPI keyが環境変数OPENAI_API_KEYに設定されているものと仮定します。OpenAI APIの挙動は時期により大きく異なります。筆者が動作確認を行ったのは2024年12月21日から同23日の期間です。

LuaTeXからOpenAIのAPIを叩く

LuaTeXであればluasocketを利用して特に外部プログラムを利用せずともOpenAIのAPIを叩くことが可能です(-shell-escapeは必要)。とはいえ、APIを叩くための通信ロジックやらJSONパーサやらを自分で書くのは大変なので、既存のOpenAI APIのLuaバインディングを利用します。ありがたや🙏

このライブラリは通常はLuaRocksで簡単にインストールすることが可能です。ただし今回のケースは通常ではありませんでした(後述)。

luarocks --local install lua-openai

LuaTeX搭載のLuaインタプリタも基本的には普通のLuaインタプリタなので、LuaRocksで導入したライブラリも利用可能です。ただし、LuaTeXをTeXエンジンとして起動した場合は探索パスがやや特殊1なので、今回のように外部ライブラリを利用するときはluapackageloaderパッケージを利用するなどして挙動を通常のインタプリタと一致させておく必要があります。

\usepackage{luacode}
\usepackage{luapackageloader}

この状態でluacode*環境内にLuaコードを書いていきます。

\begin{luacode*}
-- ここにLuaコードを書く
\end{luacode*}

lua-openaiの読み込み

普通であれば

local openai = require 'openai'

で終わりのはずです。

なのですが、筆者の場合はチョットややこしい状況にありました。システムにインストールされている通常のLuaインタプリタは5.4ですが2、LuaTeX搭載のLuaはいまのところ5.3なので非互換です。Luaコード内の仕様はそれほど変わらないはずですが、C言語によるバイナリライブラリになると非互換なので、動かすのには工夫が必要でした。

local HOME = os.getenv('HOME')

local LIB_PATH = HOME .. '/.luarocks/share/lua/5.4/'
local CLIB_PATH = HOME .. '/.luarocks/lib/lua/5.3/'
package.path = LIB_PATH .. '?.lua;' .. LIB_PATH .. '?/init.lua;' .. package.path
package.cpath = CLIB_PATH .. '?.so;' .. package.cpath

この部分はかなり環境依存な気がするので、詳細は飾り枠に入れておきます。

Note

システムのLuaが5.4なので、普通にluarocksでライブラリをインストールすると、依存関係も含めてすべてLua 5.4をターゲットにしてビルド、インストールされます。ターゲットのバージョンを明示的に指定するには--lua-version=5.xのようにすればよいようです。

luarocks --local install --lua-version=5.3 <package>

ここでlua-openaiをLua 5.3向けにインストールできれば簡単だったのですが、どうやら対応していないようで無理でした。もっともlua-openai自体のコードはLua 5.3でも問題なく動くので、問題となる依存Cライブラリのみ5.3向けにインストールします。該当するのはluasocketluaseclua-cjsonの3つです。

luarocks install --lua-version=5.3の実行には、ターゲットバージョンのLuaインタプリタが必要です。すでにHomebrewではLua 5.3を入れる手段がなかったので、公式ページから入手して自前でビルドしました。ビルドしたluaバイナリのパスを

luarocks --local config --lua-version=5.3 variables.LU <path>

のようにLuaRocksに教えてあげることで、luarocks install --lua-version=5.3としてLua 5.3向けに各ライブラリをインストールできます。

あとはpackage.pathはLua 5.4系向き、package.cpathはLua 5.3系向きに設定すると、無事にLuaTeXのLuaインタプリタでも動作しました。

クライアントの作成と回答の取得

lua-openaiの読み込みさえうまくいけばあとは難しくありません。同ライブラリには丁寧にもサンプルLuaコードが添付されているので、これにならってコードを書けば問題ありません。今回は一番シンプルなexample1.luaを改変すれば十分です。

API keyを指定してクライアントを作成します。

local openai = require 'openai'
local client = openai.new(os.getenv('OPENAI_API_KEY'), {http_provider = 'ssl.https'})

openai.new()の第2引数は指定しなくてもよしなに利用可能なHTTPライブラリが選択されるはずなのですが、うまくいかなかったのでhttp_provider = 'ssl.https'を明示しています。

あとはお好みのシステムプロンプトとメッセージを添えてAPIを叩けばOKです。

local sys_prompt = [[You are a Japanese TeX/LaTeX expert.
Return your answers as LaTeX codes, not Markdown.
You only need to produce paragraphs. You don't have to write \begin{document} or \section.
Do not include anything except LaTeX code.
Use commands \TeX{} and \LaTeX{} for TeX-related names.
Please be aware that you have to use \verb to escape TeX commands within your explanation.
Try not to produce invalid LaTeX code.
]]

local status, response = client:chat({
  {role = 'system', content = sys_prompt},
  {role = 'user', content = 'ここにメッセージを書く'}
}, {
  model = 'gpt-4o-mini',
  temperature = 0.5
})

if status == 200 then
  res = response.choices[1].message.content
else
  print('Request error: ' .. status)
end

この状態でグローバル変数resに生成AIの回答が格納されているので、本文中で\directlua{tex.sprint(res)}とでもすればPDF出力に投げ込むことができます。

完成形

もう若干だけましなエラー処理を加えてAPIを叩く部分を関数化し、通常のLuaTeX文書に組み込むと最終的にこのようになりました。

temperatureの設定次第ですが、上記のコードは実行の度に結果が異なります。手許ではこんな文書が生成されました(PDF)。

おわりに

我々は頭脳労働から解放されました。これからLaTeX文書を作成するときは、非本質的なコンテンツの作成は生成AIに任せて、我々はより本質的な仕事に集中できますね。めでたしめでたし☃


  1. 詳しくは某ZR氏の記事などを参照。 ↩︎

  2. タイムリーにもlua@5.3は今年12/14に削除されたようです(d33a504 in Homebrew/homebrew-core)。 ↩︎