Skip to content

feat: 画像埋め込みを依存ゼロの単独スクリプトに切り出し、任意のAIで生成できるようにする - #484

Merged
taminororo merged 1 commit into
developfrom
feat/kanba/483/standalone-embed-images
Aug 31, 2026
Merged

taminororo merged 1 commit into
developfrom
feat/kanba/483/standalone-embed-images

Conversation

@taminororo

Copy link
Copy Markdown
Collaborator

対応Issue

resolve #483

概要

解説HTMLの生成を、どのAIサブスクリプションでも行えるようにする。画像埋め込みを標準ライブラリのみの単独スクリプトに切り出した。

なぜ必要か

変換工程は現在、特定アカウントのClaudeサブスク(PM個人のMaxプラン共用)に依存している。9月以降のPM不在期間に、他の人が生成を回せない。

パイプラインは非決定的な工程と決定的な工程に分かれている。

pandoc で Markdown 化        決定的
LLM で HTML 生成             非決定的  ← ここだけAIアカウントが要る
画像の base64 埋め込み        決定的
完全性の検査                 決定的

LLM工程は任意のAIセッション(Claude Code / Codex / ブラウザのチャット)で代替できる。プロンプトは .claude/manual-prompt-card-strict.md にあり誰でも読める。残る決定的な工程を単独実行できれば、アカウント依存は消える。

画像埋め込みだけはLLMに任せられない。生成HTMLは数MBになるがその大半がbase64文字列で、LLMの出力長に収まらないためである。

同等の処理は generate_slide.py --embed-only にもあるが、同ファイルが冒頭で claude_agent_sdk を import するため、Claudeを使わない人もこのパッケージのインストールが必要だった。

# scripts/claude-slide/generate_slide.py:27
from claude_agent_sdk import (

使い方

python3 scripts/claude-slide/embed_images.py docs/manuals/45th_企画マニュアル_縁日

uv も claude_agent_sdk も不要。import は argparse base64 mimetypes os re sys のみ。

これにより、任意のAIで次の手順が踏める。

1. Doc → ダウンロード → ウェブページ(.zip)
2. 解凍して docs/manuals/{名前}/ に配置(source.html + images/)
3. pandoc -f html -t markdown source.html
4. 好きなAIセッションで変換(.claude/manual-prompt-card-strict.md の2ブロックを使う)
5. 応答を slide_claude.card-strict.html として保存
6. python3 scripts/claude-slide/embed_images.py <dir>     ← 本PR
7. 以降は共通(確認 → アップロード → スプシ → タスク送信)

AIアカウントが要るのは手順4だけになる。

生成側にない機能を2つ追加した

完全性の検査。埋め込み前に </html> で閉じているかを見て、切れていれば書き込まずに終了コード1で止まる。チャット経由の生成ではスクリプトによる自動検査が効かず人間が検査役になるため、見落とすと壊れたHTMLを配信してしまう。実際に応答の途中切断は起きている(#477)。

画像の取りこぼし検出。images/ にあるのにHTMLから参照されていない画像を警告する。AIが画像を落とした場合に気づける。埋め込み済みの画像を未参照と誤判定しないよう、data URIとして既に入っているものは区別している(この誤検知はテスト中に発見して修正した)。

検証

実データ 45th_企画マニュアル_ホールインワン(Google Docのエクスポート、画像2枚582KB)で確認した。

正常系      57KB -> 815KB、2枚とも埋め込み、末尾は </html> のまま
冪等性      再実行しても815KBのまま。「2枚は既に埋め込み済み」と報告し誤警告なし
途中切断    30000バイトで切ったHTMLは書き込まずに終了コード1
取りこぼし  画像を1枚しか参照しないHTMLで、image2.png を警告

{{fname}} プレースホルダーと素の相対パス(src="images/image1.png")の両方を埋め込めることも確認済み。実際のGoogle Docエクスポートは後者の形式だった。

テスト項目

  • python3 だけで実行できる(uv環境を作らずに動く)
  • 画像が埋め込まれ、ブラウザでオフライン表示できる
  • 途中で切れたHTMLを渡すと終了コード1で止まり、ファイルが書き換わらない
  • 同じディレクトリに2回実行しても結果が変わらない

備考

generate_slide.py とは load_images_base64 / _resolve_image_src / replace_placeholders が重複している。本PRでは既存スクリプトに触らず新規ファイルの追加のみとした。#478 が同ファイルを変更中で競合するため。#478 のマージ後に generate_slide.py 側を import へ寄せて解消する。

運用手順書(docs/development/manual-html-operations.md)への手順追記は、同ファイルを追加する #480 のマージ後に行う。

変換工程が特定アカウントのClaudeサブスクに依存しており、PM不在時に生成が
回らないリスクがあった。LLM工程を任意のAIセッションで代替できるようにする。

パイプラインは非決定的な工程(LLM生成)と決定的な工程(pandoc変換・画像埋め込み・
完全性検査)に分かれている。決定的な側を単独で実行できれば、LLM工程はどのAIでも
よくなる。画像埋め込みだけはLLMに任せられない(生成HTMLは数MBでその大半がbase64
文字列であり、出力長に収まらない)ため、コードで処理する必要がある。

同等の処理は generate_slide.py --embed-only にもあるが、同ファイルが冒頭で
claude_agent_sdk を import するため、Claudeを使わない人もパッケージの
インストールが必要だった。本スクリプトは標準ライブラリのみで動く。

  python3 scripts/claude-slide/embed_images.py docs/manuals/45th_企画マニュアル_縁日

生成側にない機能を2つ追加した。

- 埋め込み前に </html> で閉じているかを検査し、切れていれば書き込まずに終了する。
  チャット経由の生成では人間が検査役になり、見落とすと壊れたHTMLを配信してしまう
- images/ にあるのにHTMLから参照されていない画像を警告する。AIが画像を落とした
  場合の検出用。埋め込み済みの画像を未参照と誤判定しないよう、data URIとして
  既に入っているものは区別する

実データ(45th_企画マニュアル_ホールインワン、画像2枚582KB)で検証した。
57KB -> 815KB、2枚とも埋め込み、再実行しても結果は変わらず、
30000バイトで切ったHTMLは終了コード1で拒否、画像を1枚落としたHTMLは警告を出す。

generate_slide.py との重複は PR #478 のマージ後に import へ寄せて解消する。
@coderabbitai

coderabbitai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 57 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b9887e11-7b3b-4bf7-8077-3065ffc6693e

📥 Commits

Reviewing files that changed from the base of the PR and between 2bf6d85 and 3cecdfe.

📒 Files selected for processing (1)
  • scripts/claude-slide/embed_images.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@taminororo

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@taminororo

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@taminororo

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@taminororo
taminororo merged commit 30dcd9d into develop Aug 31, 2026
1 check passed
@taminororo
taminororo deleted the feat/kanba/483/standalone-embed-images branch August 31, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 画像埋め込みを依存ゼロの単独スクリプトに切り出し、任意のAIで生成できるようにする

1 participant