ClaudeにOfficeファイルのViewerライブラリをTypeScriptで作らせた
概要
ClaudeでMicrosoft Officeのサポートするファイル拡張子のうち、Office Open XML (OOXML) として仕様が標準化されている3つ、docx, xlsx, pptxの表示機能を提供するJSのライブラリを作った。
経緯
コーディングにおけるAI活用の文脈だと、一昨年くらいからGitHub CopilotやChatGPTは活用していたものの、所謂バイブコーディングというものに関しては、Clineが一時期盛り上がっていたのを横目に見ていたくらいで、手を出さないままで来ていた。昨年の夏頃、始めてChatGPT以外のAIエージェントとしてClaudeを触る機会があった。これはMCPに興味が湧いたのがきっかけで、当時調べたところ、無料で使えるエージェントで、ローカルに立てた自前のMCPとの接続をサポートしていたのがClaudeだけだったからである。そのときは、エージェントとしての性能は特に可もなく不可もなくで、本当にMCPという抽象化レイヤーを備えていることだけが、自分のアプリと生成AIをつなぐ架け橋として、魅力的に映った記憶がある。で、その後はまたしばらく空いて、秋になり、そうすると色々なところから、Claude Codeがすごい、という話がちらほら聞こえ始めた。MCPの件で多少Claudeに親近感もあり、今度は試しに課金して実際に触り始めることにした。
それで最初に作ったのが下の「Stencil Canvas」というWebアプリである。これはユーザーのブラウザ上で完結して、画像をステンシル(孔版印刷)で印刷したような見た目に変換してくれるアプリだ。
https://yukiyokotani.github.io/stencil-canvas/
本題から逸れるのでここでは特に触れないが、実装時にエラーでコケることなど皆無で、shader実装含めトントン拍子で要望を実現してくれることに心底驚いた。
その様子を見て、やりたくなったのがこの記事の本題であるOfficeファイルのViewerライブラリの実装である。実はこれも以前欲しくなって調べたことがあるのだが、これまでに世に出ているOfficeファイルのViewrはOSSの範囲だと、Word, Excel, PowerPointのどれか一つだけをターゲットにしているものがほとんどで、また、描画のクオリティもお世辞にも良いとは言えないものばかりだった。有料ライセンスのライブラリになると描画のクオリティはグッと上がり、編集もできるものが出てきたりするのだが、当然ライセンス料は相応にかかり、そもそも自分はそこまで機能的にリッチなものが欲しいわけではなかった(そこまでやりたいならそもそも公式のMicrosoft 365でやるわ、というね…)ということもあって、どうも丁度よいものがなかったのである。自分が欲しかったのは純粋にOfficeファイルのバイナリをそれなりに忠実に表示(プレビュー)すること、ただそれだけだった。
この調べ物をしていたときに、Officeのファイルの内、docx, xlsx, pptxについては仕様がOOXMLとして標準化されて公開されていることを知った。Claudeで遊んで、適当な思いつきレベルの要望をどんどん実現してくれるところまで生成AIが進化した今、仕様の存在するdocx, xlsx, pptxのViewerの実装をClaudeにお願いすることはまさにやればできるようなレベルの話に思えた。ちょうどClaude周りで色々キャッチアップをしたいタイミングだったのもあり、ClaudeのプランをMaxにアップグレードして取り組むことにした。
できたもの
そうしてできたものが下の2つである。1つ目はJS (TS) のライブラリで、parser部分は速度面を重視してRust (WebAssemblyにビルド) 、renderer部分はフレームワーク問わず利用できるようにプレーンなTSで実装をしている。描画品質はそれなりにこだわっているので、Office公式と比較して完全ではないが、それでもすでにかなりいい線まで行っている自負がある。(まあ 実装したのはClaudeなんだけど)
2つ目はVSCode拡張で、1つ目のJSライブラリを使ってVSCodeのWebViewでOfficeファイルを表示するものである。このVSCode拡張はおまけとしてオプションでdocx, xlsx, pptxのparserをベースに、ファイルの読み取りツールを提供するMCPを提供する。OfficeファイルをClaudeだったり、GitHub Copilotに食わせてコーディングしたいときに、何もないとエージェントは書き捨てのPythonスクリプトを書いて、ファイルをunzipし、xmlをパースして中身を読み取るのだが、これが毎回行われるのはとても無駄に思えたので、個人的にぜひ改善したかった。刺さる人には刺さるんじゃないかと思う。
実装の思い出
実装をしたのは完全にClaudeで、今回自分は一行たりともコードを書いていないが、他の部分でいくらか自分(人間)にしかできない貢献をしたので思い出として書き残しておきたいと思う。ただ、うまくやって権限も与えればもしかしたら全部エージェントで乗り越えられたのかもしれない。
正解データの提供
これは一番大きな話で、自分も実際にClaudeにやらせてみてわかったことであるが、OOXMLの仕様書はOfficeの表示を再現するという点においては完全ではない。Claudeからの返信メッセージで知ったが、いくらか実装側に任せられているものがあり、そこは何を正とするか(今回で言えばWord, Excel, PowerPointがどう表示しているか)をアドホックに与えていかないといけなかった。そこで、自分はまず初めにデモデータとなるOfficeファイルをいくつか用意し、docx, pptxについてはそこからせっせとページorスライドを画像出力してClaudeにVRTを組ませることにした。ただ、この方法は結果的にはほぼうまくいかなかった。VRTは前回断面と比較してレイアウトのリグレッションを検知するのには役に立つが、一からレイアウトを組む局面において利用しても、正解とのピクセル差分が大きすぎて、また機械には何が間違っているのか(要素がないのか、見た目が違うのか、など)の解釈が難しすぎて、精度改善には一向に寄与しなかった。そこで、docx, pptxについてはpdf出力し、これを正解として与える方式に舵を切った。正解pdfはClaudeによって良しなにpdf.js等でパースされていたようであるが、これによって何の要素がどの座標に描かれるべきか、エージェントが正確に把握できるようになり、あとはそれがOOXMLのどの仕様に基づくものなのかを適宜紐解いて、実装につなげてくれた。これで描画クオリティは大きく上がり、ベースライン実装を完成させることができた。現状は、それでもまだポツポツと存在する差異について、人の目で一つ一つ指摘しながら改善を進めているフェーズである。なお、xlsxについてはPDF出力だとそもそもページの概念との不整合により表示崩れが起きることから、当初より人の目で一つ一つ指摘して改善するという流れで実装を進めた。幸いExcelはセル番号でどこが違うかを伝えやすいこともあり、この方法でも割とスムーズに改善を進めることができたと思う。
Claudeの使用制限管理
一番初めはシングルセッションでPlanモードでOpusとSonetを使い分けるという運用をしたが、それではMaxプランのセッションリミットを全く使い切れないことがわかり、次にこれをマルチセッションで実行するようにした。これはdocx, xlxs, pptxのparser, rendererのベースラインを整備するときにはかなり効率を上げてくれたが、結局途中から先に書いたような人の目での合わせ込みが必要になって、自分がボトルネックになった結果、シングルセッションに戻った。それでやっぱりセッションリミットを使い切れなくなったと、だんだん承認が面倒になってきたのもあって、今はOpusの自動モードですべてを流している。これをやると、Max (5x) の直列実行でも簡単にセッション制限、週次制限にかかるようになったが、使い切れないよりはいいだろうということで良しとしている。結果的に色々試せて、$100のプランでできることへの肌感を得られたのがとりあえず良かった。