最近Snowflakeで仕事していることの多いこのごろです。
わけあってdocファイルとかxlsファイルとかpptファイルが大量にでてきたけど、これ読み込めないじゃんと困ってていろいろ調べたまとめです。
なにができたらうれしいか
とりあえずいろんな文書をMarkdownにしたい。最近はSnowflakeでもAI Parse Document関数によってスキャンして画像しかないPDFだろうが表まで認識してMarkdownにできるようになってきており(前はAzure Document Intelligenceくらいしかいいのなかった記憶)、これで処理できる形式になってれば勝ちです。
で、
許可されたファイルタイプ
PDF 、 PPTX 、 DOCX 、 JPEG 、 JPG 、 PNG 、 TIFF 、 TIF 、 HTML 、 TXT
とのことなので、神Excelや古のdoc, ppt, xlsなんかはこのままじゃいけないのです。ここに書いてある形式になれば、ほぼ勝ちです。
やったこと
- LiberOfficeのヘッドレスで変換
- これのDocekr化
- SPCS化
この流れです。これでSnowflakeのステージに上がってればまとめて変換できます。神エクセルも一回PDFにしちゃうので大丈夫です。
LiberOfficeのヘッドレスで変換
doc to docxなどをいろいろ調べた結果、割とみんな苦労しているみたいですが(これとかほかにも引用したい記事いくつもあったけどメモってないので二度と見つからない…)、調べてくと、Liber Officeのヘッドレスモードで変換できるということを発見。
わかれば無限に記事がでてきます
- https://naruoga.hatenablog.com/entry/2015/12/21/201558
- https://blog.k-bushi.com/post/tech/tips/convert-excel-to-pdf
- https://www.seeds-std.co.jp/blog/creators/2019-08-27-205358
というわけでUbuntu環境でためしてみたら超簡単にできました。
Liber Officeで開ければなんでもいいので、xlsもdocもpptもいけちゃう。感動。
xlsxからpdfもいけちゃいます。
soffice --headless --convert-to "docx" file.doc
こんな簡単なコマンドで変換できてしまします。
別解として手作業だったらブラウザ版のOfficeで読み込んでダウンロードしてもよさそう
これのDocekr化
最終的にはSnowflake上で動かしたいです。さすがにLiber Officeは標準ではいってないので、Snowpark Container ServicesでJOBとして動かすことを目指します。SPCSは端的に言えばSnowflakeマネージドなk8sなのでdocker imageにさえしてしまえばほぼ何でもできます。詳細はこの記事とかどうぞ。
Liber Officeはいったイメージ、どれがいいのかよくわからなかったのであきらめてDebianからaptしていきます。この辺はもうChatGPT先生がなんとかしてくれる。
というわけでコードはこちらにあります。
Excelがpdfにしたときに横がはみ出て(いつものあれです)、しかもその状態のpdfでAI_PARSE_DOCUMENTしたらハルシネーションしやがったので調整しました。
SPCS化
つくったDockerfileをSnowflakeのレポジトリに流し込んでSPEC書いてEXCUTE JOBするだけ。pipではいるsnowflake-cliを使わないとレポジトリに流し込めないという。
追記:SPCSではステージをマウントして使うことができるので処理したいファイルがあるステージをマウントすることで普通にファイルを扱うノリで変換処理ができます。(オブジェクトストレージ的な制約はあるけど今回は気にならない)
ci_push.pyとci_spcs.pyにまとめてあります。
レポジトリにイメージアップロード
$ uv run python ci_push.py --repo SNOWFLAKE_LEARNING_DB.DATA_TEST.DOC_TOOLS --image lo-convert --tag latest --build --put-spec --spec-path specs/lo_convert.yaml --stage @SNOWFLAKE_LEARNING_DB.DATA_TEST.DOC_STAGE --spec-dest specs/lo_convert.yaml --connection XVRALMC-UX32060
+ snow spcs image-registry login --connection XVRALMC-UX32060
Login Succeeded
+ snow spcs image-registry url --connection XVRALMC-UX32060
[INFO] registry host: xvralmc-ux32060.registry.snowflakecomputing.com
+ snow spcs image-repository create DOC_TOOLS --if-not-exists --connection XVRALMC-UX32060 --database SNOWFLAKE_LEARNING_DB --schema DATA_TEST
+-----------------------------------------------------------------+
| key | value |
|--------+--------------------------------------------------------|
| status | DOC_TOOLS は既に存在し、ステートメントは成功しました。 |
+-----------------------------------------------------------------+
+ docker build -t lo-convert:latest -f Dockerfile .
[+] Building 1.5s (9/9) FINISHED docker:default
=> [internal] load build definition from dockerfile 0.0s
=> => transferring dockerfile: 953B 0.0s
=> [internal] load metadata for docker.io/library/debian:bookworm-slim 0.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/debian:bookworm-slim@sha256:7e490910eea28 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 32B 0.0s
=> CACHED [2/4] RUN apt-get update && apt-get install -y --no-install 0.0s
=> CACHED [3/4] COPY convert.py /usr/local/bin/convert.py 0.0s
=> CACHED [4/4] RUN chmod +x /usr/local/bin/convert.py && mkdir -p "/root 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:2a99acccb1fa3b7f0093aace5b5d58640cbf131f159ae6 0.0s
=> => naming to docker.io/library/lo-convert:latest 0.0s
+ docker tag lo-convert:latest xvralmc-ux32060.registry.snowflakecomputing.com/snowflake_learning_db/data_test/doc_tools/lo-convert:latest
+ docker push xvralmc-ux32060.registry.snowflakecomputing.com/snowflake_learning_db/data_test/doc_tools/lo-convert:latest
The push refers to repository [xvralmc-ux32060.registry.snowflakecomputing.com/snowflake_learning_db/data_test/doc_tools/lo-convert]
6d1f23f8dbe2: Pushed
b0069f1b9d95: Pushed
e063546a29d4: Pushed
aca836066730: Layer already exists
latest: digest: sha256:f3f0fc82a70c5fd13206a9f917d8dca807d5dc859a9777417eaca7537e558504 size: 1158
[INFO] pushed: xvralmc-ux32060.registry.snowflakecomputing.com/snowflake_learning_db/data_test/doc_tools/lo-convert:latest
+ snow sql -q 'PUT file:///home/myu65/soffice/specs/lo_convert.yaml @SNOWFLAKE_LEARNING_DB.DATA_TEST.DOC_STAGE/specs/lo_convert.yaml AUTO_COMPRESS=FALSE OVERWRITE=TRUE;' --connection XVRALMC-UX32060
PUT file:///home/myu65/soffice/specs/lo_convert.yaml @SNOWFLAKE_LEARNING_DB.DATA_TEST.DOC_STAGE/specs/lo_convert.yaml AUTO_COMPRESS=FALSE OVERWRITE=TRUE;
+-------------------------------------------------------------------------------+
| | | | | source_ | target_ | | |
| | | source_ | target_ | compres | compres | | |
| source | target | size | size | sion | sion | status | message |
|---------+---------+---------+---------+---------+---------+---------+---------|
| lo_conv | lo_conv | 758 | 758 | NONE | NONE | UPLOADE | |
| ert.yam | ert.yam | | | | | D | |
| l | l | | | | | | |
+-------------------------------------------------------------------------------+
[INFO] spec PUT -> @SNOWFLAKE_LEARNING_DB.DATA_TEST.DOC_STAGE/specs/lo_convert.yaml
✅ 完了
実行
uv run python ci_spcs.py job --pool LO_POOL_XS --stage @DOC_STAGE --spec specs/lo_convert.yaml --database SNOWFLAKE_LEARNING_DB --schema DATA_TEST --connection XVRALMC-UX32060
+ snow sql -q 'USE DATABASE SNOWFLAKE_LEARNING_DB; USE SCHEMA DATA_TEST; PUT file:///tmp/tmp87gfnkie/lo_convert_DOC_JOB_20251004152457_20251004152457_d2f0912e.yaml @DOC_STAGE/specs AUTO_COMPRESS=FALSE OVERWRITE=TRUE;' --connection XVRALMC-UX32060
USE DATABASE SNOWFLAKE_LEARNING_DB;
+----------------------------------------+
| status |
|----------------------------------------|
| ステートメントは正常に実行されました。 |
+----------------------------------------+
USE SCHEMA DATA_TEST;
+----------------------------------------+
| status |
|----------------------------------------|
| ステートメントは正常に実行されました。 |
+----------------------------------------+
PUT file:///tmp/tmp87gfnkie/lo_convert_DOC_JOB_20251004152457_20251004152457_d2f0912e.yaml @DOC_STAGE/specs AUTO_COMPRESS=FALSE OVERWRITE=TRUE;
+------------------------------------------------------------------------------------------------------------------------+
| | | | | source_compress | target_compress | | |
| source | target | source_size | target_size | ion | ion | status | message |
|-----------------+-----------------+-------------+-------------+-----------------+-----------------+----------+---------|
| lo_convert_DOC_ | lo_convert_DOC_ | 700 | 700 | NONE | NONE | UPLOADED | |
| JOB_20251004152 | JOB_20251004152 | | | | | | |
| 457_20251004152 | 457_20251004152 | | | | | | |
| 457_d2f0912e.ya | 457_d2f0912e.ya | | | | | | |
| ml | ml | | | | | | |
+------------------------------------------------------------------------------------------------------------------------+
[INFO] spec PUT -> @DOC_STAGE/specs/lo_convert_DOC_JOB_20251004152457_20251004152457_d2f0912e.yaml
+ snow sql -q 'USE DATABASE SNOWFLAKE_LEARNING_DB; USE SCHEMA DATA_TEST; EXECUTE JOB SERVICE
IN COMPUTE POOL LO_POOL_XS
FROM @DOC_STAGE
SPECIFICATION_FILE='"'"'specs/lo_convert_DOC_JOB_20251004152457_20251004152457_d2f0912e.yaml'"'"'
NAME=DOC_JOB_20251004152457
ASYNC=TRUE
REPLICAS=1;' --connection XVRALMC-UX32060
USE DATABASE SNOWFLAKE_LEARNING_DB;
+----------------------------------------+
| status |
|----------------------------------------|
| ステートメントは正常に実行されました。 |
+----------------------------------------+
USE SCHEMA DATA_TEST;
+----------------------------------------+
| status |
|----------------------------------------|
| ステートメントは正常に実行されました。 |
+----------------------------------------+
EXECUTE JOB SERVICE
IN COMPUTE POOL LO_POOL_XS
FROM @DOC_STAGE
SPECIFICATION_FILE='specs/lo_convert_DOC_JOB_20251004152457_20251004152457_d2f0912e.yaml'
NAME=DOC_JOB_20251004152457
ASYNC=TRUE
REPLICAS=1;
+-------------------------------------------------------------------+
| status |
|-------------------------------------------------------------------|
| Started Snowpark Container Services Job 'DOC_JOB_20251004152457'. |
+-------------------------------------------------------------------+
[INFO] job name: DOC_JOB_20251004152457
ってな感じで実行できます。
結果
$ docker run --rm -v "$PWD/in:/in" -v "$PWD/out:/out" lo-convert python3 /usr/local/bin/convert.py --passthrough-modern --calc-fit-export --inputs "/in/**/*" --out-dir "/out" --also-pdf
これで…
xlsファイルがpdfになっています。ちなみにこのページはデフォルトだと横にはみ出て2ページにわかれてました。
Snowflakeでも、
で、で、
よめなかったExcelも
SELECT
AI_PARSE_DOCUMENT(
TO_FILE('@DOC_STAGE', 'raw/(様式)研究費とその必要性等.xlsx'),
{'mode': 'LAYOUT'}
);
{
"errorInformation": "The provided file format .xlsx isn't supported. Supported formats: ['.docx', '.pptx', '.txt', '.html', '.png', '.jpg', '.tiff', '.jpeg', '.tif', '.pdf']."
}
PDFに変換されてるので
SELECT
AI_PARSE_DOCUMENT(
TO_FILE('@DOC_STAGE', 'convert/out/(様式)研究費とその必要性等.pdf')
,{'mode': 'LAYOUT'}
);
当然ほかのdocやpptもdocxやpptx、pdfになってるのでばっちりです。
やったね。
あ、おそらく真の神エクセルにはまだ試してないので、手も足もでない可能性はあります。探すとでてこないのでいい神エクセルあったら試してもらってもいいし押してくれたら28日いないなら試します(Snowflakeのトライアルアカウントの残日数)




